Improve multithreading

This commit is contained in:
Justine Tunney 2024-07-21 06:41:30 -07:00
parent d3167126aa
commit 30afd6ddbb
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
38 changed files with 752 additions and 174 deletions

View file

@ -55,29 +55,38 @@ static const char *DescribeReturnValue(char buf[30], int err, void **value) {
*
* @return 0 on success, or errno on error
* @raise ECANCELED if calling thread was cancelled in masked mode
* @raise EDEADLK if `ctid` refers calling thread's own ctid futex
* @raise EBUSY if `abstime` was specified and deadline expired
* @cancelationpoint
*/
static errno_t _pthread_wait(atomic_int *ctid, struct timespec *abstime) {
int x, e, rc = 0;
unassert(ctid != &__get_tls()->tib_tid);
// "If the thread calling pthread_join() is canceled, then the target
// thread shall not be detached." ──Quoth POSIX.1-2017
if (!(rc = pthread_testcancel_np())) {
BEGIN_CANCELATION_POINT;
while ((x = atomic_load_explicit(ctid, memory_order_acquire))) {
e = nsync_futex_wait_(ctid, x, !IsWindows() && !IsXnu(), abstime);
if (e == -ECANCELED) {
rc = ECANCELED;
break;
} else if (e == -ETIMEDOUT) {
rc = EBUSY;
break;
int x, e;
errno_t err = 0;
if (ctid == &__get_tls()->tib_tid) {
// "If an implementation detects that the value specified by the
// thread argument to pthread_join() refers to the calling thread,
// it is recommended that the function should fail and report an
// [EDEADLK] error." ──Quoth POSIX.1-2017
err = EDEADLK;
} else {
// "If the thread calling pthread_join() is canceled, then the target
// thread shall not be detached." ──Quoth POSIX.1-2017
if (!(err = pthread_testcancel_np())) {
BEGIN_CANCELATION_POINT;
while ((x = atomic_load_explicit(ctid, memory_order_acquire))) {
e = nsync_futex_wait_(ctid, x, !IsWindows() && !IsXnu(), abstime);
if (e == -ECANCELED) {
err = ECANCELED;
break;
} else if (e == -ETIMEDOUT) {
err = EBUSY;
break;
}
}
END_CANCELATION_POINT;
}
END_CANCELATION_POINT;
}
return rc;
return err;
}
/**
@ -97,6 +106,7 @@ static errno_t _pthread_wait(atomic_int *ctid, struct timespec *abstime) {
* when we'll stop waiting; if this is null we will wait forever
* @return 0 on success, or errno on error
* @raise ECANCELED if calling thread was cancelled in masked mode
* @raise EDEADLK if `thread` refers to calling thread
* @raise EBUSY if `abstime` deadline elapsed
* @cancelationpoint
* @returnserrno
@ -104,26 +114,29 @@ static errno_t _pthread_wait(atomic_int *ctid, struct timespec *abstime) {
errno_t pthread_timedjoin_np(pthread_t thread, void **value_ptr,
struct timespec *abstime) {
int tid;
errno_t err;
errno_t err = 0;
struct PosixThread *pt;
enum PosixThreadStatus status;
pt = (struct PosixThread *)thread;
tid = _pthread_tid(pt);
unassert(_pthread_tid(pt));
status = atomic_load_explicit(&pt->pt_status, memory_order_acquire);
// "The behavior is undefined if the value specified by the thread
// argument to pthread_join() does not refer to a joinable thread."
// ──Quoth POSIX.1-2017
unassert((tid = _pthread_tid(pt)));
status = atomic_load_explicit(&pt->pt_status, memory_order_acquire);
unassert(status == kPosixThreadJoinable || status == kPosixThreadTerminated);
// "The results of multiple simultaneous calls to pthread_join()
// specifying the same target thread are undefined."
// ──Quoth POSIX.1-2017
if (!(err = _pthread_wait(&pt->tib->tib_tid, abstime))) {
_pthread_lock();
dll_remove(&_pthread_list, &pt->list);
_pthread_unlock();
if (value_ptr) {
atomic_store_explicit(&pt->pt_status, kPosixThreadZombie,
memory_order_release);
_pthread_zombify(pt);
if (value_ptr)
*value_ptr = pt->pt_rc;
}
_pthread_unref(pt);
}
STRACE("pthread_timedjoin_np(%d, %s, %s) → %s", tid,
DescribeReturnValue(alloca(30), err, value_ptr),
DescribeTimespec(err ? -1 : 0, abstime), DescribeErrno(err));