mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-29 08:42:28 +00:00
Introduce pthread_condattr_setclock()
This is one of the few POSIX APIs that was missing. It lets you choose a monotonic clock for your condition variables. This might improve perf on some platforms. It might also grant more flexibility with NTP configs. I know Qt is one project that believes it needs this. To introduce this, I needed to change some the *NSYNC APIs, to support passing a clock param. There's also new benchmarks, demonstrating Cosmopolitan's supremacy over many libc implementations when it comes to mutex performance. Cygwin has an alarmingly bad pthread_mutex_t implementation. It is so bad that they would have been significantly better off if they'd used naive spinlocks.
This commit is contained in:
parent
79516bf08e
commit
3c61a541bd
55 changed files with 449 additions and 155 deletions
|
@ -24,6 +24,7 @@
|
|||
#include "libc/intrin/describeflags.h"
|
||||
#include "libc/intrin/strace.h"
|
||||
#include "libc/runtime/syslib.internal.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
|
||||
#ifdef __aarch64__
|
||||
#define CGT_VDSO __vdsosym("LINUX_2.6.39", "__kernel_clock_gettime")
|
||||
|
@ -58,14 +59,43 @@ static int __clock_gettime_init(int clockid, struct timespec *ts) {
|
|||
return cgt(clockid, ts);
|
||||
}
|
||||
|
||||
static int clock_gettime_impl(int clock, struct timespec *ts) {
|
||||
int rc;
|
||||
if (!IsLinux())
|
||||
return __clock_gettime(clock, ts);
|
||||
TryAgain:
|
||||
|
||||
// Ensure fallback for old Linux sticks.
|
||||
if (clock == 4 /* CLOCK_MONOTONIC_RAW */)
|
||||
clock = CLOCK_MONOTONIC_RAW;
|
||||
|
||||
// Call appropriate implementation.
|
||||
rc = __clock_gettime(clock, ts);
|
||||
|
||||
// CLOCK_MONOTONIC_RAW is Linux 2.6.28+ so not available on RHEL5
|
||||
if (rc == -EINVAL && clock == 4 /* CLOCK_MONOTONIC_RAW */) {
|
||||
CLOCK_MONOTONIC_RAW = CLOCK_MONOTONIC;
|
||||
CLOCK_MONOTONIC_RAW_APPROX = CLOCK_MONOTONIC;
|
||||
goto TryAgain;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns nanosecond time.
|
||||
*
|
||||
* @param clock supports the following values across OSes:
|
||||
* - `CLOCK_REALTIME`
|
||||
* - `CLOCK_MONOTONIC`
|
||||
* - `CLOCK_MONOTONIC_RAW`
|
||||
* - `CLOCK_MONOTONIC_RAW_APPROX`
|
||||
* - `CLOCK_REALTIME_FAST`
|
||||
* - `CLOCK_REALTIME_COARSE`
|
||||
* - `CLOCK_REALTIME_PRECISE`
|
||||
* - `CLOCK_MONOTONIC_FAST`
|
||||
* - `CLOCK_MONOTONIC_COARSE`
|
||||
* - `CLOCK_MONOTONIC_PRECISE`
|
||||
* - `CLOCK_THREAD_CPUTIME_ID`
|
||||
* - `CLOCK_PROCESS_CPUTIME_ID`
|
||||
* @param ts is where the result is stored (or null to do clock check)
|
||||
|
@ -80,7 +110,7 @@ static int __clock_gettime_init(int clockid, struct timespec *ts) {
|
|||
*/
|
||||
int clock_gettime(int clock, struct timespec *ts) {
|
||||
// threads on win32 stacks call this so we can't asan check *ts
|
||||
int rc = __clock_gettime(clock, ts);
|
||||
int rc = clock_gettime_impl(clock, ts);
|
||||
if (rc) {
|
||||
errno = -rc;
|
||||
rc = -1;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/consts/timer.h"
|
||||
|
||||
/**
|
||||
|
@ -79,18 +80,32 @@
|
|||
errno_t clock_nanosleep(int clock, int flags, //
|
||||
const struct timespec *req, //
|
||||
struct timespec *rem) {
|
||||
if (IsMetal()) {
|
||||
if (IsMetal())
|
||||
return ENOSYS;
|
||||
}
|
||||
if (clock == 127 || //
|
||||
(flags & ~TIMER_ABSTIME) || //
|
||||
req->tv_sec < 0 || //
|
||||
!(0 <= req->tv_nsec && req->tv_nsec <= 999999999)) {
|
||||
!(0 <= req->tv_nsec && req->tv_nsec <= 999999999))
|
||||
return EINVAL;
|
||||
int rc;
|
||||
errno_t err, old = errno;
|
||||
|
||||
TryAgain:
|
||||
// Ensure fallback for old Linux sticks.
|
||||
if (IsLinux() && clock == 4 /* CLOCK_MONOTONIC_RAW */)
|
||||
clock = CLOCK_MONOTONIC_RAW;
|
||||
|
||||
rc = sys_clock_nanosleep(clock, flags, req, rem);
|
||||
|
||||
// CLOCK_MONOTONIC_RAW is Linux 2.6.28+ so not available on RHEL5
|
||||
if (IsLinux() && rc && errno == EINVAL &&
|
||||
clock == 4 /* CLOCK_MONOTONIC_RAW */) {
|
||||
CLOCK_MONOTONIC_RAW = CLOCK_MONOTONIC;
|
||||
CLOCK_MONOTONIC_RAW_APPROX = CLOCK_MONOTONIC;
|
||||
goto TryAgain;
|
||||
}
|
||||
errno_t old = errno;
|
||||
int rc = sys_clock_nanosleep(clock, flags, req, rem);
|
||||
errno_t err = !rc ? 0 : errno;
|
||||
|
||||
err = !rc ? 0 : errno;
|
||||
errno = old;
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ void *__maps_pickaddr(size_t);
|
|||
void __maps_add(struct Map *);
|
||||
void __maps_free(struct Map *);
|
||||
void __maps_insert(struct Map *);
|
||||
bool __maps_track(char *, size_t);
|
||||
struct Map *__maps_alloc(void);
|
||||
struct Map *__maps_floor(const char *);
|
||||
void __maps_stack(char *, int, int, size_t, int, intptr_t);
|
||||
|
|
|
@ -305,6 +305,28 @@ void __maps_insert(struct Map *map) {
|
|||
__maps_check();
|
||||
}
|
||||
|
||||
static void __maps_track_insert(struct Map *map, char *addr, size_t size,
|
||||
uintptr_t map_handle) {
|
||||
map->addr = addr;
|
||||
map->size = size;
|
||||
map->prot = PROT_READ | PROT_WRITE;
|
||||
map->flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NOFORK;
|
||||
map->hand = map_handle;
|
||||
__maps_lock();
|
||||
__maps_insert(map);
|
||||
__maps_unlock();
|
||||
}
|
||||
|
||||
bool __maps_track(char *addr, size_t size) {
|
||||
struct Map *map;
|
||||
do {
|
||||
if (!(map = __maps_alloc()))
|
||||
return false;
|
||||
} while (map == MAPS_RETRY);
|
||||
__maps_track_insert(map, addr, size, -1);
|
||||
return true;
|
||||
}
|
||||
|
||||
struct Map *__maps_alloc(void) {
|
||||
struct Map *map;
|
||||
uintptr_t tip = atomic_load_explicit(&__maps.freed, memory_order_relaxed);
|
||||
|
@ -321,14 +343,7 @@ struct Map *__maps_alloc(void) {
|
|||
if (sys.addr == MAP_FAILED)
|
||||
return 0;
|
||||
map = sys.addr;
|
||||
map->addr = sys.addr;
|
||||
map->size = gransz;
|
||||
map->prot = PROT_READ | PROT_WRITE;
|
||||
map->flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NOFORK;
|
||||
map->hand = sys.maphandle;
|
||||
__maps_lock();
|
||||
__maps_insert(map);
|
||||
__maps_unlock();
|
||||
__maps_track_insert(map, sys.addr, gransz, sys.maphandle);
|
||||
for (int i = 1; i < gransz / sizeof(struct Map); ++i)
|
||||
__maps_free(map + i);
|
||||
return MAPS_RETRY;
|
||||
|
|
|
@ -57,12 +57,12 @@ static void pthread_mutex_lock_drepper(atomic_int *futex, char pshare) {
|
|||
LOCKTRACE("acquiring pthread_mutex_lock_drepper(%t)...", futex);
|
||||
if (word == 1)
|
||||
word = atomic_exchange_explicit(futex, 2, memory_order_acquire);
|
||||
BLOCK_CANCELATION;
|
||||
while (word > 0) {
|
||||
BLOCK_CANCELATION;
|
||||
_weaken(nsync_futex_wait_)(futex, 2, pshare, 0);
|
||||
ALLOW_CANCELATION;
|
||||
_weaken(nsync_futex_wait_)(futex, 2, pshare, 0, 0);
|
||||
word = atomic_exchange_explicit(futex, 2, memory_order_acquire);
|
||||
}
|
||||
ALLOW_CANCELATION;
|
||||
}
|
||||
|
||||
static errno_t pthread_mutex_lock_recursive(pthread_mutex_t *mutex,
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
int sys_umtx_timedwait_uint_cp(atomic_int *, int, int, size_t,
|
||||
struct _umtx_time *) asm("sys_futex_cp");
|
||||
|
||||
int sys_umtx_timedwait_uint(atomic_int *p, int expect, bool pshare,
|
||||
int sys_umtx_timedwait_uint(atomic_int *p, int expect, bool pshare, int clock,
|
||||
const struct timespec *abstime) {
|
||||
int op;
|
||||
size_t size;
|
||||
|
@ -32,7 +32,7 @@ int sys_umtx_timedwait_uint(atomic_int *p, int expect, bool pshare,
|
|||
tm_p = 0;
|
||||
size = 0;
|
||||
} else {
|
||||
timo._clockid = CLOCK_REALTIME;
|
||||
timo._clockid = clock;
|
||||
timo._flags = UMTX_ABSTIME;
|
||||
timo._timeout = *abstime;
|
||||
tm_p = &timo;
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "libc/errno.h"
|
||||
#include "libc/fmt/wintime.internal.h"
|
||||
#include "libc/intrin/dll.h"
|
||||
#include "libc/intrin/maps.h"
|
||||
#include "libc/intrin/strace.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/mem/leaks.h"
|
||||
|
@ -60,6 +61,8 @@
|
|||
* @fileoverview Windows Subprocess Management.
|
||||
*/
|
||||
|
||||
#define STACK_SIZE 65536
|
||||
|
||||
struct Procs __proc;
|
||||
|
||||
static textwindows void __proc_stats(int64_t h, struct rusage *ru) {
|
||||
|
@ -130,7 +133,11 @@ textwindows int __proc_harvest(struct Proc *pr, bool iswait4) {
|
|||
|
||||
static textwindows dontinstrument uint32_t __proc_worker(void *arg) {
|
||||
struct CosmoTib tls;
|
||||
char *sp = __builtin_frame_address(0);
|
||||
__bootstrap_tls(&tls, __builtin_frame_address(0));
|
||||
__maps_track(
|
||||
(char *)(((uintptr_t)sp + __pagesize - 1) & -__pagesize) - STACK_SIZE,
|
||||
STACK_SIZE);
|
||||
for (;;) {
|
||||
|
||||
// assemble a group of processes to wait on. if more than 64
|
||||
|
@ -238,7 +245,7 @@ static textwindows dontinstrument uint32_t __proc_worker(void *arg) {
|
|||
static textwindows void __proc_setup(void) {
|
||||
__proc.onbirth = CreateEvent(0, 0, 0, 0); // auto reset
|
||||
__proc.haszombies = CreateEvent(0, 1, 0, 0); // manual reset
|
||||
__proc.thread = CreateThread(0, 65536, __proc_worker, 0,
|
||||
__proc.thread = CreateThread(0, STACK_SIZE, __proc_worker, 0,
|
||||
kNtStackSizeParamIsAReservation, 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -577,10 +577,11 @@ syscon clock CLOCK_REALTIME_PRECISE 0 0 0 0 9 0 0 0 #
|
|||
syscon clock CLOCK_REALTIME_FAST 0 0 0 0 10 0 0 0 #
|
||||
syscon clock CLOCK_REALTIME_COARSE 5 5 0 0 10 0 0 2 # Linux 2.6.32+; bsd consensus; not available on RHEL5
|
||||
syscon clock CLOCK_MONOTONIC 1 1 6 6 4 3 3 1 # XNU/NT faked; could move backwards if NTP introduces negative leap second
|
||||
syscon clock CLOCK_MONOTONIC_RAW 4 4 4 4 4 3 3 1 # actually monotonic; not subject to NTP adjustments; Linux 2.6.28+; XNU/NT/FreeBSD/OpenBSD faked; not available on RHEL5 (will fallback to CLOCK_MONOTONIC)
|
||||
syscon clock CLOCK_MONOTONIC_RAW_APPROX 4 4 5 5 4 3 3 1 # goes faster on xnu, otherwise faked
|
||||
syscon clock CLOCK_MONOTONIC_PRECISE 1 1 6 6 11 3 3 1 #
|
||||
syscon clock CLOCK_MONOTONIC_FAST 1 1 6 6 12 3 3 1 #
|
||||
syscon clock CLOCK_MONOTONIC_COARSE 6 6 5 5 12 3 3 1 # Linux 2.6.32+; bsd consensus; not available on RHEL5
|
||||
syscon clock CLOCK_MONOTONIC_RAW 4 4 4 4 127 127 127 127 # actually monotonic; not subject to NTP adjustments; Linux 2.6.28+; XNU/NT/FreeBSD/OpenBSD faked; not available on RHEL5
|
||||
syscon clock CLOCK_PROCESS_CPUTIME_ID 2 2 12 12 15 2 0x40000000 4 # NetBSD lets you bitwise a PID into clockid_t
|
||||
syscon clock CLOCK_THREAD_CPUTIME_ID 3 3 16 16 14 4 0x20000000 5 #
|
||||
syscon clock CLOCK_PROF 127 127 127 127 2 127 2 127 #
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon clock,CLOCK_MONOTONIC_RAW,4,4,4,4,127,127,127,127
|
||||
.syscon clock,CLOCK_MONOTONIC_RAW,4,4,4,4,4,3,3,1
|
||||
|
|
2
libc/sysv/consts/CLOCK_MONOTONIC_RAW_APPROX.S
Normal file
2
libc/sysv/consts/CLOCK_MONOTONIC_RAW_APPROX.S
Normal file
|
@ -0,0 +1,2 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon clock,CLOCK_MONOTONIC_RAW_APPROX,4,4,5,5,4,3,3,1
|
|
@ -8,7 +8,8 @@ extern const int CLOCK_MONOTONIC;
|
|||
extern const int CLOCK_MONOTONIC_COARSE;
|
||||
extern const int CLOCK_MONOTONIC_FAST;
|
||||
extern const int CLOCK_MONOTONIC_PRECISE;
|
||||
extern const int CLOCK_MONOTONIC_RAW;
|
||||
extern int CLOCK_MONOTONIC_RAW;
|
||||
extern int CLOCK_MONOTONIC_RAW_APPROX;
|
||||
extern const int CLOCK_PROCESS_CPUTIME_ID;
|
||||
extern const int CLOCK_PROF;
|
||||
extern const int CLOCK_REALTIME_ALARM;
|
||||
|
@ -24,9 +25,19 @@ extern const int CLOCK_UPTIME_PRECISE;
|
|||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
||||
#define CLOCK_REALTIME 0
|
||||
#define CLOCK_MONOTONIC CLOCK_MONOTONIC
|
||||
#define CLOCK_PROCESS_CPUTIME_ID CLOCK_PROCESS_CPUTIME_ID
|
||||
#define CLOCK_REALTIME 0
|
||||
#define CLOCK_REALTIME_FAST CLOCK_REALTIME_FAST
|
||||
#define CLOCK_REALTIME_PRECISE CLOCK_REALTIME_PRECISE
|
||||
#define CLOCK_REALTIME_COARSE CLOCK_REALTIME_COARSE
|
||||
|
||||
#define CLOCK_MONOTONIC CLOCK_MONOTONIC
|
||||
#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC_RAW
|
||||
#define CLOCK_MONOTONIC_RAW_APPROX CLOCK_MONOTONIC_RAW_APPROX
|
||||
#define CLOCK_MONOTONIC_FAST CLOCK_MONOTONIC_FAST
|
||||
#define CLOCK_MONOTONIC_PRECISE CLOCK_MONOTONIC_PRECISE
|
||||
#define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC_COARSE
|
||||
|
||||
#define CLOCK_THREAD_CPUTIME_ID CLOCK_THREAD_CPUTIME_ID
|
||||
#define CLOCK_PROCESS_CPUTIME_ID CLOCK_PROCESS_CPUTIME_ID
|
||||
|
||||
#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_CLOCK_H_ */
|
||||
|
|
|
@ -47,7 +47,8 @@ struct _umtx_time {
|
|||
uint32_t _clockid;
|
||||
};
|
||||
|
||||
int sys_umtx_timedwait_uint(_Atomic(int) *, int, bool, const struct timespec *);
|
||||
int sys_umtx_timedwait_uint(_Atomic(int) *, int, bool, int,
|
||||
const struct timespec *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* COSMOPOLITAN_LIBC_THREAD_FREEBSD_INTERNAL_H_ */
|
||||
|
|
|
@ -24,10 +24,12 @@
|
|||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/cosmo.h"
|
||||
#include "libc/intrin/maps.h"
|
||||
#include "libc/intrin/strace.h"
|
||||
#include "libc/nt/enum/processcreationflags.h"
|
||||
#include "libc/nt/thread.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/consts/sicode.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
@ -36,11 +38,17 @@
|
|||
#include "third_party/nsync/mu.h"
|
||||
#ifdef __x86_64__
|
||||
|
||||
#define STACK_SIZE 65536
|
||||
|
||||
struct IntervalTimer __itimer;
|
||||
|
||||
static textwindows dontinstrument uint32_t __itimer_worker(void *arg) {
|
||||
struct CosmoTib tls;
|
||||
__bootstrap_tls(&tls, __builtin_frame_address(0));
|
||||
char *sp = __builtin_frame_address(0);
|
||||
__bootstrap_tls(&tls, sp);
|
||||
__maps_track(
|
||||
(char *)(((uintptr_t)sp + __pagesize - 1) & -__pagesize) - STACK_SIZE,
|
||||
STACK_SIZE);
|
||||
for (;;) {
|
||||
bool dosignal = false;
|
||||
struct timeval now, waituntil;
|
||||
|
@ -66,11 +74,10 @@ static textwindows dontinstrument uint32_t __itimer_worker(void *arg) {
|
|||
}
|
||||
}
|
||||
nsync_mu_unlock(&__itimer.lock);
|
||||
if (dosignal) {
|
||||
if (dosignal)
|
||||
__sig_generate(SIGALRM, SI_TIMER);
|
||||
}
|
||||
nsync_mu_lock(&__itimer.lock);
|
||||
nsync_cv_wait_with_deadline(&__itimer.cond, &__itimer.lock,
|
||||
nsync_cv_wait_with_deadline(&__itimer.cond, &__itimer.lock, CLOCK_REALTIME,
|
||||
timeval_totimespec(waituntil), 0);
|
||||
nsync_mu_unlock(&__itimer.lock);
|
||||
}
|
||||
|
@ -78,7 +85,7 @@ static textwindows dontinstrument uint32_t __itimer_worker(void *arg) {
|
|||
}
|
||||
|
||||
static textwindows void __itimer_setup(void) {
|
||||
__itimer.thread = CreateThread(0, 65536, __itimer_worker, 0,
|
||||
__itimer.thread = CreateThread(0, STACK_SIZE, __itimer_worker, 0,
|
||||
kNtStackSizeParamIsAReservation, 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ errno_t pthread_barrier_wait(pthread_barrier_t *barrier) {
|
|||
// wait for everyone else to arrive at barrier
|
||||
BLOCK_CANCELATION;
|
||||
while ((n = atomic_load_explicit(&barrier->_waiters, memory_order_acquire)))
|
||||
nsync_futex_wait_(&barrier->_waiters, n, barrier->_pshared, 0);
|
||||
nsync_futex_wait_(&barrier->_waiters, n, barrier->_pshared, 0, 0);
|
||||
ALLOW_CANCELATION;
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -16,10 +16,11 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
/**
|
||||
* Initializes condition.
|
||||
* Initializes condition variable.
|
||||
*
|
||||
* @param attr may be null
|
||||
* @return 0 on success, or error number on failure
|
||||
|
@ -27,7 +28,9 @@
|
|||
errno_t pthread_cond_init(pthread_cond_t *cond,
|
||||
const pthread_condattr_t *attr) {
|
||||
*cond = (pthread_cond_t){0};
|
||||
if (attr)
|
||||
cond->_pshared = *attr;
|
||||
if (attr) {
|
||||
cond->_pshared = attr->_pshared;
|
||||
cond->_clock = attr->_clock;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/thread/lock.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
@ -63,7 +64,7 @@ static errno_t pthread_cond_timedwait_impl(pthread_cond_t *cond,
|
|||
struct PthreadWait waiter = {cond, mutex};
|
||||
pthread_cleanup_push(pthread_cond_leave, &waiter);
|
||||
rc = nsync_futex_wait_((atomic_int *)&cond->_sequence, seq1, cond->_pshared,
|
||||
abstime);
|
||||
cond->_clock, abstime);
|
||||
pthread_cleanup_pop(true);
|
||||
if (rc == -EAGAIN)
|
||||
rc = 0;
|
||||
|
@ -82,8 +83,10 @@ static errno_t pthread_cond_timedwait_impl(pthread_cond_t *cond,
|
|||
* }
|
||||
*
|
||||
* @param mutex needs to be held by thread when calling this function
|
||||
* @param abstime may be null to wait indefinitely and should contain
|
||||
* some arbitrary interval added to a `CLOCK_REALTIME` timestamp
|
||||
* @param abstime is an absolute timestamp, which may be null to wait
|
||||
* forever; it's relative to `clock_gettime(CLOCK_REALTIME)` by
|
||||
* default; pthread_condattr_setclock() may be used to customize
|
||||
* which system clock is used
|
||||
* @return 0 on success, or errno on error
|
||||
* @raise ETIMEDOUT if `abstime` was specified and the current time
|
||||
* exceeded its value
|
||||
|
@ -125,7 +128,7 @@ errno_t pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
|
|||
// if using Mike Burrows' code isn't possible, use a naive impl
|
||||
if (!cond->_pshared && !IsXnuSilicon()) {
|
||||
err = nsync_cv_wait_with_deadline(
|
||||
(nsync_cv *)cond, (nsync_mu *)mutex,
|
||||
(nsync_cv *)cond, (nsync_mu *)mutex, cond->_clock,
|
||||
abstime ? *abstime : nsync_time_no_deadline, 0);
|
||||
} else {
|
||||
err = pthread_cond_timedwait_impl(cond, mutex, abstime);
|
||||
|
|
32
libc/thread/pthread_condattr_getclock.c
Normal file
32
libc/thread/pthread_condattr_getclock.c
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2024 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/thread/thread.h"
|
||||
|
||||
/**
|
||||
* Gets clock on condition variable attributes.
|
||||
*
|
||||
* @param clock will be set to one of
|
||||
* - `CLOCK_REALTIME` (default)
|
||||
* - `CLOCK_MONOTONIC`
|
||||
* @return 0 on success, or error on failure
|
||||
*/
|
||||
int pthread_condattr_getclock(const pthread_condattr_t *attr, int *clock) {
|
||||
*clock = attr->_clock;
|
||||
return 0;
|
||||
}
|
|
@ -28,6 +28,6 @@
|
|||
*/
|
||||
errno_t pthread_condattr_getpshared(const pthread_condattr_t *attr,
|
||||
int *pshared) {
|
||||
*pshared = *attr;
|
||||
*pshared = attr->_pshared;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,6 @@
|
|||
* @return 0 on success, or error on failure
|
||||
*/
|
||||
errno_t pthread_condattr_init(pthread_condattr_t *attr) {
|
||||
*attr = 0;
|
||||
*attr = (pthread_condattr_t){0};
|
||||
return 0;
|
||||
}
|
||||
|
|
38
libc/thread/pthread_condattr_setclock.c
Normal file
38
libc/thread/pthread_condattr_setclock.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 et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2024 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/errno.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
/**
|
||||
* Sets clock for condition variable.
|
||||
*
|
||||
* @param clock can be one of
|
||||
* - `CLOCK_REALTIME` (default)
|
||||
* - `CLOCK_MONOTONIC`
|
||||
* @return 0 on success, or error on failure
|
||||
* @raises EINVAL if `clock` is invalid
|
||||
*/
|
||||
int pthread_condattr_setclock(pthread_condattr_t *attr, int clock) {
|
||||
if (clock != CLOCK_REALTIME && //
|
||||
clock != CLOCK_MONOTONIC)
|
||||
return EINVAL;
|
||||
attr->_clock = clock;
|
||||
return 0;
|
||||
}
|
|
@ -32,7 +32,7 @@ errno_t pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared) {
|
|||
switch (pshared) {
|
||||
case PTHREAD_PROCESS_SHARED:
|
||||
case PTHREAD_PROCESS_PRIVATE:
|
||||
*attr = pshared;
|
||||
attr->_pshared = pshared;
|
||||
return 0;
|
||||
default:
|
||||
return EINVAL;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "libc/intrin/describeflags.h"
|
||||
#include "libc/intrin/dll.h"
|
||||
#include "libc/intrin/strace.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
#include "libc/thread/thread2.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
@ -74,7 +75,8 @@ static errno_t _pthread_wait(atomic_int *ctid, struct timespec *abstime) {
|
|||
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);
|
||||
e = nsync_futex_wait_(ctid, x, !IsWindows() && !IsXnu(), CLOCK_REALTIME,
|
||||
abstime);
|
||||
if (e == -ECANCELED) {
|
||||
err = ECANCELED;
|
||||
break;
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/runtime/syslib.internal.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/semaphore.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
@ -121,7 +122,7 @@ int sem_timedwait(sem_t *sem, const struct timespec *abstime) {
|
|||
|
||||
do {
|
||||
if (!(v = atomic_load_explicit(&sem->sem_value, memory_order_relaxed))) {
|
||||
rc = nsync_futex_wait_(&sem->sem_value, v, true, abstime);
|
||||
rc = nsync_futex_wait_(&sem->sem_value, v, true, CLOCK_REALTIME, abstime);
|
||||
if (rc == -EINTR || rc == -ECANCELED) {
|
||||
errno = -rc;
|
||||
rc = -1;
|
||||
|
|
|
@ -56,7 +56,6 @@ COSMOPOLITAN_C_START_
|
|||
|
||||
typedef uintptr_t pthread_t;
|
||||
typedef int pthread_id_np_t;
|
||||
typedef char pthread_condattr_t;
|
||||
typedef char pthread_rwlockattr_t;
|
||||
typedef char pthread_barrierattr_t;
|
||||
typedef unsigned pthread_key_t;
|
||||
|
@ -83,12 +82,18 @@ typedef struct pthread_mutexattr_s {
|
|||
unsigned _word;
|
||||
} pthread_mutexattr_t;
|
||||
|
||||
typedef struct pthread_condattr_s {
|
||||
char _pshared;
|
||||
char _clock;
|
||||
} pthread_condattr_t;
|
||||
|
||||
typedef struct pthread_cond_s {
|
||||
union {
|
||||
void *_align;
|
||||
struct {
|
||||
uint32_t _nsync;
|
||||
char _pshared;
|
||||
char _clock;
|
||||
};
|
||||
};
|
||||
_PTHREAD_ATOMIC(uint32_t) _sequence;
|
||||
|
@ -165,10 +170,12 @@ int pthread_cond_destroy(pthread_cond_t *) libcesque paramsnonnull();
|
|||
int pthread_cond_init(pthread_cond_t *, const pthread_condattr_t *) libcesque paramsnonnull((1));
|
||||
int pthread_cond_signal(pthread_cond_t *) libcesque paramsnonnull();
|
||||
int pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *) libcesque paramsnonnull();
|
||||
int pthread_condattr_destroy(pthread_condattr_t *) libcesque paramsnonnull();
|
||||
int pthread_condattr_getpshared(const pthread_condattr_t *, int *) libcesque paramsnonnull();
|
||||
int pthread_condattr_init(pthread_condattr_t *) libcesque paramsnonnull();
|
||||
int pthread_condattr_destroy(pthread_condattr_t *) libcesque paramsnonnull();
|
||||
int pthread_condattr_setpshared(pthread_condattr_t *, int) libcesque paramsnonnull();
|
||||
int pthread_condattr_getpshared(const pthread_condattr_t *, int *) libcesque paramsnonnull();
|
||||
int pthread_condattr_setclock(pthread_condattr_t *, int) libcesque paramsnonnull();
|
||||
int pthread_condattr_getclock(const pthread_condattr_t *, int *) libcesque paramsnonnull();
|
||||
int pthread_create(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *) dontthrow paramsnonnull((1));
|
||||
int pthread_detach(pthread_t) libcesque;
|
||||
int pthread_equal(pthread_t, pthread_t) libcesque;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue