aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2020-02-18 18:14:59 -0800
committerChris Robinson <[email protected]>2020-02-18 18:14:59 -0800
commit4277c05b0c41923af7ab852a63b1984b277a638a (patch)
tree5f457fad01c532a760a7ffe542d698c3f5aed0bb
parentd4e01a181837592d7a86bab9f8b24b4f3467f90e (diff)
Workaround a 32-bit GCC/MinGW TLS bug
-rw-r--r--alc/alc.cpp38
1 files changed, 22 insertions, 16 deletions
diff --git a/alc/alc.cpp b/alc/alc.cpp
index 948fbfb1..ad6f67b3 100644
--- a/alc/alc.cpp
+++ b/alc/alc.cpp
@@ -859,14 +859,20 @@ constexpr ALchar alExtList[] =
std::atomic<ALCenum> LastNullDeviceError{ALC_NO_ERROR};
-/* Thread-local current context */
+/* Thread-local current context. The handling may look a little obtuse, but
+ * it's designed this way to avoid a bug with 32-bit GCC/MinGW, which causes
+ * thread-local object destructors to get a junk 'this' pointer. This method
+ * has the benefit of making LocalContext access more efficient since it's a
+ * a plain pointer, with the ThreadContext object used to check it at thread
+ * exit (and given no data fields, 'this' being junk is inconsequential since
+ * it's never accessed).
+ */
+thread_local ALCcontext *LocalContext{nullptr};
class ThreadCtx {
- ALCcontext *ctx{nullptr};
-
public:
~ThreadCtx()
{
- if(ctx)
+ if(ALCcontext *ctx{LocalContext})
{
const bool result{ctx->releaseIfNoDelete()};
ERR("Context %p current for thread being destroyed%s!\n",
@@ -874,10 +880,10 @@ public:
}
}
- ALCcontext *get() const noexcept { return ctx; }
- void set(ALCcontext *ctx_) noexcept { ctx = ctx_; }
+ void set(ALCcontext *ctx) const noexcept { LocalContext = ctx; }
};
-thread_local ThreadCtx LocalContext;
+thread_local ThreadCtx ThreadContext;
+
/* Process-wide current context */
std::atomic<ALCcontext*> GlobalContext{nullptr};
@@ -2581,10 +2587,10 @@ void ALCcontext::init()
bool ALCcontext::deinit()
{
- if(LocalContext.get() == this)
+ if(LocalContext == this)
{
WARN("%p released while current on thread\n", decltype(std::declval<void*>()){this});
- LocalContext.set(nullptr);
+ ThreadContext.set(nullptr);
release();
}
@@ -2655,7 +2661,7 @@ static ContextRef VerifyContext(ALCcontext *context)
*/
ContextRef GetContextRef(void)
{
- ALCcontext *context{LocalContext.get()};
+ ALCcontext *context{LocalContext};
if(context)
context->add_ref();
else
@@ -3524,7 +3530,7 @@ END_API_FUNC
ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void)
START_API_FUNC
{
- ALCcontext *Context{LocalContext.get()};
+ ALCcontext *Context{LocalContext};
if(!Context) Context = GlobalContext.load();
return Context;
}
@@ -3536,7 +3542,7 @@ END_API_FUNC
*/
ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void)
START_API_FUNC
-{ return LocalContext.get(); }
+{ return LocalContext; }
END_API_FUNC
/* alcMakeContextCurrent
@@ -3568,8 +3574,8 @@ START_API_FUNC
* thread-local context. Take ownership of the thread-local context
* reference (if any), clearing the storage to null.
*/
- ctx = ContextRef{LocalContext.get()};
- if(ctx) LocalContext.set(nullptr);
+ ctx = ContextRef{LocalContext};
+ if(ctx) ThreadContext.set(nullptr);
/* Reset (decrement) the previous thread-local reference. */
return ALC_TRUE;
@@ -3595,8 +3601,8 @@ START_API_FUNC
}
}
/* context's reference count is already incremented */
- ContextRef old{LocalContext.get()};
- LocalContext.set(ctx.release());
+ ContextRef old{LocalContext};
+ ThreadContext.set(ctx.release());
return ALC_TRUE;
}