mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-25 03:50:29 +00:00
Make detached threads work better
This change adds a double linked list of threads, so that pthread_exit() will know when it should call exit() from an orphaned child. This change also improves ftrace and strace logging.
This commit is contained in:
parent
b74d8c1acd
commit
cee6871710
37 changed files with 638 additions and 314 deletions
|
@ -953,7 +953,7 @@ static void *__asan_morgue_add(void *p) {
|
|||
p, memory_order_acq_rel);
|
||||
}
|
||||
|
||||
static void __asan_morgue_flush(void) {
|
||||
__attribute__((__destructor__)) static void __asan_morgue_flush(void) {
|
||||
unsigned i;
|
||||
for (i = 0; i < ARRAYLEN(__asan_morgue.p); ++i) {
|
||||
if (atomic_load_explicit(__asan_morgue.p + i, memory_order_acquire)) {
|
||||
|
@ -1461,8 +1461,8 @@ static textstartup void __asan_shadow_existing_mappings(void) {
|
|||
__asan_poison((void *)GetStackAddr(), PAGESIZE, kAsanStackOverflow);
|
||||
}
|
||||
|
||||
textstartup void __asan_init(int argc, char **argv, char **envp,
|
||||
intptr_t *auxv) {
|
||||
__attribute__((__constructor__)) void __asan_init(int argc, char **argv,
|
||||
char **envp, intptr_t *auxv) {
|
||||
static bool once;
|
||||
if (!_cmpxchg(&once, false, true)) return;
|
||||
if (IsWindows() && NtGetVersion() < kNtVersionWindows10) {
|
||||
|
@ -1497,13 +1497,3 @@ textstartup void __asan_init(int argc, char **argv, char **envp,
|
|||
STRACE("/_/ \\_\\____/_/ \\_\\_| \\_|");
|
||||
STRACE("cosmopolitan memory safety module initialized");
|
||||
}
|
||||
|
||||
static textstartup void __asan_ctor(void) {
|
||||
if (_weaken(__cxa_atexit)) {
|
||||
_weaken(__cxa_atexit)(__asan_morgue_flush, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
const void *const g_asan_ctor[] initarray = {
|
||||
__asan_ctor,
|
||||
};
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asmflag.h"
|
||||
#include "libc/intrin/promises.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/nt/thread.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
|
@ -47,7 +45,6 @@ __msabi extern typeof(ExitThread) *const __imp_ExitThread;
|
|||
privileged wontreturn void _Exit1(int rc) {
|
||||
char cf;
|
||||
int ax, dx, di, si;
|
||||
STRACE("_Exit1(%d)", rc);
|
||||
if (!IsWindows() && !IsMetal()) {
|
||||
// exit() on Linux
|
||||
// thr_exit() on FreeBSD
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/extend.internal.h"
|
||||
#include "libc/intrin/pushpop.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
|
@ -38,7 +39,7 @@ static textwindows dontinline void SetupWinStd(struct Fds *fds, int i, int x) {
|
|||
if (!h || h == -1) return;
|
||||
fds->p[i].kind = pushpop(kFdFile);
|
||||
fds->p[i].handle = h;
|
||||
fds->f = i + 1;
|
||||
atomic_store_explicit(&fds->f, i + 1, memory_order_relaxed);
|
||||
}
|
||||
|
||||
textstartup void InitializeFileDescriptors(void) {
|
||||
|
@ -49,7 +50,7 @@ textstartup void InitializeFileDescriptors(void) {
|
|||
fds = VEIL("r", &g_fds);
|
||||
fds->p = fds->e = (void *)kMemtrackFdsStart;
|
||||
fds->n = 4;
|
||||
fds->f = 3;
|
||||
atomic_store_explicit(&fds->f, 3, memory_order_relaxed);
|
||||
fds->e = _extend(fds->p, fds->n * sizeof(*fds->p), fds->e, MAP_PRIVATE,
|
||||
kMemtrackFdsStart + kMemtrackFdsSize);
|
||||
if (IsMetal()) {
|
||||
|
|
|
@ -16,16 +16,26 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
/**
|
||||
* Gets value of TLS slot for current thread.
|
||||
*
|
||||
* If `k` wasn't created by pthread_key_create() then the behavior is
|
||||
* undefined. If `k` was unregistered earlier by pthread_key_delete()
|
||||
* then the behavior is undefined.
|
||||
*/
|
||||
void *pthread_getspecific(pthread_key_t key) {
|
||||
if (0 <= key && key < PTHREAD_KEYS_MAX) {
|
||||
return __get_tls()->tib_keys[key];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
void *pthread_getspecific(pthread_key_t k) {
|
||||
// "The effect of calling pthread_getspecific() or
|
||||
// pthread_setspecific() with a key value not obtained from
|
||||
// pthread_key_create() or after key has been deleted with
|
||||
// pthread_key_delete() is undefined."
|
||||
// ──Quoth POSIX.1-2017
|
||||
_unassert(0 <= k && k < PTHREAD_KEYS_MAX);
|
||||
_unassert(atomic_load_explicit(_pthread_key_dtor + k, memory_order_acquire));
|
||||
return __get_tls()->tib_keys[k];
|
||||
}
|
||||
|
|
|
@ -18,18 +18,24 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
/**
|
||||
* Allocates TLS slot.
|
||||
*
|
||||
* If `dtor` is non-null, then it'll be called upon thread exit when the
|
||||
* key's value is nonzero. The key's value is set to zero before it gets
|
||||
* called. The ordering for multiple destructor calls is unspecified.
|
||||
* This function creates a thread-local storage registration, that will
|
||||
* apply to all threads. The new identifier is written to `key`, and it
|
||||
* can be passed to the pthread_setspecific() and pthread_getspecific()
|
||||
* functions to set and get its associated value. Each thread will have
|
||||
* its key value initialized to zero upon creation. It is also possible
|
||||
* to use pthread_key_delete() to unregister a key.
|
||||
*
|
||||
* The result should be passed to pthread_key_delete() later.
|
||||
* If `dtor` is non-null, then it'll be called upon pthread_exit() when
|
||||
* the key's value is nonzero. The key's value is set to zero before it
|
||||
* is called. The ordering of multiple destructor calls is unspecified.
|
||||
* The same key can be destroyed `PTHREAD_DESTRUCTOR_ITERATIONS` times,
|
||||
* in cases where it gets set again by a destructor.
|
||||
*
|
||||
* @param key is set to the allocated key on success
|
||||
* @param dtor specifies an optional destructor callback
|
||||
|
@ -42,9 +48,9 @@ int pthread_key_create(pthread_key_t *key, pthread_key_dtor dtor) {
|
|||
if (!dtor) dtor = (pthread_key_dtor)-1;
|
||||
for (i = 0; i < PTHREAD_KEYS_MAX; ++i) {
|
||||
if (!(expect = atomic_load_explicit(_pthread_key_dtor + i,
|
||||
memory_order_relaxed)) &&
|
||||
memory_order_acquire)) &&
|
||||
atomic_compare_exchange_strong_explicit(_pthread_key_dtor + i, &expect,
|
||||
dtor, memory_order_relaxed,
|
||||
dtor, memory_order_release,
|
||||
memory_order_relaxed)) {
|
||||
*key = i;
|
||||
return 0;
|
||||
|
@ -52,7 +58,3 @@ int pthread_key_create(pthread_key_t *key, pthread_key_dtor dtor) {
|
|||
}
|
||||
return EAGAIN;
|
||||
}
|
||||
|
||||
__attribute__((__constructor__)) static textstartup void _pthread_key_init() {
|
||||
atexit(_pthread_key_destruct);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
|
@ -24,16 +25,18 @@
|
|||
/**
|
||||
* Deletes TLS slot.
|
||||
*
|
||||
* This function should only be called if all threads have finished
|
||||
* using the key registration. If a key is used after being deleted
|
||||
* then the behavior is undefined. If `k` was not registered by the
|
||||
* pthread_key_create() function then the behavior is undefined.
|
||||
*
|
||||
* @param key was created by pthread_key_create()
|
||||
* @return 0 on success, or errno on error
|
||||
* @raise EINVAL if `key` isn't valid
|
||||
*/
|
||||
int pthread_key_delete(pthread_key_t key) {
|
||||
int pthread_key_delete(pthread_key_t k) {
|
||||
uint64_t mask;
|
||||
if (key < PTHREAD_KEYS_MAX) {
|
||||
atomic_store_explicit(_pthread_key_dtor + key, 0, memory_order_relaxed);
|
||||
return 0;
|
||||
} else {
|
||||
return EINVAL;
|
||||
}
|
||||
_unassert(0 <= k && k < PTHREAD_KEYS_MAX);
|
||||
_unassert(atomic_load_explicit(_pthread_key_dtor + k, memory_order_acquire));
|
||||
atomic_store_explicit(_pthread_key_dtor + k, 0, memory_order_release);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -16,18 +16,27 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/errno.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
/**
|
||||
* Sets value of TLS slot for current thread.
|
||||
*
|
||||
* If `k` wasn't created by pthread_key_create() then the behavior is
|
||||
* undefined. If `k` was unregistered earlier by pthread_key_delete()
|
||||
* then the behavior is undefined.
|
||||
*/
|
||||
int pthread_setspecific(pthread_key_t key, const void *val) {
|
||||
if (0 <= key && key < PTHREAD_KEYS_MAX) {
|
||||
__get_tls()->tib_keys[key] = val;
|
||||
return 0;
|
||||
} else {
|
||||
return EINVAL;
|
||||
}
|
||||
int pthread_setspecific(pthread_key_t k, const void *val) {
|
||||
// "The effect of calling pthread_getspecific() or
|
||||
// pthread_setspecific() with a key value not obtained from
|
||||
// pthread_key_create() or after key has been deleted with
|
||||
// pthread_key_delete() is undefined."
|
||||
// ──Quoth POSIX.1-2017
|
||||
_unassert(0 <= k && k < PTHREAD_KEYS_MAX);
|
||||
_unassert(atomic_load_explicit(_pthread_key_dtor + k, memory_order_acquire));
|
||||
__get_tls()->tib_keys[k] = val;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -17,29 +17,18 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
void _pthread_key_destruct(void) {
|
||||
int i, j, gotsome;
|
||||
void *val, **keys;
|
||||
pthread_key_dtor dtor;
|
||||
if (!__tls_enabled) return;
|
||||
keys = __get_tls()->tib_keys;
|
||||
for (j = 0; j < PTHREAD_DESTRUCTOR_ITERATIONS; ++j) {
|
||||
for (gotsome = i = 0; i < PTHREAD_KEYS_MAX; ++i) {
|
||||
if ((val = keys[i]) &&
|
||||
(dtor = atomic_load_explicit(_pthread_key_dtor + i,
|
||||
memory_order_relaxed)) &&
|
||||
dtor != (pthread_key_dtor)-1) {
|
||||
gotsome = 1;
|
||||
keys[i] = 0;
|
||||
dtor(val);
|
||||
}
|
||||
}
|
||||
if (!gotsome) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef pthread_spin_destroy
|
||||
#undef pthread_spin_destroy
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Destroys spin lock.
|
||||
*
|
||||
* @return 0 on success, or errno on error
|
||||
*/
|
||||
errno_t pthread_spin_destroy(pthread_spinlock_t *spin) {
|
||||
atomic_store_explicit(&spin->_lock, -1, memory_order_relaxed);
|
||||
return 0;
|
||||
}
|
38
libc/intrin/pthread_spin_init.c
Normal file
38
libc/intrin/pthread_spin_init.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
#ifdef pthread_spin_init
|
||||
#undef pthread_spin_init
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initializes spin lock.
|
||||
*
|
||||
* @param pshared is ignored, since this implementation always permits
|
||||
* multiple processes to operate on the same spin locks
|
||||
* @return 0 on success, or errno on error
|
||||
* @see pthread_spin_destroy
|
||||
* @see pthread_spin_lock
|
||||
*/
|
||||
errno_t pthread_spin_init(pthread_spinlock_t *spin, int pshared) {
|
||||
atomic_store_explicit(&spin->_lock, 0, memory_order_relaxed);
|
||||
return 0;
|
||||
}
|
53
libc/intrin/pthread_spin_lock.c
Normal file
53
libc/intrin/pthread_spin_lock.c
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
#ifdef pthread_spin_lock
|
||||
#undef pthread_spin_lock
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Acquires spin lock, e.g.
|
||||
*
|
||||
* pthread_spinlock_t lock;
|
||||
* pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE);
|
||||
* pthread_spin_lock(&lock);
|
||||
* // do work...
|
||||
* pthread_spin_unlock(&lock);
|
||||
* pthread_spin_destroy(&lock);
|
||||
*
|
||||
* This function has undefined behavior when `spin` wasn't intialized,
|
||||
* was destroyed, or if the lock's already held by the calling thread.
|
||||
*
|
||||
* @return 0 on success, or errno on error
|
||||
* @see pthread_spin_trylock
|
||||
* @see pthread_spin_unlock
|
||||
* @see pthread_spin_init
|
||||
*/
|
||||
errno_t pthread_spin_lock(pthread_spinlock_t *spin) {
|
||||
int x;
|
||||
for (;;) {
|
||||
x = atomic_exchange_explicit(&spin->_lock, 1, memory_order_acquire);
|
||||
if (!x) break;
|
||||
_unassert(x == 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
43
libc/intrin/pthread_spin_trylock.c
Normal file
43
libc/intrin/pthread_spin_trylock.c
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
#ifdef pthread_spin_trylock
|
||||
#undef pthread_spin_trylock
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Acquires spin lock if available.
|
||||
*
|
||||
* This function has undefined behavior when `spin` wasn't intialized,
|
||||
* was destroyed, or if the lock's already held by the calling thread.
|
||||
*
|
||||
* @return 0 on success, or errno on error
|
||||
* @raise EBUSY if lock is already held
|
||||
*/
|
||||
errno_t pthread_spin_trylock(pthread_spinlock_t *spin) {
|
||||
int x;
|
||||
x = atomic_exchange_explicit(&spin->_lock, 1, memory_order_acquire);
|
||||
if (!x) return 0;
|
||||
_unassert(x == 1);
|
||||
return EBUSY;
|
||||
}
|
38
libc/intrin/pthread_spin_unlock.c
Normal file
38
libc/intrin/pthread_spin_unlock.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
#ifdef pthread_spin_unlock
|
||||
#undef pthread_spin_unlock
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Releases spin lock.
|
||||
*
|
||||
* Calling this function when the lock isn't held by the calling thread
|
||||
* has undefined behavior.
|
||||
*
|
||||
* @return 0 on success, or errno on error
|
||||
* @see pthread_spin_lock
|
||||
*/
|
||||
errno_t pthread_spin_unlock(pthread_spinlock_t *spin) {
|
||||
atomic_store_explicit(&spin->_lock, 0, memory_order_release);
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue