summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/lcms2.h3
-rw-r--r--src/cmsplugin.c26
-rw-r--r--src/lcms2_internal.h46
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);