mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-09 04:38:03 +02:00
c11: Implement and use of thrd_current properly on win32
Now thrd_t are a struct that contains both thread handle and thread id. For threads that not created by thrd_create, thrd_current are returning pseudo thread handle; but we can still compare threads differences by using thread id. Signed-off-by: Yonggang Luo <luoyonggang@gmail.com> Reviewed-by: Jesse Natalie <jenatali@microsoft.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/17071>
This commit is contained in:
parent
125a952b66
commit
e7b4af434b
6 changed files with 55 additions and 100 deletions
|
|
@ -31,6 +31,7 @@
|
|||
#include <errno.h>
|
||||
#include <process.h> // MSVCRT
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_ */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue