mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-01 08:48:29 +00:00
Add pthread attributes and other libc functions
This commit is contained in:
parent
d5c9308a43
commit
4339d9f15e
81 changed files with 1111 additions and 428 deletions
|
@ -4,10 +4,8 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int _futex_wait_public(void *, int, struct timespec *) hidden;
|
||||
int _futex_wait_private(void *, int, struct timespec *) hidden;
|
||||
int _futex_wake_public(void *, int) hidden;
|
||||
int _futex_wake_private(void *, int) hidden;
|
||||
int _futex_wait(void *, int, char, struct timespec *) hidden;
|
||||
int _futex_wake(void *, int, char) hidden;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -28,13 +28,14 @@
|
|||
|
||||
int _futex(void *, int, int, struct timespec *) hidden;
|
||||
|
||||
static dontinline int _futex_wait_impl(void *addr, int expect,
|
||||
struct timespec *timeout, int private) {
|
||||
int op, ax;
|
||||
int _futex_wait(void *addr, int expect, char pshared,
|
||||
struct timespec *timeout) {
|
||||
int op, ax, pf;
|
||||
if (IsLinux() || IsOpenbsd()) {
|
||||
op = FUTEX_WAIT | private;
|
||||
pf = pshared == PTHREAD_PROCESS_PRIVATE ? FUTEX_PRIVATE_FLAG : 0;
|
||||
op = FUTEX_WAIT | pf;
|
||||
ax = _futex(addr, op, expect, timeout);
|
||||
if (SupportsLinux() && private && ax == -ENOSYS) {
|
||||
if (SupportsLinux() && pf && ax == -ENOSYS) {
|
||||
// RHEL5 doesn't support FUTEX_PRIVATE_FLAG
|
||||
op = FUTEX_WAIT;
|
||||
ax = _futex(addr, op, expect, timeout);
|
||||
|
@ -47,11 +48,3 @@ static dontinline int _futex_wait_impl(void *addr, int expect,
|
|||
return pthread_yield();
|
||||
}
|
||||
}
|
||||
|
||||
int _futex_wait_public(void *addr, int expect, struct timespec *timeout) {
|
||||
return _futex_wait_impl(addr, expect, timeout, 0);
|
||||
}
|
||||
|
||||
int _futex_wait_private(void *addr, int expect, struct timespec *timeout) {
|
||||
return _futex_wait_impl(addr, expect, timeout, FUTEX_PRIVATE_FLAG);
|
||||
}
|
||||
|
|
|
@ -21,16 +21,18 @@
|
|||
#include "libc/errno.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/futex.internal.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/sysv/consts/futex.h"
|
||||
|
||||
int _futex(void *, int, int) hidden;
|
||||
|
||||
static dontinline int _futex_wake_impl(void *addr, int count, int private) {
|
||||
int op, ax;
|
||||
int _futex_wake(void *addr, int count, char pshared) {
|
||||
int op, ax, pf;
|
||||
if (IsLinux() || IsOpenbsd()) {
|
||||
op = FUTEX_WAKE | private;
|
||||
pf = pshared == PTHREAD_PROCESS_PRIVATE ? FUTEX_PRIVATE_FLAG : 0;
|
||||
op = FUTEX_WAKE | pf;
|
||||
ax = _futex(addr, op, count);
|
||||
if (SupportsLinux() && private && ax == -ENOSYS) {
|
||||
if (SupportsLinux() && pf && ax == -ENOSYS) {
|
||||
// RHEL5 doesn't support FUTEX_PRIVATE_FLAG
|
||||
op = FUTEX_WAKE;
|
||||
ax = _futex(addr, op, count);
|
||||
|
@ -42,11 +44,3 @@ static dontinline int _futex_wake_impl(void *addr, int count, int private) {
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int _futex_wake_public(void *addr, int count) {
|
||||
return _futex_wake_impl(addr, count, 0);
|
||||
}
|
||||
|
||||
int _futex_wake_private(void *addr, int count) {
|
||||
return _futex_wake_impl(addr, count, FUTEX_PRIVATE_FLAG);
|
||||
}
|
||||
|
|
|
@ -31,12 +31,10 @@ struct Fds g_fds;
|
|||
static pthread_mutex_t __fds_lock_obj;
|
||||
|
||||
void(__fds_lock)(void) {
|
||||
__fds_lock_obj.attr = PTHREAD_MUTEX_RECURSIVE;
|
||||
pthread_mutex_lock(&__fds_lock_obj);
|
||||
}
|
||||
|
||||
void(__fds_unlock)(void) {
|
||||
__fds_lock_obj.attr = PTHREAD_MUTEX_RECURSIVE;
|
||||
pthread_mutex_unlock(&__fds_lock_obj);
|
||||
}
|
||||
|
||||
|
@ -51,6 +49,7 @@ static textwindows dontinline void SetupWinStd(struct Fds *fds, int i, int x) {
|
|||
|
||||
textstartup void InitializeFileDescriptors(void) {
|
||||
struct Fds *fds;
|
||||
__fds_lock_obj.type = PTHREAD_MUTEX_RECURSIVE;
|
||||
fds = VEIL("r", &g_fds);
|
||||
pushmov(&fds->n, ARRAYLEN(fds->__init_p));
|
||||
fds->f = 3;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#define PTHREAD_ONCE_INIT 0
|
||||
|
||||
#define PTHREAD_KEYS_MAX 64
|
||||
#define PTHREAD_STACK_MIN 2048
|
||||
#define PTHREAD_STACK_MIN FRAMESIZE
|
||||
#define PTHREAD_DESTRUCTOR_ITERATIONS 4
|
||||
|
||||
#define PTHREAD_BARRIER_SERIAL_THREAD 31337
|
||||
|
@ -20,60 +20,70 @@
|
|||
#define PTHREAD_PROCESS_PRIVATE 0
|
||||
#define PTHREAD_PROCESS_SHARED 1
|
||||
|
||||
#define PTHREAD_CREATE_JOINABLE 0
|
||||
#define PTHREAD_CREATE_DETACHED 1
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/* clang-format off */
|
||||
#define PTHREAD_MUTEX_INITIALIZER {PTHREAD_MUTEX_DEFAULT}
|
||||
#define PTHREAD_COND_INITIALIZER {PTHREAD_PROCESS_DEFAULT}
|
||||
#define PTHREAD_BARRIER_INITIALIZER {PTHREAD_PROCESS_DEFAULT}
|
||||
#define PTHREAD_RWLOCK_INITIALIZER {PTHREAD_PROCESS_DEFAULT}
|
||||
#define PTHREAD_MUTEX_INITIALIZER {PTHREAD_MUTEX_DEFAULT, \
|
||||
PTHREAD_PROCESS_DEFAULT}
|
||||
/* clang-format on */
|
||||
|
||||
typedef void *pthread_t;
|
||||
typedef int pthread_id_np_t;
|
||||
typedef int pthread_condattr_t;
|
||||
typedef int pthread_mutexattr_t;
|
||||
typedef int pthread_rwlockattr_t;
|
||||
typedef int pthread_barrierattr_t;
|
||||
typedef char pthread_condattr_t;
|
||||
typedef char pthread_rwlockattr_t;
|
||||
typedef char pthread_barrierattr_t;
|
||||
typedef unsigned pthread_key_t;
|
||||
typedef _Atomic(char) pthread_once_t;
|
||||
typedef _Atomic(char) pthread_spinlock_t;
|
||||
typedef void (*pthread_key_dtor)(void *);
|
||||
|
||||
typedef struct {
|
||||
int attr;
|
||||
typedef struct pthread_mutex_s {
|
||||
char type;
|
||||
char pshared;
|
||||
int reent;
|
||||
_Atomic(int) lock;
|
||||
_Atomic(int) waits;
|
||||
} pthread_mutex_t;
|
||||
|
||||
typedef struct {
|
||||
int attr;
|
||||
typedef struct pthread_mutexattr_s {
|
||||
char type;
|
||||
char pshared;
|
||||
} pthread_mutexattr_t;
|
||||
|
||||
typedef struct pthread_cond_s {
|
||||
char pshared;
|
||||
_Atomic(int) waits;
|
||||
_Atomic(unsigned) seq;
|
||||
} pthread_cond_t;
|
||||
|
||||
typedef struct {
|
||||
int attr;
|
||||
typedef struct pthread_barrier_s {
|
||||
char pshared;
|
||||
int count;
|
||||
_Atomic(int) waits;
|
||||
_Atomic(int) popped;
|
||||
} pthread_barrier_t;
|
||||
|
||||
typedef struct {
|
||||
int attr;
|
||||
typedef struct pthread_rwlock_s {
|
||||
char pshared;
|
||||
_Atomic(int) lock;
|
||||
_Atomic(int) waits;
|
||||
} pthread_rwlock_t;
|
||||
|
||||
typedef struct {
|
||||
typedef struct pthread_attr_s {
|
||||
char detachstate;
|
||||
size_t stacksize;
|
||||
size_t guardsize;
|
||||
void *stackaddr;
|
||||
int scope;
|
||||
int schedpolicy;
|
||||
int detachstate;
|
||||
int inheritsched;
|
||||
size_t guardsize;
|
||||
size_t stacksize;
|
||||
} pthread_attr_t;
|
||||
|
||||
int pthread_yield(void);
|
||||
|
@ -81,6 +91,7 @@ void pthread_exit(void *) wontreturn;
|
|||
pthread_t pthread_self(void) pureconst;
|
||||
pthread_id_np_t pthread_getthreadid_np(void);
|
||||
int64_t pthread_getunique_np(pthread_t);
|
||||
int pthread_getattr_np(pthread_t, pthread_attr_t *);
|
||||
int pthread_attr_init(pthread_attr_t *);
|
||||
int pthread_attr_destroy(pthread_attr_t *);
|
||||
int pthread_attr_getdetachstate(const pthread_attr_t *, int *);
|
||||
|
@ -156,7 +167,6 @@ int pthread_barrier_init(pthread_barrier_t *, const pthread_barrierattr_t *,
|
|||
|
||||
#define pthread_spin_init(pSpin, multiprocess) (*(pSpin) = 0)
|
||||
#define pthread_spin_destroy(pSpin) (*(pSpin) = 0)
|
||||
|
||||
#if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 407
|
||||
extern const errno_t EBUSY;
|
||||
#define pthread_spin_unlock(pSpin) \
|
||||
|
@ -164,18 +174,18 @@ extern const errno_t EBUSY;
|
|||
#define pthread_spin_trylock(pSpin) \
|
||||
(__atomic_test_and_set(pSpin, __ATOMIC_SEQ_CST) ? EBUSY : 0)
|
||||
#ifdef TINY
|
||||
#define pthread_spin_lock(pSpin) __pthread_spin_lock_tiny(pSpin)
|
||||
#define pthread_spin_lock(pSpin) _pthread_spin_lock_tiny(pSpin)
|
||||
#else
|
||||
#define pthread_spin_lock(pSpin) __pthread_spin_lock_cooperative(pSpin)
|
||||
#define pthread_spin_lock(pSpin) _pthread_spin_lock_cooperative(pSpin)
|
||||
#endif
|
||||
#define __pthread_spin_lock_tiny(pSpin) \
|
||||
#define _pthread_spin_lock_tiny(pSpin) \
|
||||
({ \
|
||||
while (__atomic_test_and_set(pSpin, __ATOMIC_SEQ_CST)) { \
|
||||
__builtin_ia32_pause(); \
|
||||
} \
|
||||
0; \
|
||||
})
|
||||
#define __pthread_spin_lock_cooperative(pSpin) \
|
||||
#define _pthread_spin_lock_cooperative(pSpin) \
|
||||
({ \
|
||||
char __x; \
|
||||
volatile int __i; \
|
||||
|
@ -197,59 +207,6 @@ extern const errno_t EBUSY;
|
|||
})
|
||||
#endif /* GCC 4.7+ */
|
||||
|
||||
#define pthread_mutexattr_init(pAttr) (*(pAttr) = PTHREAD_MUTEX_DEFAULT, 0)
|
||||
#define pthread_mutexattr_destroy(pAttr) (*(pAttr) = 0)
|
||||
#define pthread_mutexattr_gettype(pAttr, pType) (*(pType) = *(pAttr), 0)
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define pthread_mutex_init(mutex, pAttr) \
|
||||
({ \
|
||||
pthread_mutexattr_t *_pAttr = (pAttr); \
|
||||
*(mutex) = (pthread_mutex_t){ \
|
||||
_pAttr ? *_pAttr : PTHREAD_MUTEX_DEFAULT, \
|
||||
}; \
|
||||
0; \
|
||||
})
|
||||
#endif
|
||||
|
||||
#define pthread_condattr_init(pAttr) (*(pAttr) = PTHREAD_PROCESS_DEFAULT, 0)
|
||||
#define pthread_condattr_destroy(pAttr) (*(pAttr) = 0)
|
||||
#define pthread_condattr_getpshared(pAttr, pPshared) (*(pPshared) = *(pAttr), 0)
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define pthread_cond_init(cond, pAttr) \
|
||||
({ \
|
||||
pthread_condattr_t *_pAttr = (pAttr); \
|
||||
*(cond) = (pthread_cond_t){ \
|
||||
_pAttr ? *_pAttr : PTHREAD_PROCESS_DEFAULT, \
|
||||
}; \
|
||||
0; \
|
||||
})
|
||||
#endif
|
||||
|
||||
#define pthread_barrierattr_init(pAttr) (*(pAttr) = PTHREAD_PROCESS_DEFAULT, 0)
|
||||
#define pthread_barrierattr_destroy(pAttr) (*(pAttr) = 0)
|
||||
#define pthread_barrierattr_getpshared(pAttr, pPshared) \
|
||||
(*(pPshared) = *(pAttr), 0)
|
||||
|
||||
#define pthread_rwlockattr_init(pAttr) (*(pAttr) = PTHREAD_PROCESS_DEFAULT, 0)
|
||||
#define pthread_rwlockattr_destroy(pAttr) (*(pAttr) = 0)
|
||||
#define pthread_rwlockattr_getpshared(pAttr, pPshared) \
|
||||
(*(pPshared) = *(pAttr), 0)
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define pthread_rwlock_init(rwlock, pAttr) \
|
||||
({ \
|
||||
pthread_rwlockattr_t *_pAttr = (pAttr); \
|
||||
*(rwlock) = (pthread_rwlock_t){ \
|
||||
_pAttr ? *_pAttr : PTHREAD_PROCESS_DEFAULT, \
|
||||
}; \
|
||||
0; \
|
||||
})
|
||||
#endif
|
||||
|
||||
int _pthread_mutex_wake(pthread_mutex_t *) hidden;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_RUNTIME_PTHREAD_H_ */
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "libc/calls/struct/sched_param.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
|
|
|
@ -23,6 +23,6 @@
|
|||
* Destroys pthread attributes.
|
||||
*/
|
||||
int pthread_attr_destroy(pthread_attr_t *attr) {
|
||||
bzero(attr, sizeof(*attr));
|
||||
memset(attr, -1, sizeof(*attr));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,15 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/pthread.h"
|
||||
|
||||
int pthread_attr_getdetachstate(const pthread_attr_t *a, int *x) {
|
||||
*x = a->detachstate;
|
||||
/**
|
||||
* Gets thread detachable attribute.
|
||||
*
|
||||
* @param detachstate is set to one of the following
|
||||
* - `PTHREAD_CREATE_JOINABLE` (default)
|
||||
* - `PTHREAD_CREATE_DETACHED`
|
||||
* @return 0 on success, or error on failure
|
||||
*/
|
||||
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate) {
|
||||
*detachstate = attr->detachstate;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,13 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/pthread.h"
|
||||
|
||||
int pthread_attr_getguardsize(const pthread_attr_t *a, size_t *x) {
|
||||
*x = a->guardsize;
|
||||
/**
|
||||
* Returns size of unmapped pages at bottom of stack.
|
||||
*
|
||||
* @param guardsize will be set to guard size in bytes
|
||||
* @return 0 on success, or errno on error
|
||||
*/
|
||||
int pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize) {
|
||||
*guardsize = attr->guardsize;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -17,8 +17,22 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
|
||||
/**
|
||||
* Returns size of thread stack.
|
||||
*
|
||||
* This defaults to GetStackSize().
|
||||
*
|
||||
* @param x will be set to stack size in bytes
|
||||
* @return 0 on success, or errno on error
|
||||
* @see pthread_attr_setstacksize()
|
||||
*/
|
||||
int pthread_attr_getstacksize(const pthread_attr_t *a, size_t *x) {
|
||||
*x = a->stacksize;
|
||||
if (a->stacksize) {
|
||||
*x = a->stacksize;
|
||||
} else {
|
||||
*x = GetStackSize();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -17,12 +17,18 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
|
||||
/**
|
||||
* Initializes pthread attributes.
|
||||
*
|
||||
* @return 0 on success, or errno on error
|
||||
*/
|
||||
int pthread_attr_init(pthread_attr_t *attr) {
|
||||
bzero(attr, sizeof(*attr));
|
||||
*attr = (pthread_attr_t){
|
||||
.detachstate = PTHREAD_CREATE_JOINABLE,
|
||||
.stacksize = GetStackSize(),
|
||||
.guardsize = PAGESIZE,
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -16,9 +16,31 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
|
||||
int pthread_attr_setdetachstate(pthread_attr_t *a, int x) {
|
||||
a->detachstate = x;
|
||||
return 0;
|
||||
/**
|
||||
* Sets thread detachable attribute, e.g.
|
||||
*
|
||||
* pthread_attr_t attr;
|
||||
* pthread_attr_init(&attr);
|
||||
* pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
* pthread_create(0, &attr, func, 0);
|
||||
* pthread_attr_destroy(&attr);
|
||||
*
|
||||
* @param detachstate can be one of
|
||||
* - `PTHREAD_CREATE_JOINABLE` (default)
|
||||
* - `PTHREAD_CREATE_DETACHED`
|
||||
* @return 0 on success, or error on failure
|
||||
* @raises EINVAL if `detachstate` is invalid
|
||||
*/
|
||||
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) {
|
||||
switch (detachstate) {
|
||||
case PTHREAD_CREATE_JOINABLE:
|
||||
case PTHREAD_CREATE_DETACHED:
|
||||
attr->detachstate = detachstate;
|
||||
return 0;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,9 +16,21 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
int pthread_attr_setguardsize(pthread_attr_t *a, size_t x) {
|
||||
a->guardsize = x;
|
||||
/**
|
||||
* Sets size of unmapped pages at bottom of stack.
|
||||
*
|
||||
* Cosmopolitan Libc stack guards always default to 4096 bytes. Setting
|
||||
* `guardsize` to zero will disable automatic creation of guard pages.
|
||||
* Your `guardsize` will be rounded up to `PAGESIZE`.
|
||||
*
|
||||
* @param guardsize contains guard size in bytes
|
||||
* @return 0 on success, or errno on error
|
||||
*/
|
||||
int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize) {
|
||||
attr->guardsize = ROUNDUP(guardsize, PAGESIZE);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -16,9 +16,38 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
|
||||
/**
|
||||
* Sets size of thread stack.
|
||||
*
|
||||
* Your stack must have at least `PTHREAD_STACK_MIN` bytes, which
|
||||
* Cosmpolitan Libc defines as `GetStackSize()`. It's a link-time
|
||||
* constant used by Actually Portable Executable that's 128 kb by
|
||||
* default. See libc/runtime/stack.h for docs on your stack limit
|
||||
* since the APE ELF phdrs are the one true source of truth here.
|
||||
*
|
||||
* Cosmpolitan Libc runtime magic (e.g. ftrace) and memory safety
|
||||
* (e.g. kprintf) assumes that stack sizes are two-powers and are
|
||||
* aligned to that two-power. Conformance isn't required since we
|
||||
* say caveat emptor to those who don't maintain these invariants
|
||||
*
|
||||
* Unlike pthread_attr_setstack() this function should be used if
|
||||
* you want the Cosmopolitan Libc runtime to allocate a stack for
|
||||
* you. Since the runtime uses mmap(MAP_STACK) to do that, you'll
|
||||
* need to choose a multiple of FRAMESIZE, due to Windows.
|
||||
*
|
||||
* If this function isn't called it'll default to GetStackSize().
|
||||
*
|
||||
* @param x contains stack size in bytes
|
||||
* @return 0 on success, or errno on error
|
||||
* @raise EINVAL if `x` is less than `PTHREAD_STACK_MIN`
|
||||
*/
|
||||
int pthread_attr_setstacksize(pthread_attr_t *a, size_t x) {
|
||||
if (x < PTHREAD_STACK_MIN) return EINVAL;
|
||||
if (x & (FRAMESIZE - 1)) return EINVAL;
|
||||
if (x < FRAMESIZE) return EINVAL;
|
||||
a->stacksize = x;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/assert.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Destroys barrier.
|
||||
|
@ -31,6 +32,6 @@ int pthread_barrier_destroy(pthread_barrier_t *barrier) {
|
|||
assert(!"deadlock");
|
||||
return EINVAL;
|
||||
}
|
||||
*barrier = (pthread_barrier_t)PTHREAD_BARRIER_INITIALIZER;
|
||||
memset(barrier, -1, sizeof(*barrier));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -42,11 +42,7 @@ int pthread_barrier_wait(pthread_barrier_t *barrier) {
|
|||
atomic_store(&barrier->popped, 1);
|
||||
do {
|
||||
if (IsLinux() || IsOpenbsd()) {
|
||||
if (barrier->attr == PTHREAD_PROCESS_SHARED) {
|
||||
_futex_wake_public(&barrier->popped, INT_MAX);
|
||||
} else {
|
||||
_futex_wake_private(&barrier->popped, INT_MAX);
|
||||
}
|
||||
_futex_wake(&barrier->popped, INT_MAX, barrier->pshared);
|
||||
} else {
|
||||
pthread_yield();
|
||||
}
|
||||
|
@ -59,11 +55,7 @@ int pthread_barrier_wait(pthread_barrier_t *barrier) {
|
|||
}
|
||||
do {
|
||||
if (IsLinux() || IsOpenbsd()) {
|
||||
if (barrier->attr == PTHREAD_PROCESS_SHARED) {
|
||||
_futex_wait_public(&barrier->popped, 0, 0);
|
||||
} else {
|
||||
_futex_wait_private(&barrier->popped, 0, 0);
|
||||
}
|
||||
_futex_wait(&barrier->popped, 0, barrier->pshared, 0);
|
||||
} else {
|
||||
pthread_yield();
|
||||
}
|
||||
|
|
|
@ -17,12 +17,14 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Destroys barrier attributes.
|
||||
*
|
||||
* @return 0 on success, or error on failure
|
||||
*/
|
||||
int(pthread_barrierattr_destroy)(pthread_barrierattr_t *attr) {
|
||||
return pthread_barrierattr_destroy(attr);
|
||||
int pthread_barrierattr_destroy(pthread_barrierattr_t *attr) {
|
||||
memset(attr, -1, sizeof(*attr));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,8 @@
|
|||
* - `PTHREAD_PROCESS_PRIVATE`
|
||||
* @return 0 on success, or error on failure
|
||||
*/
|
||||
int(pthread_barrierattr_getpshared)(const pthread_barrierattr_t *attr,
|
||||
int *pshared) {
|
||||
return pthread_barrierattr_getpshared(attr, pshared);
|
||||
int pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr,
|
||||
int *pshared) {
|
||||
*pshared = *attr;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*
|
||||
* @return 0 on success, or error on failure
|
||||
*/
|
||||
int(pthread_barrierattr_init)(pthread_barrierattr_t *attr) {
|
||||
return pthread_barrierattr_init(attr);
|
||||
int pthread_barrierattr_init(pthread_barrierattr_t *attr) {
|
||||
*attr = PTHREAD_PROCESS_DEFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -26,11 +26,7 @@ static dontinline int pthread_cond_signal_impl(pthread_cond_t *cond, int n) {
|
|||
if (atomic_load_explicit(&cond->waits, memory_order_relaxed)) {
|
||||
atomic_fetch_add(&cond->seq, 1);
|
||||
if (IsLinux() || IsOpenbsd()) {
|
||||
if (cond->attr == PTHREAD_PROCESS_SHARED) {
|
||||
_futex_wake_public(&cond->seq, n);
|
||||
} else {
|
||||
_futex_wake_private(&cond->seq, n);
|
||||
}
|
||||
_futex_wake(&cond->seq, n, cond->pshared);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/assert.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Destroys condition.
|
||||
|
@ -31,6 +32,6 @@ int pthread_cond_destroy(pthread_cond_t *cond) {
|
|||
assert(!"deadlock");
|
||||
return EINVAL;
|
||||
}
|
||||
*cond = (pthread_cond_t)PTHREAD_COND_INITIALIZER;
|
||||
memset(cond, -1, sizeof(*cond));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
* @param attr may be null
|
||||
* @return 0 on success, or error number on failure
|
||||
*/
|
||||
int(pthread_cond_init)(pthread_cond_t *cond, const pthread_condattr_t *attr) {
|
||||
return pthread_cond_init(cond, attr);
|
||||
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) {
|
||||
*cond = (pthread_cond_t){attr ? *attr : PTHREAD_PROCESS_DEFAULT};
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -17,12 +17,14 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Destroys condition attributes.
|
||||
*
|
||||
* @return 0 on success, or error on failure
|
||||
*/
|
||||
int(pthread_condattr_destroy)(pthread_condattr_t *attr) {
|
||||
return pthread_condattr_destroy(attr);
|
||||
int pthread_condattr_destroy(pthread_condattr_t *attr) {
|
||||
memset(attr, -1, sizeof(*attr));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
* - `PTHREAD_PROCESS_PRIVATE`
|
||||
* @return 0 on success, or error on failure
|
||||
*/
|
||||
int(pthread_condattr_getpshared)(const pthread_condattr_t *attr, int *pshared) {
|
||||
return pthread_condattr_getpshared(attr, pshared);
|
||||
int pthread_condattr_getpshared(const pthread_condattr_t *attr, int *pshared) {
|
||||
*pshared = *attr;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*
|
||||
* @return 0 on success, or error on failure
|
||||
*/
|
||||
int(pthread_condattr_init)(pthread_condattr_t *attr) {
|
||||
return pthread_condattr_init(attr);
|
||||
int pthread_condattr_init(pthread_condattr_t *attr) {
|
||||
*attr = PTHREAD_PROCESS_DEFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/assert.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Destroys mutex.
|
||||
|
@ -31,6 +32,6 @@ int pthread_mutex_destroy(pthread_mutex_t *mutex) {
|
|||
assert(!"deadlock");
|
||||
return EINVAL;
|
||||
}
|
||||
*mutex = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
|
||||
memset(mutex, -1, sizeof(*mutex));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Initializes mutex.
|
||||
|
@ -25,7 +24,11 @@
|
|||
* @param attr may be null
|
||||
* @return 0 on success, or error number on failure
|
||||
*/
|
||||
int(pthread_mutex_init)(pthread_mutex_t *mutex,
|
||||
const pthread_mutexattr_t *attr) {
|
||||
return pthread_mutex_init(mutex, attr);
|
||||
int pthread_mutex_init(pthread_mutex_t *mutex,
|
||||
const pthread_mutexattr_t *attr) {
|
||||
*mutex = (pthread_mutex_t){
|
||||
attr ? attr->type : PTHREAD_MUTEX_DEFAULT,
|
||||
attr ? attr->pshared : PTHREAD_PROCESS_DEFAULT,
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ static int pthread_mutex_lock_spin(pthread_mutex_t *mutex, int expect,
|
|||
tries++;
|
||||
} else if (IsLinux() || IsOpenbsd()) {
|
||||
atomic_fetch_add(&mutex->waits, 1);
|
||||
_futex_wait_private(&mutex->lock, expect, &(struct timespec){1});
|
||||
_futex_wait(&mutex->lock, expect, mutex->pshared, &(struct timespec){1});
|
||||
atomic_fetch_sub(&mutex->waits, 1);
|
||||
} else {
|
||||
pthread_yield();
|
||||
|
@ -87,24 +87,24 @@ static int pthread_mutex_lock_spin(pthread_mutex_t *mutex, int expect,
|
|||
*
|
||||
* Microbenchmarks for single-threaded lock + unlock:
|
||||
*
|
||||
* pthread_spinlock_t : 12c ( 4ns)
|
||||
* PTHREAD_MUTEX_NORMAL : 37c ( 12ns)
|
||||
* PTHREAD_MUTEX_RECURSIVE : 22c ( 7ns)
|
||||
* PTHREAD_MUTEX_ERRORCHECK : 27c ( 9ns)
|
||||
* pthread_spinlock_t : 12c ( 4ns)
|
||||
* PTHREAD_MUTEX_NORMAL : 37c ( 12ns)
|
||||
* PTHREAD_MUTEX_RECURSIVE : 22c ( 7ns)
|
||||
* PTHREAD_MUTEX_ERRORCHECK : 27c ( 9ns)
|
||||
*
|
||||
* Microbenchmarks for multi-threaded lock + unlock:
|
||||
*
|
||||
* pthread_spinlock_t : 6,162c (1,990ns)
|
||||
* PTHREAD_MUTEX_NORMAL : 780c ( 252ns)
|
||||
* PTHREAD_MUTEX_RECURSIVE : 1,047c ( 338ns)
|
||||
* PTHREAD_MUTEX_ERRORCHECK : 1,044c ( 337ns)
|
||||
* pthread_spinlock_t : 2,396c (774ns)
|
||||
* PTHREAD_MUTEX_NORMAL : 535c (173ns)
|
||||
* PTHREAD_MUTEX_RECURSIVE : 1,045c (338ns)
|
||||
* PTHREAD_MUTEX_ERRORCHECK : 917c (296ns)
|
||||
*
|
||||
* @return 0 on success, or error number on failure
|
||||
* @see pthread_spin_lock
|
||||
*/
|
||||
int pthread_mutex_lock(pthread_mutex_t *mutex) {
|
||||
int c, me, owner, tries;
|
||||
switch (mutex->attr) {
|
||||
switch (mutex->type) {
|
||||
case PTHREAD_MUTEX_NORMAL:
|
||||
// From Futexes Are Tricky Version 1.1 § Mutex, Take 3;
|
||||
// Ulrich Drepper, Red Hat Incorporated, June 27, 2004.
|
||||
|
@ -116,7 +116,7 @@ int pthread_mutex_lock(pthread_mutex_t *mutex) {
|
|||
c = atomic_exchange_explicit(&mutex->lock, 2, memory_order_acquire);
|
||||
}
|
||||
while (c) {
|
||||
_futex_wait_private(&mutex->lock, 2, 0);
|
||||
_futex_wait(&mutex->lock, 2, mutex->pshared, 0);
|
||||
c = atomic_exchange_explicit(&mutex->lock, 2, memory_order_acquire);
|
||||
}
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ int pthread_mutex_lock(pthread_mutex_t *mutex) {
|
|||
memory_order_relaxed)) {
|
||||
break;
|
||||
} else if (owner == me) {
|
||||
if (mutex->attr != PTHREAD_MUTEX_ERRORCHECK) {
|
||||
if (mutex->type != PTHREAD_MUTEX_ERRORCHECK) {
|
||||
break;
|
||||
} else {
|
||||
assert(!"deadlock");
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
*/
|
||||
int pthread_mutex_trylock(pthread_mutex_t *mutex) {
|
||||
int c, me, owner;
|
||||
switch (mutex->attr) {
|
||||
switch (mutex->type) {
|
||||
case PTHREAD_MUTEX_NORMAL:
|
||||
c = 0;
|
||||
if (atomic_compare_exchange_strong_explicit(&mutex->lock, &c, 1,
|
||||
|
@ -52,7 +52,7 @@ int pthread_mutex_trylock(pthread_mutex_t *mutex) {
|
|||
memory_order_acquire,
|
||||
memory_order_relaxed)) {
|
||||
if (owner == me) {
|
||||
if (mutex->attr == PTHREAD_MUTEX_ERRORCHECK) {
|
||||
if (mutex->type == PTHREAD_MUTEX_ERRORCHECK) {
|
||||
return EBUSY;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/futex.internal.h"
|
||||
|
@ -31,14 +32,14 @@
|
|||
*/
|
||||
int pthread_mutex_unlock(pthread_mutex_t *mutex) {
|
||||
int c, me, owner;
|
||||
switch (mutex->attr) {
|
||||
switch (mutex->type) {
|
||||
case PTHREAD_MUTEX_NORMAL:
|
||||
// From Futexes Are Tricky Version 1.1 § Mutex, Take 3;
|
||||
// Ulrich Drepper, Red Hat Incorporated, June 27, 2004.
|
||||
if ((c = atomic_fetch_sub_explicit(&mutex->lock, 1,
|
||||
memory_order_release)) != 1) {
|
||||
atomic_store_explicit(&mutex->lock, 0, memory_order_release);
|
||||
_futex_wake_private(&mutex->lock, 1);
|
||||
_futex_wake(&mutex->lock, 1, mutex->pshared);
|
||||
}
|
||||
return 0;
|
||||
case PTHREAD_MUTEX_ERRORCHECK:
|
||||
|
@ -52,8 +53,9 @@ int pthread_mutex_unlock(pthread_mutex_t *mutex) {
|
|||
case PTHREAD_MUTEX_RECURSIVE:
|
||||
if (--mutex->reent) return 0;
|
||||
atomic_store_explicit(&mutex->lock, 0, memory_order_relaxed);
|
||||
if (atomic_load_explicit(&mutex->waits, memory_order_relaxed) > 0) {
|
||||
_pthread_mutex_wake(mutex);
|
||||
if ((IsLinux() || IsOpenbsd()) &&
|
||||
atomic_load_explicit(&mutex->waits, memory_order_relaxed) > 0) {
|
||||
return _futex_wake(&mutex->lock, 1, mutex->pshared);
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
/*-*- 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/dce.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/futex.internal.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
|
||||
int _pthread_mutex_wake(pthread_mutex_t *mutex) {
|
||||
if ((IsLinux() || IsOpenbsd()) &&
|
||||
atomic_load_explicit(&mutex->waits, memory_order_relaxed)) {
|
||||
return _futex_wake_private(&mutex->lock, 1);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -17,11 +17,13 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Destroys mutex attr.
|
||||
* @return 0 on success, or error number on failure
|
||||
*/
|
||||
int(pthread_mutexattr_destroy)(pthread_mutexattr_t *attr) {
|
||||
return pthread_mutexattr_destroy(attr);
|
||||
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr) {
|
||||
memset(attr, -1, sizeof(*attr));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,8 @@
|
|||
* - `PTHREAD_PROCESS_PRIVATE`
|
||||
* @return 0 on success, or error on failure
|
||||
*/
|
||||
int(pthread_mutexattr_getpshared)(const pthread_mutexattr_t *attr,
|
||||
int *pshared) {
|
||||
return pthread_mutexattr_getpshared(attr, pshared);
|
||||
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr,
|
||||
int *pshared) {
|
||||
*pshared = attr->pshared;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
* - `PTHREAD_MUTEX_ERRORCHECK`
|
||||
* @return 0 on success, or error on failure
|
||||
*/
|
||||
int(pthread_mutexattr_gettype)(const pthread_mutexattr_t *attr, int *type) {
|
||||
return pthread_mutexattr_gettype(attr, type);
|
||||
int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type) {
|
||||
*type = attr->type;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,10 @@
|
|||
* Initializes mutex attr.
|
||||
* @return 0 on success, or error number on failure
|
||||
*/
|
||||
int(pthread_mutexattr_init)(pthread_mutexattr_t *attr) {
|
||||
return pthread_mutexattr_init(attr);
|
||||
int pthread_mutexattr_init(pthread_mutexattr_t *attr) {
|
||||
*attr = (pthread_mutexattr_t){
|
||||
PTHREAD_MUTEX_DEFAULT,
|
||||
PTHREAD_PROCESS_DEFAULT,
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared) {
|
|||
switch (pshared) {
|
||||
case PTHREAD_PROCESS_SHARED:
|
||||
case PTHREAD_PROCESS_PRIVATE:
|
||||
*attr = pshared;
|
||||
attr->pshared = pshared;
|
||||
return 0;
|
||||
default:
|
||||
return EINVAL;
|
||||
|
|
|
@ -35,7 +35,7 @@ int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) {
|
|||
case PTHREAD_MUTEX_NORMAL:
|
||||
case PTHREAD_MUTEX_RECURSIVE:
|
||||
case PTHREAD_MUTEX_ERRORCHECK:
|
||||
*attr = type;
|
||||
attr->type = type;
|
||||
return 0;
|
||||
default:
|
||||
return EINVAL;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/assert.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Destroys read-write lock.
|
||||
|
@ -31,6 +32,6 @@ int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) {
|
|||
assert(!"deadlock");
|
||||
return EINVAL;
|
||||
}
|
||||
*rwlock = (pthread_rwlock_t)PTHREAD_RWLOCK_INITIALIZER;
|
||||
memset(rwlock, -1, sizeof(*rwlock));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,8 @@
|
|||
* @param attr may be null
|
||||
* @return 0 on success, or error number on failure
|
||||
*/
|
||||
int(pthread_rwlock_init)(pthread_rwlock_t *rwlock,
|
||||
const pthread_rwlockattr_t *attr) {
|
||||
return pthread_rwlock_init(rwlock, attr);
|
||||
int pthread_rwlock_init(pthread_rwlock_t *rwlock,
|
||||
const pthread_rwlockattr_t *attr) {
|
||||
*rwlock = (pthread_rwlock_t){attr ? *attr : PTHREAD_PROCESS_DEFAULT};
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ static int pthread_rwlock_rdlock_spin(pthread_rwlock_t *rwlock, int expect,
|
|||
tries++;
|
||||
} else if (IsLinux() || IsOpenbsd()) {
|
||||
atomic_fetch_add(&rwlock->waits, 1);
|
||||
_futex_wait_private(&rwlock->lock, expect, &(struct timespec){1});
|
||||
_futex_wait(&rwlock->lock, expect, rwlock->pshared, &(struct timespec){1});
|
||||
atomic_fetch_sub(&rwlock->waits, 1);
|
||||
} else {
|
||||
pthread_yield();
|
||||
|
|
|
@ -43,11 +43,7 @@ int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) {
|
|||
memory_order_acquire,
|
||||
memory_order_relaxed)) {
|
||||
if (waits && (IsLinux() || IsOpenbsd())) {
|
||||
if (rwlock->attr == PTHREAD_PROCESS_SHARED) {
|
||||
_futex_wake_public(&rwlock->lock, 1);
|
||||
} else {
|
||||
_futex_wake_private(&rwlock->lock, 1);
|
||||
}
|
||||
_futex_wake(&rwlock->lock, 1, rwlock->pshared);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ static int pthread_rwlock_wrlock_spin(pthread_rwlock_t *rwlock, int expect,
|
|||
tries++;
|
||||
} else if (IsLinux() || IsOpenbsd()) {
|
||||
atomic_fetch_add(&rwlock->waits, 1);
|
||||
_futex_wait_private(&rwlock->lock, expect, &(struct timespec){1});
|
||||
_futex_wait(&rwlock->lock, expect, rwlock->pshared, &(struct timespec){1});
|
||||
atomic_fetch_sub(&rwlock->waits, 1);
|
||||
} else {
|
||||
pthread_yield();
|
||||
|
|
|
@ -17,12 +17,14 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Destroys read-write lock attributes.
|
||||
*
|
||||
* @return 0 on success, or error on failure
|
||||
*/
|
||||
int(pthread_rwlockattr_destroy)(pthread_rwlockattr_t *attr) {
|
||||
return pthread_rwlockattr_destroy(attr);
|
||||
int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr) {
|
||||
memset(attr, -1, sizeof(*attr));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,8 @@
|
|||
* - `PTHREAD_PROCESS_PRIVATE`
|
||||
* @return 0 on success, or error on failure
|
||||
*/
|
||||
int(pthread_rwlockattr_getpshared)(const pthread_rwlockattr_t *attr,
|
||||
int *pshared) {
|
||||
return pthread_rwlockattr_getpshared(attr, pshared);
|
||||
int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr,
|
||||
int *pshared) {
|
||||
*pshared = *attr;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*
|
||||
* @return 0 on success, or error on failure
|
||||
*/
|
||||
int(pthread_rwlockattr_init)(pthread_rwlockattr_t *attr) {
|
||||
return pthread_rwlockattr_init(attr);
|
||||
int pthread_rwlockattr_init(pthread_rwlockattr_t *attr) {
|
||||
*attr = PTHREAD_PROCESS_DEFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ void _wait0(const int *ctid) {
|
|||
if (!(x = atomic_load_explicit(ctid, memory_order_relaxed))) {
|
||||
break;
|
||||
} else if (IsLinux() || IsOpenbsd()) {
|
||||
_futex_wait_public(ctid, x, &(struct timespec){2});
|
||||
_futex_wait(ctid, x, PTHREAD_PROCESS_SHARED, &(struct timespec){2});
|
||||
} else {
|
||||
pthread_yield();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue