From 78efc180792d232ac2740cd7e2ed404731c61ebf Mon Sep 17 00:00:00 2001
From: Camilla Berglund <elmindreda@elmindreda.org>
Date: Sun, 30 Mar 2014 14:37:20 +0200
Subject: [PATCH] Split out TLS code into separate modules.

This allows the TLS code to be re-used by partial ports like EGL.
---
 src/CMakeLists.txt   | 12 ++++----
 src/cocoa_platform.h |  2 ++
 src/egl_context.c    | 28 ++++--------------
 src/glx_context.c    | 19 ++++--------
 src/glx_platform.h   |  5 ----
 src/internal.h       |  2 ++
 src/nsgl_context.m   | 17 ++---------
 src/nsgl_platform.h  |  4 ---
 src/posix_tls.c      | 66 ++++++++++++++++++++++++++++++++++++++++++
 src/posix_tls.h      | 55 +++++++++++++++++++++++++++++++++++
 src/wgl_context.c    | 25 ++++------------
 src/wgl_platform.h   |  4 ---
 src/win32_platform.h |  2 ++
 src/win32_tls.c      | 69 ++++++++++++++++++++++++++++++++++++++++++++
 src/win32_tls.h      | 54 ++++++++++++++++++++++++++++++++++
 src/x11_platform.h   |  2 ++
 16 files changed, 278 insertions(+), 88 deletions(-)
 create mode 100644 src/posix_tls.c
 create mode 100644 src/posix_tls.h
 create mode 100644 src/win32_tls.c
 create mode 100644 src/win32_tls.h

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index cd699efd..de00a8c1 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -12,20 +12,20 @@ set(common_SOURCES clipboard.c context.c gamma.c init.c input.c joystick.c
                    monitor.c time.c window.c)
 
 if (_GLFW_COCOA)
-    set(glfw_HEADERS ${common_HEADERS} cocoa_platform.h)
+    set(glfw_HEADERS ${common_HEADERS} cocoa_platform.h posix_tls.h)
     set(glfw_SOURCES ${common_SOURCES} cocoa_clipboard.m cocoa_gamma.c
                      cocoa_init.m cocoa_joystick.m cocoa_monitor.m cocoa_time.c
-                     cocoa_window.m)
+                     cocoa_window.m posix_tls.c)
 elseif (_GLFW_WIN32)
-    set(glfw_HEADERS ${common_HEADERS} win32_platform.h)
+    set(glfw_HEADERS ${common_HEADERS} win32_platform.h win32_tls.h)
     set(glfw_SOURCES ${common_SOURCES} win32_clipboard.c win32_gamma.c
                      win32_init.c win32_joystick.c win32_monitor.c win32_time.c
-                     win32_window.c)
+                     win32_tls.c win32_window.c)
 elseif (_GLFW_X11)
-    set(glfw_HEADERS ${common_HEADERS} x11_platform.h)
+    set(glfw_HEADERS ${common_HEADERS} x11_platform.h posix_tls.h)
     set(glfw_SOURCES ${common_SOURCES} x11_clipboard.c x11_gamma.c x11_init.c
                      x11_joystick.c x11_monitor.c x11_time.c x11_window.c
-                     x11_unicode.c)
+                     x11_unicode.c posix_tls.c)
 endif()
 
 if (_GLFW_EGL)
diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h
index b9acb66e..ef44abbd 100644
--- a/src/cocoa_platform.h
+++ b/src/cocoa_platform.h
@@ -37,6 +37,8 @@
 typedef void* id;
 #endif
 
+#include "posix_tls.h"
+
 #if defined(_GLFW_NSGL)
  #include "nsgl_platform.h"
 #else
diff --git a/src/egl_context.c b/src/egl_context.c
index 7caff10f..e9fd0242 100644
--- a/src/egl_context.c
+++ b/src/egl_context.c
@@ -32,22 +32,6 @@
 #include <assert.h>
 
 
-// Thread local storage attribute macro
-//
-#if defined(_MSC_VER)
- #define _GLFW_TLS __declspec(thread)
-#elif defined(__GNUC__)
- #define _GLFW_TLS __thread
-#else
- #define _GLFW_TLS
-#endif
-
-
-// The per-thread current context/window pointer
-//
-static _GLFW_TLS _GLFWwindow* _glfwCurrentWindow = NULL;
-
-
 // Return a description of the specified EGL error
 //
 static const char* getErrorString(EGLint error)
