From c89a2e4f62c6d6a4aa64a9dbdb038c62b263ecb2 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 22 May 2020 13:45:37 +0000 Subject: [PATCH] Use a thread-safe temporary arena on every platform. This commit continues the work started in commits 521473ee and e84fd464 that parallelizes certain geometric operations. This commit cleans up the temporary arena implementations and makes them thread-safe. Also, in commit 521473ee, a call to FreeAllTemporary() was added during initialization to create the heap on Windows. This is now not necessary as the heap is created transparently on the first call to AllocTemporary(). --- src/CMakeLists.txt | 8 ----- src/lib.cpp | 3 -- src/platform/platform.cpp | 64 +++++++++++++++++++++++++++++++++++++-- src/platform/platform.h | 4 +++ src/platform/utilunix.cpp | 49 ------------------------------ src/platform/utilwin.cpp | 33 -------------------- src/solvespace.h | 7 ++--- 7 files changed, 68 insertions(+), 100 deletions(-) delete mode 100644 src/platform/utilunix.cpp delete mode 100644 src/platform/utilwin.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4834a655..d1d9fc35 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -26,14 +26,6 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in # platform utilities -if(WIN32) - set(util_SOURCES - platform/utilwin.cpp) -else() - set(util_SOURCES - platform/utilunix.cpp) -endif() - if(APPLE) set(util_LIBRARIES ${APPKIT_LIBRARY}) diff --git a/src/lib.cpp b/src/lib.cpp index d1d54ff7..b0d8e1d6 100644 --- a/src/lib.cpp +++ b/src/lib.cpp @@ -67,9 +67,6 @@ void Slvs_MakeQuaternion(double ux, double uy, double uz, void Slvs_Solve(Slvs_System *ssys, Slvs_hGroup shg) { - // Create the temporary heap, if this is the first time we're solving. - FreeAllTemporary(); - int i; for(i = 0; i < ssys->params; i++) { Slvs_Param *sp = &(ssys->param[i]); diff --git a/src/platform/platform.cpp b/src/platform/platform.cpp index 974cce62..a1d29ea8 100644 --- a/src/platform/platform.cpp +++ b/src/platform/platform.cpp @@ -18,6 +18,7 @@ #else # include # include +# include #endif namespace SolveSpace { @@ -605,9 +606,6 @@ std::vector InitCli(int argc, char **argv) { } #endif - // Create the heap that we use to store Exprs and other temp stuff. - FreeAllTemporary(); - // Extract the command-line arguments; the ones from main() are ignored, // since they are in the OEM encoding. int argcW; @@ -681,5 +679,65 @@ void DebugPrint(const char *fmt, ...) { #endif +//----------------------------------------------------------------------------- +// Temporary arena, on Windows. +//----------------------------------------------------------------------------- + +#if defined(WIN32) + +static HANDLE TempArena = NULL; + +void *AllocTemporary(size_t size) +{ + if(!TempArena) + TempArena = HeapCreate(0, 0, 0); + void *ptr = HeapAlloc(TempArena, HEAP_ZERO_MEMORY, size); + ssassert(ptr != NULL, "out of memory"); + return ptr; +} + +void FreeAllTemporary() +{ + HeapDestroy(TempArena); + TempArena = NULL; +} + +#endif + +//----------------------------------------------------------------------------- +// Temporary arena, on Linux. +//----------------------------------------------------------------------------- + +#if !defined(WIN32) + +struct ArenaChunk { + ArenaChunk *next; +}; + +static std::mutex TempArenaMutex; +static ArenaChunk *TempArena = NULL; + +void *AllocTemporary(size_t size) +{ + ArenaChunk *chunk = (ArenaChunk *)calloc(1, sizeof(ArenaChunk) + size); + ssassert(chunk != NULL, "out of memory"); + std::lock_guard guard(TempArenaMutex); + chunk->next = TempArena; + TempArena = chunk; + return (void *)(chunk + 1); +} + +void FreeAllTemporary() +{ + std::lock_guard guard(TempArenaMutex); + while(TempArena) { + ArenaChunk *chunk = TempArena; + TempArena = TempArena->next; + free(chunk); + } +} + +#endif + } } diff --git a/src/platform/platform.h b/src/platform/platform.h index adf62285..5664fa21 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -70,6 +70,10 @@ std::vector InitCli(int argc, char **argv); // Debug print function. void DebugPrint(const char *fmt, ...); +// Temporary arena functions. +void *AllocTemporary(size_t size); +void FreeAllTemporary(); + } #endif diff --git a/src/platform/utilunix.cpp b/src/platform/utilunix.cpp deleted file mode 100644 index 9a471c66..00000000 --- a/src/platform/utilunix.cpp +++ /dev/null @@ -1,49 +0,0 @@ -//----------------------------------------------------------------------------- -// Utility functions used by the Unix port. -// -// Copyright 2008-2013 Jonathan Westhues. -// Copyright 2013 Daniel Richard G. -//----------------------------------------------------------------------------- -#include "solvespace.h" - -namespace SolveSpace { - -//----------------------------------------------------------------------------- -// A separate heap, on which we allocate expressions. Maybe a bit faster, -// since fragmentation is less of a concern, and it also makes it possible -// to be sloppy with our memory management, and just free everything at once -// at the end. -//----------------------------------------------------------------------------- - -typedef struct _AllocTempHeader AllocTempHeader; - -typedef struct _AllocTempHeader { - AllocTempHeader *prev; - AllocTempHeader *next; -} AllocTempHeader; - -static AllocTempHeader *Head = NULL; - -void *AllocTemporary(size_t n) -{ - AllocTempHeader *h = - (AllocTempHeader *)malloc(n + sizeof(AllocTempHeader)); - h->prev = NULL; - h->next = Head; - if(Head) Head->prev = h; - Head = h; - memset(&h[1], 0, n); - return (void *)&h[1]; -} - -void FreeAllTemporary() { - AllocTempHeader *h = Head; - while(h) { - AllocTempHeader *f = h; - h = h->next; - free(f); - } - Head = NULL; -} - -}; diff --git a/src/platform/utilwin.cpp b/src/platform/utilwin.cpp deleted file mode 100644 index 16bce190..00000000 --- a/src/platform/utilwin.cpp +++ /dev/null @@ -1,33 +0,0 @@ -//----------------------------------------------------------------------------- -// Utility functions that depend on Win32. -// -// Copyright 2008-2013 Jonathan Westhues. -//----------------------------------------------------------------------------- -#include "solvespace.h" - -// Include after solvespace.h to avoid identifier clashes. -#include - -namespace SolveSpace { - -//----------------------------------------------------------------------------- -// A separate heap, on which we allocate expressions. Maybe a bit faster, -// since no fragmentation issues whatsoever, and it also makes it possible -// to be sloppy with our memory management, and just free everything at once -// at the end. -//----------------------------------------------------------------------------- -static HANDLE TempHeap; - -void *AllocTemporary(size_t n) -{ - void *v = HeapAlloc(TempHeap, HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY, n); - ssassert(v != NULL, "Cannot allocate memory"); - return v; -} -void FreeAllTemporary() -{ - if(TempHeap) HeapDestroy(TempHeap); - TempHeap = HeapCreate(HEAP_NO_SERIALIZE, 1024*1024*20, 0); -} - -} diff --git a/src/solvespace.h b/src/solvespace.h index 165fd086..17e74b54 100644 --- a/src/solvespace.h +++ b/src/solvespace.h @@ -132,16 +132,15 @@ inline double Random(double vmax) { #include "platform/gui.h" #include "resource.h" +using Platform::AllocTemporary; +using Platform::FreeAllTemporary; + class Expr; class ExprVector; class ExprQuaternion; class RgbaColor; enum class Command : uint32_t; -// Temporary heap, defined in the platform-specific code. -void *AllocTemporary(size_t n); -void FreeAllTemporary(); - enum class Unit : uint32_t { MM = 0, INCHES,