From fb3f1a5841b1d5ac6baad71b0a87a9a5cb080f68 Mon Sep 17 00:00:00 2001 From: LIU Hao Date: Tue, 26 Nov 2024 13:19:06 +0800 Subject: [PATCH] gthr_aux: Unify thread implementation Reference: https://github.com/lhmouse/mcfgthread/issues/270 Signed-off-by: LIU Hao --- mcfgthread/c11.c | 10 ------ mcfgthread/c11.h | 56 ++++-------------------------- mcfgthread/gthr.h | 61 ++++++++------------------------- mcfgthread/gthr_aux.c | 72 ++++++++++++++++++++++++++++++++++++--- mcfgthread/gthr_aux.h | 19 +++++++---- mcfgthread/gthr_libobjc.h | 11 ++---- mcfgthread/libcxx.h | 40 +++------------------- mcfgthread/xglobals.h | 6 ++++ 8 files changed, 115 insertions(+), 160 deletions(-) diff --git a/mcfgthread/c11.c b/mcfgthread/c11.c index ef2134d3c3..936c5fb466 100644 --- a/mcfgthread/c11.c +++ b/mcfgthread/c11.c @@ -12,16 +12,6 @@ #include "c11.h" #include "clock.h" -__MCF_DLLEXPORT -void -__MCF_c11_thread_thunk_v2(_MCF_thread* thrd) - { - __MCF_c11_thread_record* rec = _MCF_thread_get_data(thrd); - - /* Invoke the user-defined procedure and save its result in the record. */ - rec->__result = (*(rec->__proc)) (rec->__arg); - } - __MCF_DLLEXPORT int __MCF_c11_thrd_sleep(const __MCF_timespec* dur, __MCF_timespec* rem_opt) diff --git a/mcfgthread/c11.h b/mcfgthread/c11.h index b7f12ffbdc..890a6535aa 100644 --- a/mcfgthread/c11.h +++ b/mcfgthread/c11.h @@ -56,11 +56,6 @@ typedef _MCF_once once_flag; typedef _MCF_cond cnd_t; typedef __MCF_c11_mutex mtx_t; -/* This is the actual thread function for a C11 thread. */ -__MCF_C11_IMPORT -void -__MCF_c11_thread_thunk_v2(_MCF_thread* __thrd) __MCF_noexcept; - /* Define enumeration constants. */ enum __MCF_mtx_type { @@ -510,16 +505,8 @@ __MCF_C11_INLINE int __MCF_c11_thrd_create(thrd_t* __thrdp, thrd_start_t __proc, void* __arg) __MCF_noexcept { - __MCF_c11_thread_record __rec[1] = __MCF_0_INIT; - _MCF_thread* __thrd; - - __rec->__proc = __proc; - __rec->__arg = __arg; - __rec->__joinable[0] = 1; - - __thrd = _MCF_thread_new(__MCF_c11_thread_thunk_v2, __rec, sizeof(*__rec)); - *__thrdp = __thrd; - return (__thrd == __MCF_nullptr) ? thrd_nomem : thrd_success; + *__thrdp = __MCF_gthr_thread_create_v3(__MCF_CAST_PTR(__MCF_gthr_thread_procedure, __proc), __arg); + return (*__thrdp == __MCF_nullptr) ? thrd_nomem : thrd_success; } __MCF_C11_INLINE __MCF_FN_CONST @@ -533,15 +520,6 @@ __MCF_C11_INLINE int __MCF_c11_thrd_detach(thrd_t __thrd) __MCF_noexcept { - __MCF_c11_thread_record* __rec = __MCF_nullptr; - if(__thrd->__proc == __MCF_c11_thread_thunk_v2) - __rec = (__MCF_c11_thread_record*) _MCF_thread_get_data(__thrd); - - /* Clear the joinable state. If the thread is not joinable, fail. */ - if(__rec && (_MCF_atomic_xchg_8_rlx(__rec->__joinable, 0) == 0)) - return thrd_error; - - /* Free the thread. */ _MCF_thread_drop_ref(__thrd); return thrd_success; } @@ -557,37 +535,17 @@ __MCF_C11_INLINE __MCF_NEVER_RETURN void __MCF_c11_thrd_exit(int __result) __MCF_noexcept { - _MCF_thread* __self = _MCF_thread_self(); - int* __resp = __MCF_nullptr; - if(__self->__proc == __MCF_c11_thread_thunk_v2) - __resp = &(((__MCF_c11_thread_record*) _MCF_thread_get_data(__self))->__result); - - /* Set the exit status and exit. Unlike `ExitThread()`, if the last - * thread exits, the current process exits with zero. */ - __MCF_SET_IF(__resp, __result); - _MCF_thread_exit(); + __MCF_gthr_thread_exit_v3((void*)(intptr_t) __result); } __MCF_C11_INLINE int __MCF_c11_thrd_join(thrd_t __thrd, int* __resp_opt) __MCF_noexcept { - __MCF_c11_thread_record* __rec = __MCF_nullptr; - if(__thrd->__proc == __MCF_c11_thread_thunk_v2) - __rec = (__MCF_c11_thread_record*) _MCF_thread_get_data(__thrd); - - if(__thrd->__tid == _MCF_thread_self_tid()) - return thrd_error; - - /* Clear the joinable state. If the thread is not joinable, fail. */ - if(__rec && (_MCF_atomic_xchg_8_rlx(__rec->__joinable, 0) == 0)) - return thrd_error; - - /* Wait for the thread to terminate. */ - _MCF_thread_wait(__thrd, __MCF_nullptr); - __MCF_SET_IF(__resp_opt, __rec ? __rec->__result : 0); - _MCF_thread_drop_ref(__thrd); - return 0; + void* __resp; + __MCF_gthr_thread_join_v3(__thrd, &__resp); + __MCF_SET_IF(__resp_opt, (int)(intptr_t) __resp); + return thrd_success; } __MCF_C11_INLINE diff --git a/mcfgthread/gthr.h b/mcfgthread/gthr.h index ec7ce4b06a..ac14cf780f 100644 --- a/mcfgthread/gthr.h +++ b/mcfgthread/gthr.h @@ -305,31 +305,31 @@ __MCF_FNA(__MCF_gthr_cond_broadcast, __gthread_cond_broadcast); /* Creates a thread, like `pthread_create()`. */ __MCF_GTHR_IMPORT int -__MCF_gthr_create_v2(__gthread_t* __thrdp, __MCF_gthr_thread_procedure* __proc, void* __arg) __MCF_noexcept; +__MCF_gthr_create_v3(__gthread_t* __thrdp, __MCF_gthr_thread_procedure* __proc, void* __arg) __MCF_noexcept; #ifndef __MCF_GTHR_NO_ALIASES -__MCF_FNA(__MCF_gthr_create_v2, __gthread_create); -# define __MCF_gthr_create_v2 __gthread_create +__MCF_FNA(__MCF_gthr_create_v3, __gthread_create); +# define __MCF_gthr_create_v3 __gthread_create #endif /* Awaits a thread to terminate and gets its result, like `pthread_join()`. */ __MCF_GTHR_IMPORT int -__MCF_gthr_join_v2(__gthread_t __thrd, void** __resp_opt) __MCF_noexcept; +__MCF_gthr_join_v3(__gthread_t __thrd, void** __resp_opt) __MCF_noexcept; #ifndef __MCF_GTHR_NO_ALIASES -__MCF_FNA(__MCF_gthr_join_v2, __gthread_join); -# define __MCF_gthr_join_v2 __gthread_join +__MCF_FNA(__MCF_gthr_join_v3, __gthread_join); +# define __MCF_gthr_join_v3 __gthread_join #endif /* Detaches a thread, like `pthread_detach()` */ __MCF_GTHR_IMPORT int -__MCF_gthr_detach_v2(__gthread_t __thrd) __MCF_noexcept; +__MCF_gthr_detach(__gthread_t __thrd) __MCF_noexcept; #ifndef __MCF_GTHR_NO_ALIASES -__MCF_FNA(__MCF_gthr_detach_v2, __gthread_detach); -# define __MCF_gthr_detach_v2 __gthread_detach +__MCF_FNA(__MCF_gthr_detach, __gthread_detach); +# define __MCF_gthr_detach __gthread_detach #endif /* Gets a thread itself, like `pthread_self()`. @@ -593,55 +593,24 @@ __MCF_gthr_cond_broadcast(__gthread_cond_t* __cond) __MCF_noexcept __MCF_GTHR_INLINE int -__MCF_gthr_create_v2(__gthread_t* __thrdp, __MCF_gthr_thread_procedure* __proc, void* __arg) __MCF_noexcept +__MCF_gthr_create_v3(__gthread_t* __thrdp, __MCF_gthr_thread_procedure* __proc, void* __arg) __MCF_noexcept { - __MCF_gthr_thread_record __rec[1] = __MCF_0_INIT; - _MCF_thread* __thrd; - - __rec->__proc = __proc; - __rec->__arg = __arg; - __rec->__joinable[0] = 1; - - __thrd = _MCF_thread_new(__MCF_gthr_thread_thunk_v2, __rec, sizeof(*__rec)); - *__thrdp = __thrd; - return (__thrd == __MCF_nullptr) ? EAGAIN : 0; + *__thrdp = __MCF_gthr_thread_create_v3(__proc, __arg); + return (*__thrdp == __MCF_nullptr) ? EAGAIN : 0; } __MCF_GTHR_INLINE int -__MCF_gthr_join_v2(__gthread_t __thrd, void** __resp_opt) __MCF_noexcept +__MCF_gthr_join_v3(__gthread_t __thrd, void** __resp_opt) __MCF_noexcept { - __MCF_gthr_thread_record* __rec = __MCF_nullptr; - if(__thrd->__proc == __MCF_gthr_thread_thunk_v2) - __rec = (__MCF_gthr_thread_record*) _MCF_thread_get_data(__thrd); - - if(__thrd->__tid == _MCF_thread_self_tid()) - return EDEADLK; - - /* Clear the joinable state. If the thread is not joinable, fail. */ - if(__rec && (_MCF_atomic_xchg_8_rlx(__rec->__joinable, 0) == 0)) - return EINVAL; - - /* Wait for the thread to terminate. */ - _MCF_thread_wait(__thrd, __MCF_nullptr); - __MCF_SET_IF(__resp_opt, __rec ? __rec->__result : __MCF_nullptr); - _MCF_thread_drop_ref(__thrd); + __MCF_gthr_thread_join_v3(__thrd, __resp_opt); return 0; } __MCF_GTHR_INLINE int -__MCF_gthr_detach_v2(__gthread_t __thrd) __MCF_noexcept +__MCF_gthr_detach(__gthread_t __thrd) __MCF_noexcept { - __MCF_gthr_thread_record* __rec = __MCF_nullptr; - if(__thrd->__proc == __MCF_gthr_thread_thunk_v2) - __rec = (__MCF_gthr_thread_record*) _MCF_thread_get_data(__thrd); - - /* Clear the joinable state. If the thread is not joinable, fail. */ - if(__rec && (_MCF_atomic_xchg_8_rlx(__rec->__joinable, 0) == 0)) - return EINVAL; - - /* Free the thread. */ _MCF_thread_drop_ref(__thrd); return 0; } diff --git a/mcfgthread/gthr_aux.c b/mcfgthread/gthr_aux.c index 51e48225bc..5ca5d9eb3f 100644 --- a/mcfgthread/gthr_aux.c +++ b/mcfgthread/gthr_aux.c @@ -301,12 +301,76 @@ __MCF_gthr_cond_recursive_mutex_wait(_MCF_cond* cond, __MCF_gthr_rc_mutex* rmtx, (intptr_t) rmtx, timeout_opt); } -__MCF_DLLEXPORT +static __MCF_ALIGNED(16) +const GUID gthread_guid = __MCF_GUID(9FB2D15C,C5F2,4AE7,868D,2769591B8E92); + +static void -__MCF_gthr_thread_thunk_v2(_MCF_thread* thrd) +do_gthr_thread_thunk_v3(_MCF_thread* thrd) { __MCF_gthr_thread_record* rec = _MCF_thread_get_data(thrd); + rec->__arg_or_result = (*(rec->__proc)) (rec->__arg_or_result); + } + +static inline +__MCF_gthr_thread_record* +do_gthr_get_thread_record(_MCF_thread* thrd) + { + __MCF_gthr_thread_record* rec = _MCF_thread_get_data(thrd); + if(!rec) + return __MCF_nullptr; + + /* Check the GUID. As user-defined data are aligned to 16-byte boundaries, + * there must be at least 16 bytes available. */ + if(__builtin_memcmp(rec->__magic_guid, >hread_guid, 16) != 0) + return __MCF_nullptr; + + /* Assume so. `do_gthr_thread_thunk_v3()` is not shared across modules, + * so we should not check it for uniqueness. */ + return rec; + } + +__MCF_DLLEXPORT +_MCF_thread* +__MCF_gthr_thread_create_v3(__MCF_gthr_thread_procedure* proc, void* arg) + { + __MCF_ALIGNED(16) __MCF_gthr_thread_record record; + __builtin_memcpy(record.__magic_guid, >hread_guid, 16); + record.__proc = proc; + record.__arg_or_result = arg; + return _MCF_thread_new(do_gthr_thread_thunk_v3, &record, sizeof(record)); + } + +__MCF_DLLEXPORT +void +__MCF_gthr_thread_join_v3(_MCF_thread* thrd, void** resp_opt) + { + /* Wait for the thread to terminate. */ + __MCF_ASSERT(thrd->__tid != _MCF_thread_self_tid()); + _MCF_thread_wait(thrd, __MCF_nullptr); + + if(resp_opt) { + *resp_opt = __MCF_nullptr; + + /* Get the exit code. */ + __MCF_gthr_thread_record* rec = do_gthr_get_thread_record(thrd); + if(rec) + *resp_opt = rec->__arg_or_result; + } + + /* Free the thread. */ + _MCF_thread_drop_ref(thrd); + } + +__MCF_DLLEXPORT +void +__MCF_gthr_thread_exit_v3(void* resp) + { + /* Set the exit code. */ + __MCF_gthr_thread_record* rec = do_gthr_get_thread_record(_MCF_thread_self()); + if(rec) + rec->__arg_or_result = resp; - /* Invoke the user-defined procedure and save its result in the record. */ - rec->__result = (*(rec->__proc)) (rec->__arg); + /* Terminate the current thread. */ + _MCF_thread_exit(); } diff --git a/mcfgthread/gthr_aux.h b/mcfgthread/gthr_aux.h index 56b0e46df0..7e9a37e967 100644 --- a/mcfgthread/gthr_aux.h +++ b/mcfgthread/gthr_aux.h @@ -36,12 +36,9 @@ struct __MCF_gthr_rc_mutex struct __MCF_gthr_thread_record { - void* __result; + uint8_t __magic_guid[16]; __MCF_gthr_thread_procedure* __proc; - void* __arg; - uint8_t __joinable[1]; - uintptr_t __reserved_low; - uintptr_t __reserved_high; + void* __arg_or_result; }; /* These functions implement `__gthread_once()`. If `__once_fn` initiates stack @@ -135,10 +132,18 @@ __MCF_GTHR_AUX_IMPORT int __MCF_gthr_cond_recursive_mutex_wait(_MCF_cond* __cond, __MCF_gthr_rc_mutex* __rmtx, int64_t* __timeout_opt) __MCF_noexcept; -/* This is the actual thread function for a gthread. */ +/* These are auxiliary functions for threads. */ __MCF_GTHR_AUX_IMPORT +_MCF_thread* +__MCF_gthr_thread_create_v3(__MCF_gthr_thread_procedure* __proc, void* __arg) __MCF_noexcept; + +__MCF_GTHR_AUX_IMPORT +void +__MCF_gthr_thread_join_v3(_MCF_thread* __thrd, void** __resp_opt) __MCF_noexcept; + +__MCF_GTHR_AUX_IMPORT __MCF_NEVER_RETURN void -__MCF_gthr_thread_thunk_v2(_MCF_thread* __thrd) __MCF_noexcept; +__MCF_gthr_thread_exit_v3(void* __resp) __MCF_noexcept; /* Define inline functions after all declarations. * We would like to keep them away from declarations for conciseness, which also diff --git a/mcfgthread/gthr_libobjc.h b/mcfgthread/gthr_libobjc.h index 9b9d754e50..329b855d70 100644 --- a/mcfgthread/gthr_libobjc.h +++ b/mcfgthread/gthr_libobjc.h @@ -352,19 +352,14 @@ __MCF_GTHR_LIBOBJC_INLINE objc_thread_t __MCF_gthr_objc_thread_detach(__MCF_gthr_thread_procedure* __proc, void* __arg) __MCF_noexcept { - __MCF_gthr_thread_record __rec[1] = __MCF_0_INIT; - _MCF_thread* __thrd; - uint32_t __tid; - - __rec->__proc = __proc; - __rec->__arg = __arg; - - __thrd = _MCF_thread_new(__MCF_gthr_thread_thunk_v2, __rec, sizeof(*__rec)); + uint32_t __tid = 0; + _MCF_thread* __thrd = __MCF_gthr_thread_create_v3(__proc, __arg); if(!__thrd) return __MCF_nullptr; __tid = __thrd->__tid; _MCF_thread_drop_ref_nonnull(__thrd); + return (objc_thread_t)(uintptr_t) __tid; } diff --git a/mcfgthread/libcxx.h b/mcfgthread/libcxx.h index 474ba13ee9..b278a2150d 100644 --- a/mcfgthread/libcxx.h +++ b/mcfgthread/libcxx.h @@ -554,37 +554,15 @@ __MCF_LIBCXX_INLINE int __MCF_libcxx_thread_create(__libcpp_thread_t* __thrdp, __MCF_gthr_thread_procedure* __proc, void* __arg) __MCF_noexcept { - __MCF_gthr_thread_record __rec[1] = __MCF_0_INIT; - _MCF_thread* __thrd; - - __rec->__proc = __proc; - __rec->__arg = __arg; - __rec->__joinable[0] = 1; - - __thrd = _MCF_thread_new(__MCF_gthr_thread_thunk_v2, __rec, sizeof(*__rec)); - *__thrdp = __thrd; - return (__thrd == __MCF_nullptr) ? EAGAIN : 0; /* as specified by POSIX */ + *__thrdp = __MCF_gthr_thread_create_v3(__proc, __arg); + return (*__thrdp == __MCF_nullptr) ? EAGAIN : 0; } __MCF_LIBCXX_INLINE int __MCF_libcxx_thread_join(const __libcpp_thread_t* __thrdp) __MCF_noexcept { - __MCF_gthr_thread_record* __rec = __MCF_nullptr; - _MCF_thread* __thrd = *__thrdp; - if(__thrd->__proc == __MCF_gthr_thread_thunk_v2) - __rec = (__MCF_gthr_thread_record*) _MCF_thread_get_data(__thrd); - - if(__thrd->__tid == _MCF_thread_self_tid()) - return EDEADLK; - - /* Clear the joinable state. If the thread is not joinable, fail. */ - if(__rec && (_MCF_atomic_xchg_8_rlx(__rec->__joinable, 0) == 0)) - return EINVAL; - - /* Wait for the thread to terminate. */ - _MCF_thread_wait(__thrd, __MCF_nullptr); - _MCF_thread_drop_ref(__thrd); + __MCF_gthr_thread_join_v3(*__thrdp, __MCF_nullptr); return 0; } @@ -592,17 +570,7 @@ __MCF_LIBCXX_INLINE int __MCF_libcxx_thread_detach(const __libcpp_thread_t* __thrdp) __MCF_noexcept { - __MCF_gthr_thread_record* __rec = __MCF_nullptr; - _MCF_thread* __thrd = *__thrdp; - if(__thrd->__proc == __MCF_gthr_thread_thunk_v2) - __rec = (__MCF_gthr_thread_record*) _MCF_thread_get_data(__thrd); - - /* Clear the joinable state. If the thread is not joinable, fail. */ - if(__rec && (_MCF_atomic_xchg_8_rlx(__rec->__joinable, 0) == 0)) - return EINVAL; - - /* Free the thread. */ - _MCF_thread_drop_ref(__thrd); + _MCF_thread_drop_ref(*__thrdp); return 0; } diff --git a/mcfgthread/xglobals.h b/mcfgthread/xglobals.h index 926c59809c..273c14b5c3 100644 --- a/mcfgthread/xglobals.h +++ b/mcfgthread/xglobals.h @@ -58,6 +58,12 @@ NTSYSAPI SIZE_T NTAPI RtlCompareMemory(const void* src, const void* cmp, SIZE_T NTSYSAPI ULONG NTAPI RtlNtStatusToDosError(NTSTATUS status); NTSYSAPI ULONG NTAPI RtlNtStatusToDosErrorNoTeb(NTSTATUS status) __MCF_FN_CONST; +/* Initialize a GUID in the canonical form. */ +#define __MCF_GUID(a8,b4,c4,d4,e12) \ + ((GUID) { 0x##a8, 0x##b4, 0x##c4, { (0x##d4 >> 8) & 0xFF, 0x##d4 & 0xFF, \ + (0x##e12 >> 40) & 0xFF, (0x##e12 >> 32) & 0xFF, (0x##e12 >> 24) & 0xFF, \ + (0x##e12 >> 16) & 0xFF, (0x##e12 >> 8) & 0xFF, 0x##e12 & 0xFF } }) + /* Allocate a variable in a specific section. */ #define __MCF__CRT_ALLOC(x) __attribute__((__section__(x), __used__))