@@ -207,6 +191,9 @@ static GLboolean chooseFBConfigs(const _GLFWctxconfig* ctxconfig,
 //
 int _glfwInitContextAPI(void)
 {
+    if (!_glfwInitTLS())
+        return GL_FALSE;
+
     _glfw.egl.display = eglGetDisplay((EGLNativeDisplayType)_GLFW_EGL_NATIVE_DISPLAY);
     if (_glfw.egl.display == EGL_NO_DISPLAY)
     {
@@ -237,6 +224,8 @@ int _glfwInitContextAPI(void)
 void _glfwTerminateContextAPI(void)
 {
     eglTerminate(_glfw.egl.display);
+
+    _glfwTerminateTLS();
 }
 
 #define setEGLattrib(attribName, attribValue) \
@@ -482,12 +471,7 @@ void _glfwPlatformMakeContextCurrent(_GLFWwindow* window)
                        EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
     }
 
-    _glfwCurrentWindow = window;
-}
-
-_GLFWwindow* _glfwPlatformGetCurrentContext(void)
-{
-    return _glfwCurrentWindow;
+    _glfwSetCurrentContext(window);
 }
 
 void _glfwPlatformSwapBuffers(_GLFWwindow* window)
diff --git a/src/glx_context.c b/src/glx_context.c
index 0cf10fd0..076b7b3c 100644
--- a/src/glx_context.c
+++ b/src/glx_context.c
@@ -165,6 +165,9 @@ static GLXContext createLegacyContext(_GLFWwindow* window,
 //
 int _glfwInitContextAPI(void)
 {
+    if (!_glfwInitTLS())
+        return GL_FALSE;
+
 #ifdef _GLFW_DLOPEN_LIBGL
     _glfw.glx.libGL = dlopen("libGL.so.1", RTLD_LAZY | RTLD_GLOBAL);
     if (!_glfw.glx.libGL)
@@ -174,13 +177,6 @@ int _glfwInitContextAPI(void)
     }
 #endif
 
-    if (pthread_key_create(&_glfw.glx.current, NULL) != 0)
-    {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "GLX: Failed to create context TLS");
-        return GL_FALSE;
-    }
-
     if (!glXQueryExtension(_glfw.x11.display,
                            &_glfw.glx.errorBase,
                            &_glfw.glx.eventBase))
@@ -272,7 +268,7 @@ void _glfwTerminateContextAPI(void)
     }
 #endif
 
-    pthread_key_delete(_glfw.glx.current);
+    _glfwTerminateTLS();
 }
 
 #define setGLXattrib(attribName, attribValue) \
@@ -478,12 +474,7 @@ void _glfwPlatformMakeContextCurrent(_GLFWwindow* window)
     else
         glXMakeCurrent(_glfw.x11.display, None, NULL);
 
-    pthread_setspecific(_glfw.glx.current, window);
-}
-
-_GLFWwindow* _glfwPlatformGetCurrentContext(void)
-{
-    return (_GLFWwindow*) pthread_getspecific(_glfw.glx.current);
+    _glfwSetCurrentContext(window);
 }
 
 void _glfwPlatformSwapBuffers(_GLFWwindow* window)
diff --git a/src/glx_platform.h b/src/glx_platform.h
index da96b433..440f599c 100644
--- a/src/glx_platform.h
+++ b/src/glx_platform.h
@@ -41,8 +41,6 @@
  #include <dlfcn.h>
 #endif
 
-#include <pthread.h>
-
 // We support four different ways for getting addresses for GL/GLX
 // extension functions: glXGetProcAddress, glXGetProcAddressARB,
 // glXGetProcAddressEXT, and dlsym
@@ -93,9 +91,6 @@ typedef struct _GLFWlibraryGLX
     int             eventBase;
     int             errorBase;
 
-    // TLS key for per-thread current context/window
-    pthread_key_t   current;
-
     // GLX extensions
     PFNGLXSWAPINTERVALSGIPROC             SwapIntervalSGI;
     PFNGLXSWAPINTERVALEXTPROC             SwapIntervalEXT;
