diff options
author | Chris Robinson <[email protected]> | 2020-02-18 18:14:59 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2020-02-18 18:14:59 -0800 |
commit | 4277c05b0c41923af7ab852a63b1984b277a638a (patch) | |
tree | 5f457fad01c532a760a7ffe542d698c3f5aed0bb | |
parent | d4e01a181837592d7a86bab9f8b24b4f3467f90e (diff) |
Workaround a 32-bit GCC/MinGW TLS bug
-rw-r--r-- | alc/alc.cpp | 38 |
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; } |