Skip to content

Commit

Permalink
c11,gthr,libcxx: Allow foreign threads to be joined
Browse files Browse the repository at this point in the history
  • Loading branch information
lhmouse committed Nov 13, 2024
1 parent b3ad9ae commit 03a81e2
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 94 deletions.
55 changes: 18 additions & 37 deletions mcfgthread/c11.h
Original file line number Diff line number Diff line change
Expand Up @@ -533,17 +533,12 @@ __MCF_C11_INLINE
int
__MCF_c11_thrd_detach(thrd_t __thrd) __MCF_noexcept
{
__MCF_c11_thread_record* __rec;
__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);

/* As there is no type information, we examine the thread procedure to
* ensure we don't mistake a thread of a wrong type. */
if(__thrd->__proc != __MCF_c11_thread_thunk_v2)
return thrd_error;

__rec = (__MCF_c11_thread_record*) _MCF_thread_get_data(__thrd);

/* Fail if the thread has already been detached. */
if(_MCF_atomic_xchg_8_rlx(__rec->__joinable, 0) == 0)
/* 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. */
Expand All @@ -563,50 +558,36 @@ void
__MCF_c11_thrd_exit(int __result) __MCF_noexcept
{
_MCF_thread* __self = _MCF_thread_self();
__MCF_c11_thread_record* __rec;

/* As there is no type information, we examine the thread procedure to
* ensure we don't mistake a thread of a wrong type. The current thread
* shall terminate even if it is foreign. */
if(__self->__proc != __MCF_c11_thread_thunk_v2)
_MCF_thread_exit();
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. */
__rec = (__MCF_c11_thread_record*) _MCF_thread_get_data(__self);
__rec->__result = __result;
__MCF_SET_IF(__resp, __result);
_MCF_thread_exit();
}

__MCF_C11_INLINE
int
__MCF_c11_thrd_join(thrd_t __thrd, int* __resp_opt) __MCF_noexcept
{
__MCF_c11_thread_record* __rec;
int __err;

/* As there is no type information, we examine the thread procedure to
* ensure we don't mistake a thread of a wrong type. */
if(__thrd->__proc != __MCF_c11_thread_thunk_v2)
return thrd_error;
__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);

__rec = (__MCF_c11_thread_record*) _MCF_thread_get_data(__thrd);

/* Joining with the calling thread itself would result in deadlocks. */
if(__thrd->__tid == _MCF_thread_self_tid())
return thrd_error;

/* Fail if the thread has already been detached. */
if(_MCF_atomic_xchg_8_rlx(__rec->__joinable, 0) == 0)
/* 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;

__err = _MCF_thread_wait(__thrd, __MCF_nullptr);
__MCF_ASSERT(__err == 0);
__MCF_SET_IF(__resp_opt, __rec->__result);

/* Free the thread. */
/* 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 thrd_success;
return 0;
}

__MCF_C11_INLINE
Expand Down
46 changes: 16 additions & 30 deletions mcfgthread/gthr.h
Original file line number Diff line number Diff line change
Expand Up @@ -611,29 +611,20 @@ __MCF_GTHR_INLINE
int
__MCF_gthr_join_v2(__gthread_t __thrd, void** __resp_opt) __MCF_noexcept
{
__MCF_gthr_thread_record* __rec;
int __err;
__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);

/* As there is no type information, we examine the thread procedure to
* ensure we don't mistake a thread of a wrong type. */
if(__thrd->__proc != __MCF_gthr_thread_thunk_v2)
return -1;

__rec = (__MCF_gthr_thread_record*) _MCF_thread_get_data(__thrd);

/* Joining with the calling thread itself would result in deadlocks. */
if(__thrd->__tid == _MCF_thread_self_tid())
return -2;
return EDEADLK;

/* Fail if the thread has already been detached. */
if(_MCF_atomic_xchg_8_rlx(__rec->__joinable, 0) == 0)
return -3;

__err = _MCF_thread_wait(__thrd, __MCF_nullptr);
__MCF_ASSERT(__err == 0);
__MCF_SET_IF(__resp_opt, __rec->__result);
/* 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. */
/* 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);
return 0;
}
Expand All @@ -642,18 +633,13 @@ __MCF_GTHR_INLINE
int
__MCF_gthr_detach_v2(__gthread_t __thrd) __MCF_noexcept
{
__MCF_gthr_thread_record* __rec;

/* As there is no type information, we examine the thread procedure to
* ensure we don't mistake a thread of a wrong type. */
if(__thrd->__proc != __MCF_gthr_thread_thunk_v2)
return -1;

__rec = (__MCF_gthr_thread_record*) _MCF_thread_get_data(__thrd);
__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);