diff --git a/src/internal.h b/src/internal.h
index 7a44d12f..5b24b427 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -348,6 +348,8 @@ struct _GLFWlibrary
     _GLFW_PLATFORM_LIBRARY_WINDOW_STATE;
     // This is defined in the context API's platform.h
     _GLFW_PLATFORM_LIBRARY_OPENGL_STATE;
+    // This is defined in the platform's tls.h
+    _GLFW_PLATFORM_TLS_STATE;
 };
 
 
diff --git a/src/nsgl_context.m b/src/nsgl_context.m
index 47d01956..32ef85c8 100644
--- a/src/nsgl_context.m
+++ b/src/nsgl_context.m
@@ -26,8 +26,6 @@
 
 #include "internal.h"
 
-#include <pthread.h>
-
 
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW internal API                      //////
@@ -37,12 +35,8 @@
 //
 int _glfwInitContextAPI(void)
 {
-    if (pthread_key_create(&_glfw.nsgl.current, NULL) != 0)
-    {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "NSGL: Failed to create context TLS");
+    if (!_glfwInitTLS())
         return GL_FALSE;
-    }
 
     _glfw.nsgl.framework =
         CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
@@ -60,7 +54,7 @@ int _glfwInitContextAPI(void)
 //
 void _glfwTerminateContextAPI(void)
 {
-    pthread_key_delete(_glfw.nsgl.current);
+    _glfwTerminateTLS();
 }
 
 // Create the OpenGL context
@@ -235,12 +229,7 @@ void _glfwPlatformMakeContextCurrent(_GLFWwindow* window)
     else
         [NSOpenGLContext clearCurrentContext];
 
-    pthread_setspecific(_glfw.nsgl.current, window);
-}
-
-_GLFWwindow* _glfwPlatformGetCurrentContext(void)
-{
-    return (_GLFWwindow*) pthread_getspecific(_glfw.nsgl.current);
+    _glfwSetCurrentContext(window);
 }
 
 void _glfwPlatformSwapBuffers(_GLFWwindow* window)
diff --git a/src/nsgl_platform.h b/src/nsgl_platform.h
index fd9b5e05..86c0dd1f 100644
--- a/src/nsgl_platform.h
+++ b/src/nsgl_platform.h
@@ -27,7 +27,6 @@
 #ifndef _nsgl_platform_h_
 #define _nsgl_platform_h_
 
-
 #define _GLFW_PLATFORM_FBCONFIG
 #define _GLFW_PLATFORM_CONTEXT_STATE        _GLFWcontextNSGL nsgl
 #define _GLFW_PLATFORM_LIBRARY_OPENGL_STATE _GLFWlibraryNSGL nsgl
@@ -55,9 +54,6 @@ typedef struct _GLFWlibraryNSGL
     // dlopen handle for dynamically loading OpenGL extension entry points
     void*           framework;
 
-    // TLS key for per-thread current context/window
-    pthread_key_t   current;
-
 } _GLFWlibraryNSGL;
 
 
