Make glfwGetError also provide description

Related to #970.
This commit is contained in:
Camilla Löwy 2017-05-25 18:23:09 +02:00
parent beaeb0d4af
commit 14a3fe0ac0
17 changed files with 244 additions and 107 deletions

View File

@ -122,7 +122,8 @@ information on what to include when reporting a bug.
## Changelog ## 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 - Added `glfwRequestWindowAttention` function for requesting attention from the
user (#732,#988) user (#732,#988)
- Added `glfwGetKeyScancode` function that allows retrieving platform dependent - Added `glfwGetKeyScancode` function that allows retrieving platform dependent

View File

@ -128,15 +128,19 @@ immediately.
@section error_handling Error handling @section error_handling Error handling
Some GLFW functions have return values that indicate an error, but this is often 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 not very helpful when trying to figure out what happened or why it occurred.
functions have no return value reserved for errors, so error notification needs Other functions have no return value reserved for errors, so error notification
a separate channel. Finally, far from all GLFW functions have return values. 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 The last [error code](@ref errors) for the calling thread can be queried at any
glfwGetError. time with @ref glfwGetError.
@code @code
int error = glfwGetError(); int code = glfwGetError(NULL);
if (code != GLFW_NO_ERROR)
handle_error(code);
@endcode @endcode
If no error has occurred since the last call, @ref GLFW_NO_ERROR is returned. 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 such as @ref GLFW_NOT_INITIALIZED has only a single meaning, whereas others like
@ref GLFW_PLATFORM_ERROR are used for many different errors. @ref GLFW_PLATFORM_ERROR are used for many different errors.
GLFW usually has much more information about the error than its general category GLFW often has more information about an error than its general category. You
at the point where it occurred. This is where the error callback comes in. can retrieve a UTF-8 encoded human-readable description along with the error
This callback is called whenever an error occurs. It is set with @ref code. If no error has occurred since the last call, the description is set to
glfwSetErrorCallback, a function that may be called regardless of whether GLFW `NULL`.
is initialized.
@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 @code
glfwSetErrorCallback(error_callback); glfwSetErrorCallback(error_callback);
@endcode @endcode
The error callback receives a human-readable description of the error and (when The error callback receives the same error code and human-readable description
possible) its cause. The description encoded as UTF-8. The callback is also returned by @ref glfwGetError.
provided with an [error code](@ref errors).
@code @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 @endcode
The error callback is called after the error code is set, so calling @ref The error callback is called after the error is stored, so calling @ref
glfwGetError from within the error callback returns the same value as the glfwGetError from within the error callback returns the same values as the
callback argument. 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 __Reported errors are never fatal.__ As long as GLFW was successfully
initialized, it will remain initialized and in a safe state until terminated initialized, it will remain initialized and in a safe state until terminated
regardless of how many errors occur. If an error occurs during initialization 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 that causes @ref glfwInit to fail, any part of the library that was initialized
will be safely terminated. 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 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. future that same call may generate a different error or become valid.

View File

@ -7,8 +7,8 @@
@subsection news_33_geterror Error query @subsection news_33_geterror Error query
GLFW now supports querying the last error code for the calling thread with @ref GLFW now supports querying the last error code for the calling thread and its
glfwGetError. human-readable description with @ref glfwGetError.
@see @ref error_handling @see @ref error_handling

View File

@ -1646,13 +1646,20 @@ GLFWAPI const char* glfwGetVersionString(void);
/*! @brief Returns and clears the last error for the calling thread. /*! @brief Returns and clears the last error for the calling thread.
* *
* This function returns and clears the [error code](@ref error) of the last * 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 * error that occurred on the calling thread, and optionally a UTF-8 encoded
* the last call, it returns @ref GLFW_NO_ERROR. * 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. * @return The last error code for the calling thread, or @ref GLFW_NO_ERROR.
* *
* @errors None. * @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. * @remark This function may be called before @ref glfwInit.
* *
* @thread_safety This function may be called from any thread. * @thread_safety This function may be called from any thread.
@ -1664,7 +1671,7 @@ GLFWAPI const char* glfwGetVersionString(void);
* *
* @ingroup init * @ingroup init
*/ */
GLFWAPI int glfwGetError(void); GLFWAPI int glfwGetError(const char** description);
/*! @brief Sets the error callback. /*! @brief Sets the error callback.
* *

View File

@ -331,7 +331,7 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig)
NULL NULL
}; };
window = _glfwPlatformGetTls(&_glfw.context); window = _glfwPlatformGetTls(&_glfw.contextSlot);
window->context.source = ctxconfig->source; window->context.source = ctxconfig->source;
window->context.client = GLFW_OPENGL_API; window->context.client = GLFW_OPENGL_API;
@ -578,7 +578,7 @@ GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions
GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle) GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle)
{ {
_GLFWwindow* window = (_GLFWwindow*) handle; _GLFWwindow* window = (_GLFWwindow*) handle;
_GLFWwindow* previous = _glfwPlatformGetTls(&_glfw.context); _GLFWwindow* previous = _glfwPlatformGetTls(&_glfw.contextSlot);
_GLFW_REQUIRE_INIT(); _GLFW_REQUIRE_INIT();
@ -601,7 +601,7 @@ GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle)
GLFWAPI GLFWwindow* glfwGetCurrentContext(void) GLFWAPI GLFWwindow* glfwGetCurrentContext(void)
{ {
_GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
return _glfwPlatformGetTls(&_glfw.context); return _glfwPlatformGetTls(&_glfw.contextSlot);
} }
GLFWAPI void glfwSwapBuffers(GLFWwindow* handle) GLFWAPI void glfwSwapBuffers(GLFWwindow* handle)
@ -626,7 +626,7 @@ GLFWAPI void glfwSwapInterval(int interval)
_GLFW_REQUIRE_INIT(); _GLFW_REQUIRE_INIT();
window = _glfwPlatformGetTls(&_glfw.context); window = _glfwPlatformGetTls(&_glfw.contextSlot);
if (!window) if (!window)
{ {
_glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL);
@ -643,7 +643,7 @@ GLFWAPI int glfwExtensionSupported(const char* extension)
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
window = _glfwPlatformGetTls(&_glfw.context); window = _glfwPlatformGetTls(&_glfw.contextSlot);
if (!window) if (!window)
{ {
_glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL);
@ -708,7 +708,7 @@ GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname)
_GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
window = _glfwPlatformGetTls(&_glfw.context); window = _glfwPlatformGetTls(&_glfw.contextSlot);
if (!window) if (!window)
{ {
_glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL);

View File

@ -199,12 +199,12 @@ static void makeContextCurrentEGL(_GLFWwindow* window)
} }
} }
_glfwPlatformSetTls(&_glfw.context, window); _glfwPlatformSetTls(&_glfw.contextSlot, window);
} }
static void swapBuffersEGL(_GLFWwindow* window) static void swapBuffersEGL(_GLFWwindow* window)
{ {
if (window != _glfwPlatformGetTls(&_glfw.context)) if (window != _glfwPlatformGetTls(&_glfw.contextSlot))
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"EGL: The context must be current on the calling thread when swapping buffers"); "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) static GLFWglproc getProcAddressEGL(const char* procname)
{ {
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.context); _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
if (window->context.egl.client) if (window->context.egl.client)
{ {

View File

@ -165,7 +165,7 @@ static void makeContextCurrentGLX(_GLFWwindow* window)
} }
} }
_glfwPlatformSetTls(&_glfw.context, window); _glfwPlatformSetTls(&_glfw.contextSlot, window);
} }
static void swapBuffersGLX(_GLFWwindow* window) static void swapBuffersGLX(_GLFWwindow* window)
@ -175,7 +175,7 @@ static void swapBuffersGLX(_GLFWwindow* window)
static void swapIntervalGLX(int interval) static void swapIntervalGLX(int interval)
{ {
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.context); _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
if (_glfw.glx.EXT_swap_control) if (_glfw.glx.EXT_swap_control)
{ {

View File

@ -43,7 +43,7 @@ _GLFWlibrary _glfw = { GLFW_FALSE };
// These are outside of _glfw so they can be used before initialization and // These are outside of _glfw so they can be used before initialization and
// after termination // after termination
// //
static int _glfwErrorCode; static _GLFWerror _glfwMainThreadError;
static GLFWerrorfun _glfwErrorCallback; static GLFWerrorfun _glfwErrorCallback;
static _GLFWinitconfig _glfwInitHints = static _GLFWinitconfig _glfwInitHints =
{ {
@ -56,9 +56,9 @@ static _GLFWinitconfig _glfwInitHints =
// Returns a generic string representation of the specified error // 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: case GLFW_NOT_INITIALIZED:
return "The GLFW library is not initialized"; return "The GLFW library is not initialized";
@ -114,11 +114,18 @@ static void terminate(void)
_glfwTerminateVulkan(); _glfwTerminateVulkan();
_glfwPlatformTerminate(); _glfwPlatformTerminate();
if (_glfwPlatformIsValidTls(&_glfw.error)) _glfw.initialized = GLFW_FALSE;
_glfwErrorCode = (int) (intptr_t) _glfwPlatformGetTls(&_glfw.error);
_glfwPlatformDestroyTls(&_glfw.context); while (_glfw.errorListHead)
_glfwPlatformDestroyTls(&_glfw.error); {
_GLFWerror* error = _glfw.errorListHead;
_glfw.errorListHead = error->next;
free(error);
}
_glfwPlatformDestroyTls(&_glfw.contextSlot);
_glfwPlatformDestroyTls(&_glfw.errorSlot);
_glfwPlatformDestroyMutex(&_glfw.errorLock);
memset(&_glfw, 0, sizeof(_glfw)); memset(&_glfw, 0, sizeof(_glfw));
} }
@ -128,17 +135,10 @@ static void terminate(void)
////// GLFW event API ////// ////// GLFW event API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void _glfwInputError(int error, const char* format, ...) void _glfwInputError(int code, const char* format, ...)
{ {
if (_glfw.initialized) _GLFWerror* error;
_glfwPlatformSetTls(&_glfw.error, (void*) (intptr_t) error); char description[1024];
else
_glfwErrorCode = error;
if (_glfwErrorCallback)
{
char buffer[8192];
const char* description;
if (format) if (format)
{ {
@ -146,19 +146,36 @@ void _glfwInputError(int error, const char* format, ...)
va_list vl; va_list vl;
va_start(vl, format); va_start(vl, format);
count = vsnprintf(buffer, sizeof(buffer), format, vl); count = vsnprintf(description, sizeof(description), format, vl);
va_end(vl); va_end(vl);
if (count < 0) if (count < 0)
buffer[sizeof(buffer) - 1] = '\0'; description[sizeof(description) - 1] = '\0';
description = buffer;
} }
else else
description = getErrorString(error); strcpy(description, getErrorString(code));
_glfwErrorCallback(error, description); 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)
_glfwErrorCallback(code, description);
} }
@ -180,12 +197,14 @@ GLFWAPI int glfwInit(void)
return GLFW_FALSE; return GLFW_FALSE;
} }
if (!_glfwPlatformCreateTls(&_glfw.error)) if (!_glfwPlatformCreateMutex(&_glfw.errorLock))
return GLFW_FALSE; return GLFW_FALSE;
if (!_glfwPlatformCreateTls(&_glfw.context)) if (!_glfwPlatformCreateTls(&_glfw.errorSlot))
return GLFW_FALSE;
if (!_glfwPlatformCreateTls(&_glfw.contextSlot))
return GLFW_FALSE; return GLFW_FALSE;
_glfwPlatformSetTls(&_glfw.error, (void*) (intptr_t) _glfwErrorCode); _glfwPlatformSetTls(&_glfw.errorSlot, &_glfwMainThreadError);
_glfw.initialized = GLFW_TRUE; _glfw.initialized = GLFW_TRUE;
_glfw.timer.offset = _glfwPlatformGetTimerValue(); _glfw.timer.offset = _glfwPlatformGetTimerValue();
@ -237,22 +256,28 @@ GLFWAPI const char* glfwGetVersionString(void)
return _glfwPlatformGetVersionString(); 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) if (_glfw.initialized)
{ error = _glfwPlatformGetTls(&_glfw.errorSlot);
error = (int) (intptr_t) _glfwPlatformGetTls(&_glfw.error);
_glfwPlatformSetTls(&_glfw.error, (void*) (intptr_t) GLFW_NO_ERROR);
}
else else
error = &_glfwMainThreadError;
if (error)
{ {
error = _glfwErrorCode; code = error->code;
_glfwErrorCode = GLFW_NO_ERROR; error->code = GLFW_NO_ERROR;
if (description && code)
*description = error->description;
} }
return error; return code;
} }
GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun) GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun)

View File

@ -55,6 +55,7 @@
typedef int GLFWbool; typedef int GLFWbool;
typedef struct _GLFWerror _GLFWerror;
typedef struct _GLFWinitconfig _GLFWinitconfig; typedef struct _GLFWinitconfig _GLFWinitconfig;
typedef struct _GLFWwndconfig _GLFWwndconfig; typedef struct _GLFWwndconfig _GLFWwndconfig;
typedef struct _GLFWctxconfig _GLFWctxconfig; typedef struct _GLFWctxconfig _GLFWctxconfig;
@ -66,6 +67,7 @@ typedef struct _GLFWmonitor _GLFWmonitor;
typedef struct _GLFWcursor _GLFWcursor; typedef struct _GLFWcursor _GLFWcursor;
typedef struct _GLFWjoystick _GLFWjoystick; typedef struct _GLFWjoystick _GLFWjoystick;
typedef struct _GLFWtls _GLFWtls; typedef struct _GLFWtls _GLFWtls;
typedef struct _GLFWmutex _GLFWmutex;
typedef void (* _GLFWmakecontextcurrentfun)(_GLFWwindow*); typedef void (* _GLFWmakecontextcurrentfun)(_GLFWwindow*);
typedef void (* _GLFWswapbuffersfun)(_GLFWwindow*); typedef void (* _GLFWswapbuffersfun)(_GLFWwindow*);
@ -257,6 +259,13 @@ typedef void (APIENTRY * PFN_vkVoidFunction)(void);
// Platform-independent structures // Platform-independent structures
//======================================================================== //========================================================================
struct _GLFWerror
{
_GLFWerror* next;
int code;
char description[1024];
};
/*! @brief Initialization configuration. /*! @brief Initialization configuration.
* *
* Parameters relating to the initialization of the library. * Parameters relating to the initialization of the library.
@ -490,6 +499,14 @@ struct _GLFWtls
_GLFW_PLATFORM_TLS_STATE; _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. /*! @brief Library global data.
*/ */
struct _GLFWlibrary struct _GLFWlibrary
@ -504,8 +521,8 @@ struct _GLFWlibrary
int refreshRate; int refreshRate;
} hints; } hints;
_GLFWerror* errorListHead;
_GLFWcursor* cursorListHead; _GLFWcursor* cursorListHead;
_GLFWwindow* windowListHead; _GLFWwindow* windowListHead;
_GLFWmonitor** monitors; _GLFWmonitor** monitors;
@ -513,8 +530,9 @@ struct _GLFWlibrary
_GLFWjoystick joysticks[GLFW_JOYSTICK_LAST + 1]; _GLFWjoystick joysticks[GLFW_JOYSTICK_LAST + 1];
_GLFWtls error; _GLFWtls errorSlot;
_GLFWtls context; _GLFWtls contextSlot;
_GLFWmutex errorLock;
struct { struct {
uint64_t offset; uint64_t offset;
@ -651,7 +669,11 @@ GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls);
void _glfwPlatformDestroyTls(_GLFWtls* tls); void _glfwPlatformDestroyTls(_GLFWtls* tls);
void* _glfwPlatformGetTls(_GLFWtls* tls); void* _glfwPlatformGetTls(_GLFWtls* tls);
void _glfwPlatformSetTls(_GLFWtls* tls, void* value); 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); void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window);
/*! @brief Notifies shared code of an error. /*! @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 * @param[in] format The `printf` style format string of the error
* description. * description.
* @ingroup event * @ingroup event
*/ */
#if defined(__GNUC__) #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 #else
void _glfwInputError(int error, const char* format, ...); void _glfwInputError(int code, const char* format, ...);
#endif #endif
/*! @brief Notifies shared code of files or directories dropped on a window. /*! @brief Notifies shared code of files or directories dropped on a window.

View File

@ -34,7 +34,7 @@ static void makeContextCurrentNSGL(_GLFWwindow* window)
else else
[NSOpenGLContext clearCurrentContext]; [NSOpenGLContext clearCurrentContext];
_glfwPlatformSetTls(&_glfw.context, window); _glfwPlatformSetTls(&_glfw.contextSlot, window);
} }
static void swapBuffersNSGL(_GLFWwindow* window) static void swapBuffersNSGL(_GLFWwindow* window)
@ -45,7 +45,7 @@ static void swapBuffersNSGL(_GLFWwindow* window)
static void swapIntervalNSGL(int interval) static void swapIntervalNSGL(int interval)
{ {
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.context); _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
GLint sync = interval; GLint sync = interval;
[window->context.nsgl.object setValues:&sync [window->context.nsgl.object setValues:&sync

View File

@ -63,7 +63,7 @@ static void makeContextCurrentOSMesa(_GLFWwindow* window)
} }
} }
_glfwPlatformSetTls(&_glfw.context, window); _glfwPlatformSetTls(&_glfw.contextSlot, window);
} }
static GLFWglproc getProcAddressOSMesa(const char* procname) static GLFWglproc getProcAddressOSMesa(const char* procname)

View File

@ -69,8 +69,35 @@ void _glfwPlatformSetTls(_GLFWtls* tls, void* value)
pthread_setspecific(tls->posix.key, 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);
} }

View File

@ -28,6 +28,7 @@
#include <pthread.h> #include <pthread.h>
#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 // POSIX-specific thread local storage data
@ -39,3 +40,12 @@ typedef struct _GLFWtlsPOSIX
} _GLFWtlsPOSIX; } _GLFWtlsPOSIX;
// POSIX-specific mutex data
//
typedef struct _GLFWmutexPOSIX
{
GLFWbool allocated;
pthread_mutex_t handle;
} _GLFWmutexPOSIX;

View File

@ -249,12 +249,12 @@ static void makeContextCurrentWGL(_GLFWwindow* window)
if (window) if (window)
{ {
if (wglMakeCurrent(window->context.wgl.dc, window->context.wgl.handle)) if (wglMakeCurrent(window->context.wgl.dc, window->context.wgl.handle))
_glfwPlatformSetTls(&_glfw.context, window); _glfwPlatformSetTls(&_glfw.contextSlot, window);
else else
{ {
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR, _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to make context current"); "WGL: Failed to make context current");
_glfwPlatformSetTls(&_glfw.context, NULL); _glfwPlatformSetTls(&_glfw.contextSlot, NULL);
} }
} }
else else
@ -265,7 +265,7 @@ static void makeContextCurrentWGL(_GLFWwindow* window)
"WGL: Failed to clear current context"); "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) static void swapIntervalWGL(int interval)
{ {
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.context); _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
window->context.wgl.interval = interval; window->context.wgl.interval = interval;

View File

@ -221,6 +221,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWin32 win32 #define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWin32 win32
#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorWin32 win32 #define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorWin32 win32
#define _GLFW_PLATFORM_TLS_STATE _GLFWtlsWin32 win32 #define _GLFW_PLATFORM_TLS_STATE _GLFWtlsWin32 win32
#define _GLFW_PLATFORM_MUTEX_STATE _GLFWmutexWin32 win32
// Win32-specific per-window data // Win32-specific per-window data
@ -334,6 +335,15 @@ typedef struct _GLFWtlsWin32
} _GLFWtlsWin32; } _GLFWtlsWin32;
// Win32-specific mutex data
//
typedef struct _GLFWmutexWin32
{
GLFWbool allocated;
CRITICAL_SECTION section;
} _GLFWmutexWin32;
GLFWbool _glfwRegisterWindowClassWin32(void); GLFWbool _glfwRegisterWindowClassWin32(void);
void _glfwUnregisterWindowClassWin32(void); void _glfwUnregisterWindowClassWin32(void);

View File

@ -69,8 +69,29 @@ void _glfwPlatformSetTls(_GLFWtls* tls, void* value)
TlsSetValue(tls->win32.index, 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);
} }

View File

@ -192,7 +192,7 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
window->denom = GLFW_DONT_CARE; window->denom = GLFW_DONT_CARE;
// Save the currently current context so it can be restored later // 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) if (ctxconfig.client != GLFW_NO_API)
glfwMakeContextCurrent(NULL); glfwMakeContextCurrent(NULL);
@ -408,7 +408,7 @@ GLFWAPI void glfwDestroyWindow(GLFWwindow* handle)
// The window's context must not be current on another thread when the // The window's context must not be current on another thread when the
// window is destroyed // window is destroyed
if (window == _glfwPlatformGetTls(&_glfw.context)) if (window == _glfwPlatformGetTls(&_glfw.contextSlot))
glfwMakeContextCurrent(NULL); glfwMakeContextCurrent(NULL);
_glfwPlatformDestroyWindow(window); _glfwPlatformDestroyWindow(window);