diff --git a/src/c11/impl/threads_win32.c b/src/c11/impl/threads_win32.c index 1b2b42bce94..67aa29e48ac 100644 --- a/src/c11/impl/threads_win32.c +++ b/src/c11/impl/threads_win32.c @@ -31,6 +31,7 @@ #include #include // MSVCRT #include +#include #include "c11/threads.h" @@ -83,13 +84,24 @@ Implementation limits: struct impl_thrd_param { thrd_start_t func; void *arg; + thrd_t thrd; }; +struct thrd_state { + thrd_t thrd; + bool handle_need_close; +}; + +static thread_local struct thrd_state impl_current_thread = { 0 }; + static unsigned __stdcall impl_thrd_routine(void *p) { + struct impl_thrd_param *pack_p = (struct impl_thrd_param *)p; struct impl_thrd_param pack; int code; - memcpy(&pack, p, sizeof(struct impl_thrd_param)); + impl_current_thread.thrd = pack_p->thrd; + impl_current_thread.handle_need_close = false; + memcpy(&pack, pack_p, sizeof(struct impl_thrd_param)); free(p); code = pack.func(pack.arg); return (unsigned)code; @@ -307,7 +319,12 @@ mtx_unlock(mtx_t *mtx) void __threads_win32_tls_callback(void) { + struct thrd_state *state = &impl_current_thread; impl_tss_dtor_invoke(); + if (state->handle_need_close) { + state->handle_need_close = false; + CloseHandle(state->thrd.handle); + } } /*------------------- 7.25.5 Thread functions -------------------*/ @@ -322,25 +339,23 @@ thrd_create(thrd_t *thr, thrd_start_t func, void *arg) if (!pack) return thrd_nomem; pack->func = func; pack->arg = arg; - handle = _beginthreadex(NULL, 0, impl_thrd_routine, pack, 0, NULL); + handle = _beginthreadex(NULL, 0, impl_thrd_routine, pack, CREATE_SUSPENDED, NULL); if (handle == 0) { free(pack); if (errno == EAGAIN || errno == EACCES) return thrd_nomem; return thrd_error; } - *thr = (thrd_t)handle; + thr->handle = (void*)handle; + pack->thrd = *thr; + ResumeThread((HANDLE)handle); return thrd_success; } -#if 0 // 7.25.5.2 -static inline thrd_t +thrd_t thrd_current(void) { - HANDLE hCurrentThread; - BOOL bRet; - /* GetCurrentThread() returns a pseudo-handle, which we need * to pass to DuplicateHandle(). Only the resulting handle can be used * from other threads. @@ -358,27 +373,24 @@ thrd_current(void) * Life would be much easier if C11 threads had different abstractions for * threads and thread IDs, just like C++11 threads does... */ - - bRet = DuplicateHandle(GetCurrentProcess(), // source process (pseudo) handle - GetCurrentThread(), // source (pseudo) handle - GetCurrentProcess(), // target process - &hCurrentThread, // target handle - 0, - FALSE, - DUPLICATE_SAME_ACCESS); - assert(bRet); - if (!bRet) { - hCurrentThread = GetCurrentThread(); + struct thrd_state *state = &impl_current_thread; + if (state->thrd.handle == NULL) + { + if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), + &(state->thrd.handle), 0, FALSE, DUPLICATE_SAME_ACCESS)) + { + abort(); + } + state->handle_need_close = true; } - return hCurrentThread; + return state->thrd; } -#endif // 7.25.5.3 int thrd_detach(thrd_t thr) { - CloseHandle(thr); + CloseHandle(thr.handle); return thrd_success; } @@ -386,7 +398,7 @@ thrd_detach(thrd_t thr) int thrd_equal(thrd_t thr0, thrd_t thr1) { - return GetThreadId(thr0) == GetThreadId(thr1); + return GetThreadId(thr0.handle) == GetThreadId(thr1.handle); } // 7.25.5.5 @@ -402,17 +414,20 @@ int thrd_join(thrd_t thr, int *res) { DWORD w, code; - w = WaitForSingleObject(thr, INFINITE); + if (thr.handle == NULL) { + return thrd_error; + } + w = WaitForSingleObject(thr.handle, INFINITE); if (w != WAIT_OBJECT_0) return thrd_error; if (res) { - if (!GetExitCodeThread(thr, &code)) { - CloseHandle(thr); + if (!GetExitCodeThread(thr.handle, &code)) { + CloseHandle(thr.handle); return thrd_error; } *res = (int)code; } - CloseHandle(thr); + CloseHandle(thr.handle); return thrd_success; } diff --git a/src/c11/threads.h b/src/c11/threads.h index c2818fd3012..ac6902f3b02 100644 --- a/src/c11/threads.h +++ b/src/c11/threads.h @@ -88,7 +88,11 @@ typedef struct { void *Ptr; } cnd_t; -typedef void *thrd_t; +/* Define thrd_t as struct type intentionally for avoid use of thrd_t as pointer type */ +typedef struct +{ + void *handle; +} thrd_t; typedef unsigned long tss_t; typedef struct { diff --git a/src/gallium/auxiliary/util/u_threaded_context.c b/src/gallium/auxiliary/util/u_threaded_context.c index 4a778c8c903..45cd8561aea 100644 --- a/src/gallium/auxiliary/util/u_threaded_context.c +++ b/src/gallium/auxiliary/util/u_threaded_context.c @@ -97,7 +97,7 @@ static void tc_set_driver_thread(struct threaded_context *tc) { #ifndef NDEBUG - tc->driver_thread = util_get_thread_id(); + tc->driver_thread = thrd_current(); #endif } diff --git a/src/gallium/auxiliary/util/u_threaded_context.h b/src/gallium/auxiliary/util/u_threaded_context.h index 9b330a849d2..95aa55e724f 100644 --- a/src/gallium/auxiliary/util/u_threaded_context.h +++ b/src/gallium/auxiliary/util/u_threaded_context.h @@ -485,7 +485,7 @@ struct threaded_context { * there are cases where the queue is flushed directly * from the frontend thread */ - thread_id driver_thread; + thrd_t driver_thread; #endif bool seen_tcs; @@ -600,7 +600,7 @@ tc_assert_driver_thread(struct threaded_context *tc) if (!tc) return; #ifndef NDEBUG - assert(util_thread_id_equal(tc->driver_thread, util_get_thread_id())); + assert(u_thread_is_self(tc->driver_thread)); #endif } diff --git a/src/gallium/drivers/llvmpipe/lp_rast.c b/src/gallium/drivers/llvmpipe/lp_rast.c index b92863f3c6e..36a23c96dd0 100644 --- a/src/gallium/drivers/llvmpipe/lp_rast.c +++ b/src/gallium/drivers/llvmpipe/lp_rast.c @@ -1337,7 +1337,7 @@ lp_rast_destroy(struct lp_rasterizer *rast) * other threads when returning from main. */ DWORD exit_code = STILL_ACTIVE; - if (GetExitCodeThread(rast->threads[i], &exit_code) && + if (GetExitCodeThread(rast->threads[i].handle, &exit_code) && exit_code == STILL_ACTIVE) { pipe_semaphore_wait(&rast->tasks[i].work_done); } diff --git a/src/util/u_thread.h b/src/util/u_thread.h index 804593f63eb..c25067930b2 100644 --- a/src/util/u_thread.h +++ b/src/util/u_thread.h @@ -197,7 +197,7 @@ util_set_thread_affinity(thrd_t thread, if (sizeof(m) > 4 && num_mask_bits > 32) m |= (uint64_t)mask[1] << 32; - m = SetThreadAffinityMask(thread, m); + m = SetThreadAffinityMask(thread.handle, m); if (!m) return false; @@ -221,21 +221,10 @@ util_set_current_thread_affinity(const uint32_t *mask, uint32_t *old_mask, unsigned num_mask_bits) { -#if defined(HAVE_PTHREAD_SETAFFINITY) - return util_set_thread_affinity(pthread_self(), mask, old_mask, + return util_set_thread_affinity(thrd_current(), mask, old_mask, num_mask_bits); - -#elif defined(_WIN32) && !defined(__CYGWIN__) - /* The GetCurrentThreadId() handle is only valid within the current thread. */ - return util_set_thread_affinity(GetCurrentThread(), mask, old_mask, - num_mask_bits); - -#else - return false; -#endif } - /* * Thread statistics. */ @@ -261,24 +250,12 @@ util_thread_get_time_nano(thrd_t thread) static inline int64_t util_current_thread_get_time_nano(void) { -#if defined(HAVE_PTHREAD) - return util_thread_get_time_nano(pthread_self()); - -#elif defined(_WIN32) && !defined(__CYGWIN__) - /* The GetCurrentThreadId() handle is only valid within the current thread. */ - return util_thread_get_time_nano(GetCurrentThread()); - -#else - return 0; -#endif + return util_thread_get_time_nano(thrd_current()); } static inline bool u_thread_is_self(thrd_t thread) { -#if defined(HAVE_PTHREAD) - return pthread_equal(pthread_self(), thread); -#endif - return false; + return thrd_equal(thrd_current(), thread); } /* @@ -357,45 +334,4 @@ static inline bool util_barrier_wait(util_barrier *barrier) #endif -/* - * Thread-id's. - * - * thrd_current() is not portable to windows (or at least not in a desirable - * way), so thread_id's provide an alternative mechanism - */ - -#ifdef _WIN32 -typedef DWORD thread_id; -#else -typedef thrd_t thread_id; -#endif - -static inline thread_id -util_get_thread_id(void) -{ - /* - * XXX: Callers of of this function assume it is a lightweight function. - * But unfortunately C11's thrd_current() gives no such guarantees. In - * fact, it's pretty hard to have a compliant implementation of - * thrd_current() on Windows with such characteristics. So for now, we - * side-step this mess and use Windows thread primitives directly here. - */ -#ifdef _WIN32 - return GetCurrentThreadId(); -#else - return thrd_current(); -#endif -} - - -static inline int -util_thread_id_equal(thread_id t1, thread_id t2) -{ -#ifdef _WIN32 - return t1 == t2; -#else - return thrd_equal(t1, t2); -#endif -} - #endif /* U_THREAD_H_ */