diff --git a/src/posix_tls.c b/src/posix_tls.c
new file mode 100644
index 00000000..70fe19bb
--- /dev/null
+++ b/src/posix_tls.c
@@ -0,0 +1,66 @@
+//========================================================================
+// GLFW 3.1 POSIX - www.glfw.org
+//------------------------------------------------------------------------
+// Copyright (c) 2002-2006 Marcus Geelnard
+// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+//    claim that you wrote the original software. If you use this software
+//    in a product, an acknowledgment in the product documentation would
+//    be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such, and must not
+//    be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source
+//    distribution.
+//
+//========================================================================
+
+#include "internal.h"
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                       GLFW internal API                      //////
+//////////////////////////////////////////////////////////////////////////
+
+int _glfwInitTLS(void)
+{
+    if (pthread_key_create(&_glfw.posix_tls.context, NULL) != 0)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "POSIX: Failed to create context TLS");
+        return GL_FALSE;
+    }
+
+    return GL_TRUE;
+}
+
+void _glfwTerminateTLS(void)
+{
+    pthread_key_delete(_glfw.posix_tls.context);
+}
+
+void _glfwSetCurrentContext(_GLFWwindow* context)
+{
+    pthread_setspecific(_glfw.posix_tls.context, context);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                       GLFW platform API                      //////
+//////////////////////////////////////////////////////////////////////////
+
+_GLFWwindow* _glfwPlatformGetCurrentContext(void)
+{
+    return pthread_getspecific(_glfw.posix_tls.context);
+}
+
diff --git a/src/posix_tls.h b/src/posix_tls.h
new file mode 100644
index 00000000..bd644da4
--- /dev/null
+++ b/src/posix_tls.h
@@ -0,0 +1,55 @@
+//========================================================================
+// GLFW 3.1 POSIX - www.glfw.org
+//------------------------------------------------------------------------
+// Copyright (c) 2002-2006 Marcus Geelnard
+// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+//    claim that you wrote the original software. If you use this software
+//    in a product, an acknowledgment in the product documentation would
+//    be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such, and must not
+//    be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source
+//    distribution.
+//
+//========================================================================
+
+#ifndef _posix_tls_h_
+#define _posix_tls_h_
+
+#include <pthread.h>
+
+#define _GLFW_PLATFORM_TLS_STATE _GLFWtlsPOSIX posix_tls
+
+
+//========================================================================
+// GLFW platform specific types
+//========================================================================
+
+typedef struct _GLFWtlsPOSIX
+{
+    pthread_key_t   context;
+
+} _GLFWtlsPOSIX;
+
+
+//========================================================================
+// Prototypes for platform specific internal functions
+//========================================================================
+
+int _glfwInitTLS(void);
+void _glfwTerminateTLS(void);
+void _glfwSetCurrentContext(_GLFWwindow* context);
+
+#endif // _posix_tls_h_
diff --git a/src/wgl_context.c b/src/wgl_context.c
index 2cb85ec2..038846c5 100644
--- a/src/wgl_context.c
+++ b/src/wgl_context.c
@@ -306,6 +306,9 @@ static GLboolean choosePixelFormat(_GLFWwindow* window,
 //
 int _glfwInitContextAPI(void)
 {
+    if (!_glfwInitTLS())
+        return GL_FALSE;
+
     _glfw.wgl.opengl32.instance = LoadLibraryW(L"opengl32.dll");
     if (!_glfw.wgl.opengl32.instance)
     {
@@ -313,16 +316,6 @@ int _glfwInitContextAPI(void)
         return GL_FALSE;
     }
 
-    _glfw.wgl.current = TlsAlloc();
-    if (_glfw.wgl.current == TLS_OUT_OF_INDEXES)
-    {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "WGL: Failed to allocate TLS index");
-        return GL_FALSE;
-    }
-
-    _glfw.wgl.hasTLS = GL_TRUE;
-
     return GL_TRUE;
 }
 
@@ -330,11 +323,10 @@ int _glfwInitContextAPI(void)
 //
 void _glfwTerminateContextAPI(void)
 {
-    if (_glfw.wgl.hasTLS)
-        TlsFree(_glfw.wgl.current);
-
     if (_glfw.wgl.opengl32.instance)
         FreeLibrary(_glfw.wgl.opengl32.instance);
+
+    _glfwTerminateTLS();
 }
 
 #define setWGLattrib(attribName, attribValue) \
@@ -588,12 +580,7 @@ void _glfwPlatformMakeContextCurrent(_GLFWwindow* window)
     else
         wglMakeCurrent(NULL, NULL);
 
-    TlsSetValue(_glfw.wgl.current, window);
-}
-
-_GLFWwindow* _glfwPlatformGetCurrentContext(void)
-{
-    return TlsGetValue(_glfw.wgl.current);
+    _glfwSetCurrentContext(window);
 }
 
 void _glfwPlatformSwapBuffers(_GLFWwindow* window)
diff --git a/src/wgl_platform.h b/src/wgl_platform.h
index dd1cc5b7..7fea8695 100644
--- a/src/wgl_platform.h
+++ b/src/wgl_platform.h
@@ -33,7 +33,6 @@
 // extensions and not all operating systems come with an up-to-date version
 #include "../deps/GL/wglext.h"
 
-
 #define _GLFW_PLATFORM_FBCONFIG             int             wgl
 #define _GLFW_PLATFORM_CONTEXT_STATE        _GLFWcontextWGL wgl
 #define _GLFW_PLATFORM_LIBRARY_OPENGL_STATE _GLFWlibraryWGL wgl
