diff --git a/README.md b/README.md index 8856b2f4..516c913b 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,8 @@ information on what to include when reporting a bug. ## Changelog -- Added `glfwGetError` function for querying the last error code (#970) +- Added `glfwGetError` function for querying the last error code and its + description (#970) - Added `glfwRequestWindowAttention` function for requesting attention from the user (#732,#988) - Added `glfwGetKeyScancode` function that allows retrieving platform dependent diff --git a/docs/intro.dox b/docs/intro.dox index 55aa7862..180f63fd 100644 --- a/docs/intro.dox +++ b/docs/intro.dox @@ -128,15 +128,19 @@ immediately. @section error_handling Error handling Some GLFW functions have return values that indicate an error, but this is often -not very helpful when trying to figure out _why_ the error occurred. Other -functions have no return value reserved for errors, so error notification needs -a separate channel. Finally, far from all GLFW functions have return values. +not very helpful when trying to figure out what happened or why it occurred. +Other functions have no return value reserved for errors, so error notification +needs a separate channel. Finally, far from all GLFW functions have return +values. -The last error code for the calling thread can be queried at any time with @ref -glfwGetError. +The last [error code](@ref errors) for the calling thread can be queried at any +time with @ref glfwGetError. @code -int error = glfwGetError(); +int code = glfwGetError(NULL); + +if (code != GLFW_NO_ERROR) + handle_error(code); @endcode If no error has occurred since the last call, @ref GLFW_NO_ERROR is returned. @@ -146,42 +150,52 @@ The error code indicates the general category of the error. Some error codes, such as @ref GLFW_NOT_INITIALIZED has only a single meaning, whereas others like @ref GLFW_PLATFORM_ERROR are used for many different errors. -GLFW usually has much more information about the error than its general category -at the point where it occurred. This is where the error callback comes in. -This callback is called whenever an error occurs. It is set with @ref -glfwSetErrorCallback, a function that may be called regardless of whether GLFW -is initialized. +GLFW often has more information about an error than its general category. You +can retrieve a UTF-8 encoded human-readable description along with the error +code. If no error has occurred since the last call, the description is set to +`NULL`. + +@code +const char* description; +int code = glfwGetError(&description); + +if (description) + display_error_message(code, description); +@endcode + +The retrieved description string is only valid until the next error occurs. +This means you must make a copy of it if you want to keep it. + +You can also set an error callback, which will be called each time an error +occurs. It is set with @ref glfwSetErrorCallback. @code glfwSetErrorCallback(error_callback); @endcode -The error callback receives a human-readable description of the error and (when -possible) its cause. The description encoded as UTF-8. The callback is also -provided with an [error code](@ref errors). +The error callback receives the same error code and human-readable description +returned by @ref glfwGetError. @code -void error_callback(int error, const char* description) +void error_callback(int code, const char* description) { - puts(description); + display_error_message(code, description); } @endcode -The error callback is called after the error code is set, so calling @ref -glfwGetError from within the error callback returns the same value as the +The error callback is called after the error is stored, so calling @ref +glfwGetError from within the error callback returns the same values as the callback argument. +The description string passed to the callback is only valid until the error +callback returns. This means you must make a copy of it if you want to keep it. + __Reported errors are never fatal.__ As long as GLFW was successfully initialized, it will remain initialized and in a safe state until terminated regardless of how many errors occur. If an error occurs during initialization that causes @ref glfwInit to fail, any part of the library that was initialized will be safely terminated. -The description string is only valid until the error callback returns, as it may -have been generated specifically for that error. This lets GLFW provide much -more specific error descriptions but means you must make a copy if you want to -keep the description string. - Do not rely on a currently invalid call to generate a specific error, as in the future that same call may generate a different error or become valid. diff --git a/docs/news.dox b/docs/news.dox index b2c8571f..39ad4eaa 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -7,8 +7,8 @@ @subsection news_33_geterror Error query -GLFW now supports querying the last error code for the calling thread with @ref -glfwGetError. +GLFW now supports querying the last error code for the calling thread and its +human-readable description with @ref glfwGetError. @see @ref error_handling diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 3b2d5b85..fb18edec 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1646,13 +1646,20 @@ GLFWAPI const char* glfwGetVersionString(void); /*! @brief Returns and clears the last error for the calling thread. * * This function returns and clears the [error code](@ref error) of the last - * error that occurred on the calling thread. If no error has occurred since - * the last call, it returns @ref GLFW_NO_ERROR. + * error that occurred on the calling thread, and optionally a UTF-8 encoded + * human-readable description of it. If no error has occurred since the last + * call, it returns @ref GLFW_NO_ERROR and the description pointer is set to + * `NULL`. * + * @param[in] description Where to store the error description pointer, or `NULL`. * @return The last error code for the calling thread, or @ref GLFW_NO_ERROR. * * @errors None. * + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is guaranteed to be valid only until the + * next error occurs or the library is terminated. + * * @remark This function may be called before @ref glfwInit. * * @thread_safety This function may be called from any thread. @@ -1664,7 +1671,7 @@ GLFWAPI const char* glfwGetVersionString(void); * * @ingroup init */ -GLFWAPI int glfwGetError(void); +GLFWAPI int glfwGetError(const char** description); /*! @brief Sets the error callback. * diff --git a/src/context.c b/src/context.c index 498e0e16..5a4c3372 100644 --- a/src/context.c +++ b/src/context.c @@ -331,7 +331,7 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig) NULL }; - window = _glfwPlatformGetTls(&_glfw.context); + window = _glfwPlatformGetTls(&_glfw.contextSlot); window->context.source = ctxconfig->source; window->context.client = GLFW_OPENGL_API; @@ -578,7 +578,7 @@ GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; - _GLFWwindow* previous = _glfwPlatformGetTls(&_glfw.context); + _GLFWwindow* previous = _glfwPlatformGetTls(&_glfw.contextSlot); _GLFW_REQUIRE_INIT(); @@ -601,7 +601,7 @@ GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle) GLFWAPI GLFWwindow* glfwGetCurrentContext(void) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - return _glfwPlatformGetTls(&_glfw.context); + return _glfwPlatformGetTls(&_glfw.contextSlot); } GLFWAPI void glfwSwapBuffers(GLFWwindow* handle) @@ -626,7 +626,7 @@ GLFWAPI void glfwSwapInterval(int interval) _GLFW_REQUIRE_INIT(); - window = _glfwPlatformGetTls(&_glfw.context); + window = _glfwPlatformGetTls(&_glfw.contextSlot); if (!window) { _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); @@ -643,7 +643,7 @@ GLFWAPI int glfwExtensionSupported(const char* extension) _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); - window = _glfwPlatformGetTls(&_glfw.context); + window = _glfwPlatformGetTls(&_glfw.contextSlot); if (!window) { _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); @@ -708,7 +708,7 @@ GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname) _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - window = _glfwPlatformGetTls(&_glfw.context); + window = _glfwPlatformGetTls(&_glfw.contextSlot); if (!window) { _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); diff --git a/src/egl_context.c b/src/egl_context.c index 328a0457..e101315a 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -199,12 +199,12 @@ static void makeContextCurrentEGL(_GLFWwindow* window) } } - _glfwPlatformSetTls(&_glfw.context, window); + _glfwPlatformSetTls(&_glfw.contextSlot, window); } static void swapBuffersEGL(_GLFWwindow* window) { - if (window != _glfwPlatformGetTls(&_glfw.context)) + if (window != _glfwPlatformGetTls(&_glfw.contextSlot)) { _glfwInputError(GLFW_PLATFORM_ERROR, "EGL: The context must be current on the calling thread when swapping buffers"); @@ -233,7 +233,7 @@ static int extensionSupportedEGL(const char* extension) static GLFWglproc getProcAddressEGL(const char* procname) { - _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.context); + _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); if (window->context.egl.client) { diff --git a/src/glx_context.c b/src/glx_context.c index 9c2ccb12..3e6ff96f 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -165,7 +165,7 @@ static void makeContextCurrentGLX(_GLFWwindow* window) } } - _glfwPlatformSetTls(&_glfw.context, window); + _glfwPlatformSetTls(&_glfw.contextSlot, window); } static void swapBuffersGLX(_GLFWwindow* window) @@ -175,7 +175,7 @@ static void swapBuffersGLX(_GLFWwindow* window) static void swapIntervalGLX(int interval) { - _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.context); + _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); if (_glfw.glx.EXT_swap_control) { diff --git a/src/init.c b/src/init.c index 19ae4c1d..b999149c 100644 --- a/src/init.c +++ b/src/init.c @@ -43,7 +43,7 @@ _GLFWlibrary _glfw = { GLFW_FALSE }; // These are outside of _glfw so they can be used before initialization and // after termination // -static int _glfwErrorCode; +static _GLFWerror _glfwMainThreadError; static GLFWerrorfun _glfwErrorCallback; static _GLFWinitconfig _glfwInitHints = { @@ -56,9 +56,9 @@ static _GLFWinitconfig _glfwInitHints = // Returns a generic string representation of the specified error // -static const char* getErrorString(int error) +static const char* getErrorString(int code) { - switch (error) + switch (code) { case GLFW_NOT_INITIALIZED: return "The GLFW library is not initialized"; @@ -114,11 +114,18 @@ static void terminate(void) _glfwTerminateVulkan(); _glfwPlatformTerminate(); - if (_glfwPlatformIsValidTls(&_glfw.error)) - _glfwErrorCode = (int) (intptr_t) _glfwPlatformGetTls(&_glfw.error); + _glfw.initialized = GLFW_FALSE; - _glfwPlatformDestroyTls(&_glfw.context); - _glfwPlatformDestroyTls(&_glfw.error); + while (_glfw.errorListHead) + { + _GLFWerror* error = _glfw.errorListHead; + _glfw.errorListHead = error->next; + free(error); + } + + _glfwPlatformDestroyTls(&_glfw.contextSlot); + _glfwPlatformDestroyTls(&_glfw.errorSlot); + _glfwPlatformDestroyMutex(&_glfw.errorLock); memset(&_glfw, 0, sizeof(_glfw)); } @@ -128,37 +135,47 @@ static void terminate(void) ////// GLFW event API ////// ////////////////////////////////////////////////////////////////////////// -void _glfwInputError(int error, const char* format, ...) +void _glfwInputError(int code, const char* format, ...) { - if (_glfw.initialized) - _glfwPlatformSetTls(&_glfw.error, (void*) (intptr_t) error); + _GLFWerror* error; + char description[1024]; + + if (format) + { + int count; + va_list vl; + + va_start(vl, format); + count = vsnprintf(description, sizeof(description), format, vl); + va_end(vl); + + if (count < 0) + description[sizeof(description) - 1] = '\0'; + } else - _glfwErrorCode = error; + strcpy(description, getErrorString(code)); + + if (_glfw.initialized) + { + error = _glfwPlatformGetTls(&_glfw.errorSlot); + if (!error) + { + error = calloc(1, sizeof(_GLFWerror)); + _glfwPlatformSetTls(&_glfw.errorSlot, error); + _glfwPlatformLockMutex(&_glfw.errorLock); + error->next = _glfw.errorListHead; + _glfw.errorListHead = error; + _glfwPlatformUnlockMutex(&_glfw.errorLock); + } + } + else + error = &_glfwMainThreadError; + + error->code = code; + strcpy(error->description, description); if (_glfwErrorCallback) - { - char buffer[8192]; - const char* description; - - if (format) - { - int count; - va_list vl; - - va_start(vl, format); - count = vsnprintf(buffer, sizeof(buffer), format, vl); - va_end(vl); - - if (count < 0) - buffer[sizeof(buffer) - 1] = '\0'; - - description = buffer; - } - else - description = getErrorString(error); - - _glfwErrorCallback(error, description); - } + _glfwErrorCallback(code, description); } @@ -180,12 +197,14 @@ GLFWAPI int glfwInit(void) return GLFW_FALSE; } - if (!_glfwPlatformCreateTls(&_glfw.error)) + if (!_glfwPlatformCreateMutex(&_glfw.errorLock)) return GLFW_FALSE; - if (!_glfwPlatformCreateTls(&_glfw.context)) + if (!_glfwPlatformCreateTls(&_glfw.errorSlot)) + return GLFW_FALSE; + if (!_glfwPlatformCreateTls(&_glfw.contextSlot)) return GLFW_FALSE; - _glfwPlatformSetTls(&_glfw.error, (void*) (intptr_t) _glfwErrorCode); + _glfwPlatformSetTls(&_glfw.errorSlot, &_glfwMainThreadError); _glfw.initialized = GLFW_TRUE; _glfw.timer.offset = _glfwPlatformGetTimerValue(); @@ -237,22 +256,28 @@ GLFWAPI const char* glfwGetVersionString(void) return _glfwPlatformGetVersionString(); } -GLFWAPI int glfwGetError(void) +GLFWAPI int glfwGetError(const char** description) { - int error; + _GLFWerror* error; + int code = GLFW_NO_ERROR; + + if (description) + *description = NULL; if (_glfw.initialized) - { - error = (int) (intptr_t) _glfwPlatformGetTls(&_glfw.error); - _glfwPlatformSetTls(&_glfw.error, (void*) (intptr_t) GLFW_NO_ERROR); - } + error = _glfwPlatformGetTls(&_glfw.errorSlot); else + error = &_glfwMainThreadError; + + if (error) { - error = _glfwErrorCode; - _glfwErrorCode = GLFW_NO_ERROR; + code = error->code; + error->code = GLFW_NO_ERROR; + if (description && code) + *description = error->description; } - return error; + return code; } GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun) diff --git a/src/internal.h b/src/internal.h index bd4c5307..72ac953e 100644 --- a/src/internal.h +++ b/src/internal.h @@ -55,6 +55,7 @@ typedef int GLFWbool; +typedef struct _GLFWerror _GLFWerror; typedef struct _GLFWinitconfig _GLFWinitconfig; typedef struct _GLFWwndconfig _GLFWwndconfig; typedef struct _GLFWctxconfig _GLFWctxconfig; @@ -66,6 +67,7 @@ typedef struct _GLFWmonitor _GLFWmonitor; typedef struct _GLFWcursor _GLFWcursor; typedef struct _GLFWjoystick _GLFWjoystick; typedef struct _GLFWtls _GLFWtls; +typedef struct _GLFWmutex _GLFWmutex; typedef void (* _GLFWmakecontextcurrentfun)(_GLFWwindow*); typedef void (* _GLFWswapbuffersfun)(_GLFWwindow*); @@ -257,6 +259,13 @@ typedef void (APIENTRY * PFN_vkVoidFunction)(void); // Platform-independent structures //======================================================================== +struct _GLFWerror +{ + _GLFWerror* next; + int code; + char description[1024]; +}; + /*! @brief Initialization configuration. * * Parameters relating to the initialization of the library. @@ -490,6 +499,14 @@ struct _GLFWtls _GLFW_PLATFORM_TLS_STATE; }; +/*! @brief Mutex structure. + */ +struct _GLFWmutex +{ + // This is defined in the platform's tls.h + _GLFW_PLATFORM_MUTEX_STATE; +}; + /*! @brief Library global data. */ struct _GLFWlibrary @@ -504,8 +521,8 @@ struct _GLFWlibrary int refreshRate; } hints; + _GLFWerror* errorListHead; _GLFWcursor* cursorListHead; - _GLFWwindow* windowListHead; _GLFWmonitor** monitors; @@ -513,8 +530,9 @@ struct _GLFWlibrary _GLFWjoystick joysticks[GLFW_JOYSTICK_LAST + 1]; - _GLFWtls error; - _GLFWtls context; + _GLFWtls errorSlot; + _GLFWtls contextSlot; + _GLFWmutex errorLock; struct { uint64_t offset; @@ -651,7 +669,11 @@ GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls); void _glfwPlatformDestroyTls(_GLFWtls* tls); void* _glfwPlatformGetTls(_GLFWtls* tls); void _glfwPlatformSetTls(_GLFWtls* tls, void* value); -GLFWbool _glfwPlatformIsValidTls(_GLFWtls* tls); + +GLFWbool _glfwPlatformCreateMutex(_GLFWmutex* mutex); +void _glfwPlatformDestroyMutex(_GLFWmutex* mutex); +void _glfwPlatformLockMutex(_GLFWmutex* mutex); +void _glfwPlatformUnlockMutex(_GLFWmutex* mutex); /*! @} */ @@ -798,15 +820,15 @@ void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement); void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window); /*! @brief Notifies shared code of an error. - * @param[in] error The error code most suitable for the error. + * @param[in] code The error code most suitable for the error. * @param[in] format The `printf` style format string of the error * description. * @ingroup event */ #if defined(__GNUC__) -void _glfwInputError(int error, const char* format, ...) __attribute__((format(printf, 2, 3))); +void _glfwInputError(int code, const char* format, ...) __attribute__((format(printf, 2, 3))); #else -void _glfwInputError(int error, const char* format, ...); +void _glfwInputError(int code, const char* format, ...); #endif /*! @brief Notifies shared code of files or directories dropped on a window. diff --git a/src/nsgl_context.m b/src/nsgl_context.m index f2902d7f..cc2615fa 100644 --- a/src/nsgl_context.m +++ b/src/nsgl_context.m @@ -34,7 +34,7 @@ static void makeContextCurrentNSGL(_GLFWwindow* window) else [NSOpenGLContext clearCurrentContext]; - _glfwPlatformSetTls(&_glfw.context, window); + _glfwPlatformSetTls(&_glfw.contextSlot, window); } static void swapBuffersNSGL(_GLFWwindow* window) @@ -45,7 +45,7 @@ static void swapBuffersNSGL(_GLFWwindow* window) static void swapIntervalNSGL(int interval) { - _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.context); + _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); GLint sync = interval; [window->context.nsgl.object setValues:&sync diff --git a/src/osmesa_context.c b/src/osmesa_context.c index 7ea65627..aa18aa62 100644 --- a/src/osmesa_context.c +++ b/src/osmesa_context.c @@ -63,7 +63,7 @@ static void makeContextCurrentOSMesa(_GLFWwindow* window) } } - _glfwPlatformSetTls(&_glfw.context, window); + _glfwPlatformSetTls(&_glfw.contextSlot, window); } static GLFWglproc getProcAddressOSMesa(const char* procname) diff --git a/src/posix_tls.c b/src/posix_tls.c index cf2ae6fa..ce0bc39b 100644 --- a/src/posix_tls.c +++ b/src/posix_tls.c @@ -69,8 +69,35 @@ void _glfwPlatformSetTls(_GLFWtls* tls, void* value) pthread_setspecific(tls->posix.key, value); } -GLFWbool _glfwPlatformIsValidTls(_GLFWtls* tls) +GLFWbool _glfwPlatformCreateMutex(_GLFWmutex* mutex) { - return tls->posix.allocated; + assert(mutex->posix.allocated == GLFW_FALSE); + + if (pthread_mutex_init(&mutex->posix.handle, NULL) != 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "POSIX: Failed to create mutex"); + return GLFW_FALSE; + } + + return mutex->posix.allocated = GLFW_TRUE; +} + +void _glfwPlatformDestroyMutex(_GLFWmutex* mutex) +{ + if (mutex->posix.allocated) + pthread_mutex_destroy(&mutex->posix.handle); + memset(mutex, 0, sizeof(_GLFWmutex)); +} + +void _glfwPlatformLockMutex(_GLFWmutex* mutex) +{ + assert(mutex->posix.allocated == GLFW_TRUE); + pthread_mutex_lock(&mutex->posix.handle); +} + +void _glfwPlatformUnlockMutex(_GLFWmutex* mutex) +{ + assert(mutex->posix.allocated == GLFW_TRUE); + pthread_mutex_unlock(&mutex->posix.handle); } diff --git a/src/posix_tls.h b/src/posix_tls.h index f738dc0d..bdddf41a 100644 --- a/src/posix_tls.h +++ b/src/posix_tls.h @@ -27,7 +27,8 @@ #include -#define _GLFW_PLATFORM_TLS_STATE _GLFWtlsPOSIX posix +#define _GLFW_PLATFORM_TLS_STATE _GLFWtlsPOSIX posix +#define _GLFW_PLATFORM_MUTEX_STATE _GLFWmutexPOSIX posix // POSIX-specific thread local storage data @@ -39,3 +40,12 @@ typedef struct _GLFWtlsPOSIX } _GLFWtlsPOSIX; +// POSIX-specific mutex data +// +typedef struct _GLFWmutexPOSIX +{ + GLFWbool allocated; + pthread_mutex_t handle; + +} _GLFWmutexPOSIX; + diff --git a/src/wgl_context.c b/src/wgl_context.c index ff1d2d4e..fc1b3970 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -249,12 +249,12 @@ static void makeContextCurrentWGL(_GLFWwindow* window) if (window) { if (wglMakeCurrent(window->context.wgl.dc, window->context.wgl.handle)) - _glfwPlatformSetTls(&_glfw.context, window); + _glfwPlatformSetTls(&_glfw.contextSlot, window); else { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "WGL: Failed to make context current"); - _glfwPlatformSetTls(&_glfw.context, NULL); + _glfwPlatformSetTls(&_glfw.contextSlot, NULL); } } else @@ -265,7 +265,7 @@ static void makeContextCurrentWGL(_GLFWwindow* window) "WGL: Failed to clear current context"); } - _glfwPlatformSetTls(&_glfw.context, NULL); + _glfwPlatformSetTls(&_glfw.contextSlot, NULL); } } @@ -284,7 +284,7 @@ static void swapBuffersWGL(_GLFWwindow* window) static void swapIntervalWGL(int interval) { - _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.context); + _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); window->context.wgl.interval = interval; diff --git a/src/win32_platform.h b/src/win32_platform.h index 3e0c93b0..c21d5ce3 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -221,6 +221,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)( #define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWin32 win32 #define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorWin32 win32 #define _GLFW_PLATFORM_TLS_STATE _GLFWtlsWin32 win32 +#define _GLFW_PLATFORM_MUTEX_STATE _GLFWmutexWin32 win32 // Win32-specific per-window data @@ -334,6 +335,15 @@ typedef struct _GLFWtlsWin32 } _GLFWtlsWin32; +// Win32-specific mutex data +// +typedef struct _GLFWmutexWin32 +{ + GLFWbool allocated; + CRITICAL_SECTION section; + +} _GLFWmutexWin32; + GLFWbool _glfwRegisterWindowClassWin32(void); void _glfwUnregisterWindowClassWin32(void); diff --git a/src/win32_tls.c b/src/win32_tls.c index 9c20aad0..98231c1e 100644 --- a/src/win32_tls.c +++ b/src/win32_tls.c @@ -69,8 +69,29 @@ void _glfwPlatformSetTls(_GLFWtls* tls, void* value) TlsSetValue(tls->win32.index, value); } -GLFWbool _glfwPlatformIsValidTls(_GLFWtls* tls) +GLFWbool _glfwPlatformCreateMutex(_GLFWmutex* mutex) { - return tls->win32.allocated; + assert(mutex->win32.allocated == GLFW_FALSE); + InitializeCriticalSection(&mutex->win32.section); + return mutex->win32.allocated = GLFW_TRUE; +} + +void _glfwPlatformDestroyMutex(_GLFWmutex* mutex) +{ + if (mutex->win32.allocated) + DeleteCriticalSection(&mutex->win32.section); + memset(mutex, 0, sizeof(_GLFWmutex)); +} + +void _glfwPlatformLockMutex(_GLFWmutex* mutex) +{ + assert(mutex->win32.allocated == GLFW_TRUE); + EnterCriticalSection(&mutex->win32.section); +} + +void _glfwPlatformUnlockMutex(_GLFWmutex* mutex) +{ + assert(mutex->win32.allocated == GLFW_TRUE); + LeaveCriticalSection(&mutex->win32.section); } diff --git a/src/window.c b/src/window.c index 546d233d..1d717c30 100644 --- a/src/window.c +++ b/src/window.c @@ -192,7 +192,7 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, window->denom = GLFW_DONT_CARE; // Save the currently current context so it can be restored later - previous = _glfwPlatformGetTls(&_glfw.context); + previous = _glfwPlatformGetTls(&_glfw.contextSlot); if (ctxconfig.client != GLFW_NO_API) glfwMakeContextCurrent(NULL); @@ -408,7 +408,7 @@ GLFWAPI void glfwDestroyWindow(GLFWwindow* handle) // The window's context must not be current on another thread when the // window is destroyed - if (window == _glfwPlatformGetTls(&_glfw.context)) + if (window == _glfwPlatformGetTls(&_glfw.contextSlot)) glfwMakeContextCurrent(NULL); _glfwPlatformDestroyWindow(window);