diff options
-rw-r--r-- | include/lcms2.h | 3 | ||||
-rw-r--r-- | src/cmsplugin.c | 26 | ||||
-rw-r--r-- | src/lcms2_internal.h | 46 |
3 files changed, 72 insertions, 3 deletions
diff --git a/include/lcms2.h b/include/lcms2.h index 739e6e1..b6da91d 100644 --- a/include/lcms2.h +++ b/include/lcms2.h @@ -58,6 +58,9 @@ // Uncomment to get rid of pthreads/windows dependency // #define CMS_NO_PTHREADS 1 +// Uncomment this for special windows mutex initialization (see lcms2_internal.h) +// #define CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT + // ********** End of configuration toggles ****************************** // Needed for streams diff --git a/src/cmsplugin.c b/src/cmsplugin.c index 79b145d..a5f770d 100644 --- a/src/cmsplugin.c +++ b/src/cmsplugin.c @@ -750,6 +750,30 @@ cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData) struct _cmsContext_struct* ctx; struct _cmsContext_struct fakeContext; + // See the comments regarding locking in lcms2_internal.h + // for an explanation of why we need the following code. +#ifdef CMS_IS_WINDOWS_ +#ifndef CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT + { + static HANDLE _cmsWindowsInitMutex = NULL; + static volatile HANDLE *mutex = &_cmsWindowsInitMutex; + + if (*mutex == NULL) + { + HANDLE p = CreateMutex(NULL, FALSE, NULL); + if (InterlockedCompareExchangePointer((void **)mutex, (void*)p, NULL) != NULL) + CloseHandle(p); + } + if (WaitForSingleObject(*mutex, INFINITE) == WAIT_FAILED) + return NULL; + if (((void **)&_cmsContextPoolHeadMutex)[0] == NULL) + InitializeCriticalSection(&_cmsContextPoolHeadMutex); + if (!ReleaseMutex(*mutex)) + return NULL; + } +#endif +#endif + _cmsInstallAllocFunctions(_cmsFindMemoryPlugin(Plugin), &fakeContext.DefaultMemoryManager); fakeContext.chunks[UserPtr] = UserData; @@ -776,7 +800,7 @@ cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData) ctx ->chunks[MemPlugin] = &ctx->DefaultMemoryManager; // Now we can allocate the pool by using default memory manager - ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*)); // default size about 32 pointers + ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*)); // default size about 22 pointers if (ctx ->MemPool == NULL) { cmsDeleteContext(ctx); diff --git a/src/lcms2_internal.h b/src/lcms2_internal.h index 727cb06..fc62d8c 100644 --- a/src/lcms2_internal.h +++ b/src/lcms2_internal.h @@ -185,6 +185,34 @@ cmsINLINE cmsUInt16Number _cmsQuickSaturateWord(cmsFloat64Number d) #include <windows.h> +// The locking scheme in LCMS requires a single 'top level' mutex +// to work. This is actually implemented on Windows as a +// CriticalSection, because they are lighter weight. With +// pthreads, this is statically inited. Unfortunately, windows +// can't officially statically init critical sections. +// +// We can work around this in 2 ways. +// +// 1) We can use a proper mutex purely to protect the init +// of the CriticalSection. This in turns requires us to protect +// the Mutex creation, which we can do using the snappily +// named InterlockedCompareExchangePointer API (present on +// windows XP and above). +// +// 2) In cases where we want to work on pre-Windows XP, we +// can use an even more horrible hack described below. +// +// So why wouldn't we always use 2)? Because not calling +// the init function for a critical section means it fails +// testing with ApplicationVerifier (and presumably similar +// tools). +// +// We therefore default to 1, and people who want to be able +// to run on pre-Windows XP boxes can build with: +// CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT +// defined. This is automatically set for builds using +// versions of MSVC that don't have this API available. +// // From: http://locklessinc.com/articles/pthreads_on_windows/ // The pthreads API has an initialization macro that has no correspondence to anything in // the windows API. By investigating the internal definition of the critical section type, @@ -206,14 +234,28 @@ cmsINLINE cmsUInt16Number _cmsQuickSaturateWord(cmsFloat64Number d) typedef CRITICAL_SECTION _cmsMutex; -#define CMS_MUTEX_INITIALIZER {(PRTL_CRITICAL_SECTION_DEBUG) -1,-1,0,0,0,0} - #ifdef _MSC_VER # if (_MSC_VER >= 1800) # pragma warning(disable : 26135) # endif #endif +#ifndef CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT +// If we are building with a version of MSVC smaller +// than 1400 (i.e. before VS2005) then we don't have +// the InterlockedCompareExchangePointer API, so use +// the old version. +# ifdef _MSC_VER +# if _MSC_VER < 1400 +# define CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT +# endif +# endif +#endif + +#ifdef CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT +#else +#endif + cmsINLINE int _cmsLockPrimitive(_cmsMutex *m) { EnterCriticalSection(m); |