@@ -74,9 +73,6 @@ typedef struct _GLFWcontextWGL
 //------------------------------------------------------------------------
 typedef struct _GLFWlibraryWGL
 {
-    GLboolean       hasTLS;
-    DWORD           current;
-
     // opengl32.dll
     struct {
         HINSTANCE   instance;
diff --git a/src/win32_platform.h b/src/win32_platform.h
index 5ecdd09f..aecdf272 100644
--- a/src/win32_platform.h
+++ b/src/win32_platform.h
@@ -151,6 +151,8 @@ typedef HRESULT (WINAPI * DWMISCOMPOSITIONENABLED_T)(BOOL*);
 #define _GLFW_RECREATION_IMPOSSIBLE 2
 
 
+#include "win32_tls.h"
+
 #if defined(_GLFW_WGL)
  #include "wgl_platform.h"
 #elif defined(_GLFW_EGL)
diff --git a/src/win32_tls.c b/src/win32_tls.c
new file mode 100644
index 00000000..088e25df
--- /dev/null
+++ b/src/win32_tls.c
@@ -0,0 +1,69 @@
+//========================================================================
+// GLFW 3.1 Win32 - www.glfw.org
+//------------------------------------------------------------------------
+// Copyright (c) 2002-2006 Marcus Geelnard
+// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+//    claim that you wrote the original software. If you use this software
+//    in a product, an acknowledgment in the product documentation would
+//    be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such, and must not
+//    be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source
+//    distribution.
+//
+//========================================================================
+
+#include "internal.h"
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                       GLFW internal API                      //////
+//////////////////////////////////////////////////////////////////////////
+
+int _glfwInitTLS(void)
+{
+    _glfw.win32_tls.context = TlsAlloc();
+    if (_glfw.win32_tls.context == TLS_OUT_OF_INDEXES)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Win32: Failed to allocate TLS index");
+        return GL_FALSE;
+    }
+
+    _glfw.win32_tls.allocated = GL_TRUE;
+    return GL_TRUE;
+}
+
+void _glfwTerminateTLS(void)
+{
+    if (_glfw.win32_tls.allocated)
+        TlsFree(_glfw.win32_tls.context);
+}
+
+void _glfwSetCurrentContext(_GLFWwindow* context)
+{
+    TlsSetValue(_glfw.win32_tls.context, context);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                       GLFW platform API                      //////
+//////////////////////////////////////////////////////////////////////////
+
+_GLFWwindow* _glfwPlatformGetCurrentContext(void)
+{
+    return TlsGetValue(_glfw.win32_tls.context);
+}
+
diff --git a/src/win32_tls.h b/src/win32_tls.h
new file mode 100644
index 00000000..ef2d4194
--- /dev/null
+++ b/src/win32_tls.h
@@ -0,0 +1,54 @@
+//========================================================================
+// GLFW 3.1 Win32 - www.glfw.org
+//------------------------------------------------------------------------
+// Copyright (c) 2002-2006 Marcus Geelnard
+// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+//    claim that you wrote the original software. If you use this software
+//    in a product, an acknowledgment in the product documentation would
+//    be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such, and must not
+//    be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source
+//    distribution.
+//
+//========================================================================
+
+#ifndef _win32_tls_h_
+#define _win32_tls_h_
+
+#define _GLFW_PLATFORM_TLS_STATE _GLFWtlsWin32 win32_tls
+
+
+//========================================================================
+// GLFW platform specific types
+//========================================================================
+
+typedef struct _GLFWtlsWin32
+{
+    GLboolean       allocated;
+    DWORD           context;
+
+} _GLFWtlsWin32;
+
+
+//========================================================================
+// Prototypes for platform specific internal functions
+//========================================================================
+
+int _glfwInitTLS(void);
+void _glfwTerminateTLS(void);
+void _glfwSetCurrentContext(_GLFWwindow* context);
+
+#endif // _win32_tls_h_
diff --git a/src/x11_platform.h b/src/x11_platform.h
index 0eb27fb5..fca8d3e1 100644
--- a/src/x11_platform.h
+++ b/src/x11_platform.h
@@ -48,6 +48,8 @@
 // The Xkb extension provides improved keyboard support
 #include <X11/XKBlib.h>
 
+#include "posix_tls.h"
+
 #if defined(_GLFW_GLX)
  #define _GLFW_X11_CONTEXT_VISUAL window->glx.visual
  #include "glx_platform.h"