/* Fail if the thread has already been detached. */
if(_MCF_atomic_xchg_8_rlx(__rec->__joinable, 0) == 0)
return -3;
/* 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);
Expand Down
38 changes: 12 additions & 26 deletions mcfgthread/libcxx.h
Original file line number Diff line number Diff line change
Expand Up @@ -575,29 +575,20 @@ __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;
__MCF_gthr_thread_record* __rec;
int __err;
if(__thrd->__proc == __MCF_gthr_thread_thunk_v2)
__rec = (__MCF_gthr_thread_record*) _MCF_thread_get_data(__thrd);

/* As there is no type information, we examine the thread procedure to
* ensure we don't mistake a thread of a wrong type. */
if(__thrd->__proc != __MCF_gthr_thread_thunk_v2)
return EINVAL;

__rec = (__MCF_gthr_thread_record*) _MCF_thread_get_data(__thrd);

/* Joining with the calling thread itself would result in deadlocks. */
if(__thrd->__tid == _MCF_thread_self_tid())
return EDEADLK;

/* Fail if the thread has already been detached. */
if(_MCF_atomic_xchg_8_rlx(__rec->__joinable, 0) == 0)
/* Clear the joinable state. If the thread is not joinable, fail. */
if(__rec && (_MCF_atomic_xchg_8_rlx(__rec->__joinable, 0) == 0))
return EINVAL;

__err = _MCF_thread_wait(__thrd, __MCF_nullptr);
__MCF_ASSERT(__err == 0);

/* Free the thread. */
/* Wait for the thread to terminate. */
_MCF_thread_wait(__thrd, __MCF_nullptr);
_MCF_thread_drop_ref(__thrd);
return 0;
}
Expand All @@ -606,18 +597,13 @@ __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;
__MCF_gthr_thread_record* __rec;

/* As there is no type information, we examine the thread procedure to
* ensure we don't mistake a thread of a wrong type. */
if(__thrd->__proc != __MCF_gthr_thread_thunk_v2)
return EINVAL;

__rec = (__MCF_gthr_thread_record*) _MCF_thread_get_data(__thrd);
if(__thrd->__proc == __MCF_gthr_thread_thunk_v2)
__rec = (__MCF_gthr_thread_record*) _MCF_thread_get_data(__thrd);

/* Fail if the thread has already been detached. */
if(_MCF_atomic_xchg_8_rlx(__rec->__joinable, 0) == 0)
/* 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. */
Expand Down
2 changes: 1 addition & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ test_src = [
'test/c11_cnd_timeout.c', 'test/c11_cnd_consumers.c',
'test/c11_cnd_consumers_recursive.c', 'test/c11_tss_dtor.c', 'test/c11_tss_set.c',
'test/c11_tss_deleted_key.c', 'test/c11_tss_many.c', 'test/c11_thrd_return.c',
'test/c11_thrd_equal.c', 'test/c11_thrd_sleep.c',
'test/c11_thrd_equal.c', 'test/c11_thrd_sleep.c', 'test/c11_thrd_join_main.c',
'test/c11__thrd_sleep_until.c', 'test/atexit_thread_self.c', 'test/atexit_order.c',
'test/atexit_ignored_on_quick_exit.c', 'test/atexit_ignored_on__Exit.c',
'test/at_quick_exit_order.c', 'test/at_quick_exit_ignored_on_exit.c',
Expand Down
45 changes: 45 additions & 0 deletions test/c11_thrd_join_main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/* This file is part of MCF Gthread.
* Copyright (C) 2022-2024 LH_Mouse. All wrongs reserved.
*
* MCF Gthread is free software. Licensing information is included in
* LICENSE.TXT as a whole. The GCC Runtime Library Exception applies
* to this file. */

#include "../mcfgthread/c11.h"
#include "../mcfgthread/exit.h"
#include <assert.h>
#include <stdio.h>

static
int
test_thrd_func(void* p)
{
thrd_sleep(&(struct timespec) { .tv_sec = 2 }, __MCF_nullptr);
thrd_t mthr = p;
fprintf(stderr, "got main thread = %p, ref = %d\n", (void*) mthr, _MCF_thread_get_ref(mthr));

int code;
int err = thrd_join(mthr, &code);
assert(err == 0);
fprintf(stderr, "main thread joined: code = %d\n", code);
// zero; main thread is foreign.
assert(code == 0);
__MCF__Exit(0);
}

int
main(void)
{
thrd_t mthr = thrd_current();
assert(mthr);
fprintf(stderr, "main thread = %p, ref = %d\n", (void*) mthr, _MCF_thread_get_ref(mthr));

thrd_t cthr;
int err = thrd_create(&cthr, test_thrd_func, mthr);
assert(err == 0);
fprintf(stderr, "new thread = %p\n", (void*) cthr);

thrd_sleep(&(struct timespec) { .tv_sec = 1 }, __MCF_nullptr);
fprintf(stderr, "main thread exiting\n");
thrd_exit(42);
}

0 comments on commit 03a81e2

Please sign in to comment.