diff --git a/libc/Makefile b/libc/Makefile index 0263eda7..05517945 100644 --- a/libc/Makefile +++ b/libc/Makefile @@ -438,6 +438,7 @@ pthread/pthread_condattr_getclock.o \ pthread/pthread_condattr_init.o \ pthread/pthread_condattr_setclock.o \ pthread/pthread_cond_broadcast.o \ +pthread/pthread_cond_clockwait.o \ pthread/pthread_cond_destroy.o \ pthread/pthread_cond_init.o \ pthread/pthread_cond_signal.o \ @@ -456,15 +457,21 @@ pthread/pthread_mutexattr_destroy.o \ pthread/pthread_mutexattr_gettype.o \ pthread/pthread_mutexattr_init.o \ pthread/pthread_mutexattr_settype.o \ +pthread/pthread_mutex_clocklock.o \ pthread/pthread_mutex_destroy.o \ pthread/pthread_mutex_init.o \ pthread/pthread_mutex_lock.o \ +pthread/pthread_mutex_timedlock.o \ pthread/pthread_mutex_trylock.o \ pthread/pthread_mutex_unlock.o \ pthread/pthread_once.o \ +pthread/pthread_rwlock_clockrdlock.o \ +pthread/pthread_rwlock_clockwrlock.o \ pthread/pthread_rwlock_destroy.o \ pthread/pthread_rwlock_init.o \ pthread/pthread_rwlock_rdlock.o \ +pthread/pthread_rwlock_timedrdlock.o \ +pthread/pthread_rwlock_timedwrlock.o \ pthread/pthread_rwlock_tryrdlock.o \ pthread/pthread_rwlock_trywrlock.o \ pthread/pthread_rwlock_unlock.o \ @@ -488,6 +495,7 @@ pwd/setpwent.o \ sched/sched_yield.o \ pty/openpty.o \ scram/scram.o \ +semaphore/sem_clockwait.o \ semaphore/sem_destroy.o \ semaphore/sem_getvalue.o \ semaphore/sem_init.o \ diff --git a/libc/include/pthread.h b/libc/include/pthread.h index a6ed8b16..290bafb6 100644 --- a/libc/include/pthread.h +++ b/libc/include/pthread.h @@ -252,7 +252,8 @@ int pthread_mutex_init(pthread_mutex_t* __restrict, const pthread_mutexattr_t* __restrict); int pthread_mutex_lock(pthread_mutex_t*); /* TODO: pthread_mutex_setprioceiling */ -/* TODO: pthread_mutex_timedlock */ +int pthread_mutex_timedlock(pthread_mutex_t* __restrict, + const struct timespec* __restrict); int pthread_mutex_trylock(pthread_mutex_t*); int pthread_mutex_unlock(pthread_mutex_t*); int pthread_mutexattr_destroy(pthread_mutexattr_t*); @@ -272,8 +273,10 @@ int pthread_rwlock_destroy(pthread_rwlock_t*); int pthread_rwlock_init(pthread_rwlock_t* __restrict, const pthread_rwlockattr_t* __restrict); int pthread_rwlock_rdlock(pthread_rwlock_t*); -/* TODO: pthread_rwlock_timedrdlock */ -/* TODO: pthread_rwlock_timedwrlock */ +int pthread_rwlock_timedrdlock(pthread_rwlock_t* __restrict, + const struct timespec* __restrict); +int pthread_rwlock_timedwrlock(pthread_rwlock_t* __restrict, + const struct timespec* __restrict); int pthread_rwlock_tryrdlock(pthread_rwlock_t*); int pthread_rwlock_trywrlock(pthread_rwlock_t*); int pthread_rwlock_unlock(pthread_rwlock_t*); @@ -296,6 +299,18 @@ int pthread_setspecific(pthread_key_t, const void*); /* TODO: pthread_spin_unlock */ /* TODO: pthread_testcancel */ +#if __USE_SORTIX || 202405L <= __USE_POSIX +int pthread_cond_clockwait(pthread_cond_t* __restrict, + pthread_mutex_t* __restrict, clockid_t, + const struct timespec* __restrict); +int pthread_mutex_clocklock(pthread_mutex_t* __restrict, clockid_t, + const struct timespec* __restrict); +int pthread_rwlock_clockrdlock(pthread_rwlock_t* __restrict, clockid_t, + const struct timespec* __restrict); +int pthread_rwlock_clockwrlock(pthread_rwlock_t* __restrict, clockid_t, + const struct timespec* __restrict); +#endif + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/libc/include/semaphore.h b/libc/include/semaphore.h index a718ad5e..f323cbff 100644 --- a/libc/include/semaphore.h +++ b/libc/include/semaphore.h @@ -22,7 +22,7 @@ #include -#include +#include #ifdef __cplusplus extern "C" { @@ -52,6 +52,11 @@ int sem_trywait(sem_t*); /*int sem_unlink(const char*);*/ int sem_wait(sem_t*); +#if __USE_SORTIX || 202405L <= __USE_POSIX +int sem_clockwait(sem_t* __restrict, clockid_t clock, + const struct timespec* __restrict); +#endif + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/libc/pthread/pthread_cond_clockwait.c b/libc/pthread/pthread_cond_clockwait.c new file mode 100644 index 00000000..454eb0be --- /dev/null +++ b/libc/pthread/pthread_cond_clockwait.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2014, 2021, 2024 Jonas 'Sortie' Termansen. + * + * Permission to use, copy, modify, and 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. + * + * pthread/pthread_cond_clockwait.c + * Waits on a condition or until a timeout happens. + */ + +#include + +#include +#include + +int pthread_cond_clockwait(pthread_cond_t* restrict cond, + pthread_mutex_t* restrict mutex, + clockid_t clock, + const struct timespec* restrict abstime) +{ + struct pthread_cond_elem elem; + pthread_mutex_lock(&cond->lock); + elem.next = NULL; + elem.prev = cond->last; + elem.woken = 0; + if ( cond->last ) + cond->last->next = &elem; + if ( !cond->first ) + cond->first = &elem; + cond->last = &elem; + pthread_mutex_unlock(&cond->lock); + pthread_mutex_unlock(mutex); + int op = FUTEX_WAIT | FUTEX_ABSOLUTE | FUTEX_CLOCK(clock); + int result = 0; + while ( !__atomic_load_n(&elem.woken, __ATOMIC_SEQ_CST) && + futex(&elem.woken, op, 0, abstime) < 0 ) + { + if ( errno == EINTR ) + continue; + if ( errno != EAGAIN ) + result = errno; + break; + } + pthread_mutex_lock(mutex); + pthread_mutex_lock(&cond->lock); + if ( !__atomic_load_n(&elem.woken, __ATOMIC_SEQ_CST) ) + { + if ( elem.next ) + elem.next->prev = elem.prev; + else + cond->last = elem.prev; + if ( elem.prev ) + elem.prev->next = elem.next; + else + cond->first = elem.next; + } + pthread_mutex_unlock(&cond->lock); + return result; +} diff --git a/libc/pthread/pthread_cond_timedwait.c b/libc/pthread/pthread_cond_timedwait.c index 53d70149..5c2ab659 100644 --- a/libc/pthread/pthread_cond_timedwait.c +++ b/libc/pthread/pthread_cond_timedwait.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021 Jonas 'Sortie' Termansen. + * Copyright (c) 2014, 2021, 2024 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,51 +17,11 @@ * Waits on a condition or until a timeout happens. */ -#include - -#include #include int pthread_cond_timedwait(pthread_cond_t* restrict cond, pthread_mutex_t* restrict mutex, const struct timespec* restrict abstime) { - struct pthread_cond_elem elem; - pthread_mutex_lock(&cond->lock); - elem.next = NULL; - elem.prev = cond->last; - elem.woken = 0; - if ( cond->last ) - cond->last->next = &elem; - if ( !cond->first ) - cond->first = &elem; - cond->last = &elem; - pthread_mutex_unlock(&cond->lock); - pthread_mutex_unlock(mutex); - int op = FUTEX_WAIT | FUTEX_ABSOLUTE | FUTEX_CLOCK(cond->clock); - int result = 0; - while ( !__atomic_load_n(&elem.woken, __ATOMIC_SEQ_CST) && - futex(&elem.woken, op, 0, abstime) < 0 ) - { - if ( errno == EINTR ) - continue; - if ( errno != EAGAIN ) - result = errno; - break; - } - pthread_mutex_lock(mutex); - pthread_mutex_lock(&cond->lock); - if ( !__atomic_load_n(&elem.woken, __ATOMIC_SEQ_CST) ) - { - if ( elem.next ) - elem.next->prev = elem.prev; - else - cond->last = elem.prev; - if ( elem.prev ) - elem.prev->next = elem.next; - else - cond->first = elem.next; - } - pthread_mutex_unlock(&cond->lock); - return result; + return pthread_cond_clockwait(cond, mutex, cond->clock, abstime); } diff --git a/libc/pthread/pthread_mutex_clocklock.c b/libc/pthread/pthread_mutex_clocklock.c new file mode 100644 index 00000000..e556ba11 --- /dev/null +++ b/libc/pthread/pthread_mutex_clocklock.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2013, 2014, 2021, 2024 Jonas 'Sortie' Termansen. + * + * Permission to use, copy, modify, and 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. + * + * pthread/pthread_mutex_clocklock.c + * Locks a mutex or waits for a timeout. + */ + +#include + +#include +#include +#include +#include + +static const int UNLOCKED = 0; +static const int LOCKED = 1; +static const int CONTENDED = 2; + +int pthread_mutex_clocklock(pthread_mutex_t* mutex, + clockid_t clock, + const struct timespec* abstime) +{ + int state = UNLOCKED; + int desired = LOCKED; + while ( !__atomic_compare_exchange_n(&mutex->lock, &state, desired, false, + __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ) + { + if ( mutex->type == PTHREAD_MUTEX_RECURSIVE && + (pthread_t) mutex->owner == pthread_self() ) + { + if ( mutex->recursion == ULONG_MAX ) + return errno = EAGAIN; + mutex->recursion++; + return 0; + } + if ( state == LOCKED && + !__atomic_compare_exchange_n(&mutex->lock, &state, CONTENDED, + false, __ATOMIC_SEQ_CST, + __ATOMIC_SEQ_CST) ) + { + state = UNLOCKED; + continue; + } + desired = CONTENDED; + int op = FUTEX_WAIT | FUTEX_ABSOLUTE | FUTEX_CLOCK(clock); + if ( futex(&mutex->lock, op, CONTENDED, abstime) < 0 && + errno != EAGAIN && errno != EINTR ) + return errno; + state = UNLOCKED; + } + mutex->owner = (unsigned long) pthread_self(); + mutex->recursion = 0; + return 0; +} diff --git a/libc/pthread/pthread_mutex_lock.c b/libc/pthread/pthread_mutex_lock.c index 581c6bef..9d45bb79 100644 --- a/libc/pthread/pthread_mutex_lock.c +++ b/libc/pthread/pthread_mutex_lock.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, 2021 Jonas 'Sortie' Termansen. + * Copyright (c) 2013, 2014, 2021, 2024 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,47 +17,9 @@ * Locks a mutex. */ -#include - -#include -#include #include -#include - -static const int UNLOCKED = 0; -static const int LOCKED = 1; -static const int CONTENDED = 2; int pthread_mutex_lock(pthread_mutex_t* mutex) { - int state = UNLOCKED; - int desired = LOCKED; - while ( !__atomic_compare_exchange_n(&mutex->lock, &state, desired, false, - __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ) - { - if ( mutex->type == PTHREAD_MUTEX_RECURSIVE && - (pthread_t) mutex->owner == pthread_self() ) - { - if ( mutex->recursion == ULONG_MAX ) - return errno = EAGAIN; - mutex->recursion++; - return 0; - } - if ( state == LOCKED && - !__atomic_compare_exchange_n(&mutex->lock, &state, CONTENDED, - false, __ATOMIC_SEQ_CST, - __ATOMIC_SEQ_CST) ) - { - state = UNLOCKED; - continue; - } - desired = CONTENDED; - if ( futex(&mutex->lock, FUTEX_WAIT, CONTENDED, NULL) < 0 && - errno != EAGAIN && errno != EINTR ) - return errno; - state = UNLOCKED; - } - mutex->owner = (unsigned long) pthread_self(); - mutex->recursion = 0; - return 0; + return pthread_mutex_timedlock(mutex, NULL); } diff --git a/libc/pthread/pthread_mutex_timedlock.c b/libc/pthread/pthread_mutex_timedlock.c new file mode 100644 index 00000000..bfdadb3a --- /dev/null +++ b/libc/pthread/pthread_mutex_timedlock.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2013, 2014, 2021, 2024 Jonas 'Sortie' Termansen. + * + * Permission to use, copy, modify, and 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. + * + * pthread/pthread_mutex_timedlock.c + * Locks a mutex or waits for a timeout. + */ + +#include + +int pthread_mutex_timedlock(pthread_mutex_t* mutex, + const struct timespec* abstime) +{ + return pthread_mutex_clocklock(mutex, CLOCK_REALTIME, abstime); +} diff --git a/libc/pthread/pthread_rwlock_clockrdlock.c b/libc/pthread/pthread_rwlock_clockrdlock.c new file mode 100644 index 00000000..d9ed073d --- /dev/null +++ b/libc/pthread/pthread_rwlock_clockrdlock.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013, 2024 Jonas 'Sortie' Termansen. + * + * Permission to use, copy, modify, and 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. + * + * pthread/pthread_rwlock_clockrdlock.c + * Acquires read access to a read-write lock or waits for a timeout. + */ + +#include + +int pthread_rwlock_clockrdlock(pthread_rwlock_t* rwlock, clockid_t clock, + const struct timespec* abstime) +{ + pthread_mutex_lock(&rwlock->request_mutex); + rwlock->pending_readers++; + int ret = 0; + while ( !ret && (!rwlock->num_writers || rwlock->pending_writers) ) + ret = pthread_cond_clockwait(&rwlock->reader_condition, + &rwlock->request_mutex, clock, abstime); + rwlock->pending_readers--; + if ( !ret ) + rwlock->num_readers++; + pthread_mutex_unlock(&rwlock->request_mutex); + return ret; +} diff --git a/libc/pthread/pthread_rwlock_clockwrlock.c b/libc/pthread/pthread_rwlock_clockwrlock.c new file mode 100644 index 00000000..5547748f --- /dev/null +++ b/libc/pthread/pthread_rwlock_clockwrlock.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013, 2024 Jonas 'Sortie' Termansen. + * + * Permission to use, copy, modify, and 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. + * + * pthread/pthread_rwlock_clockwrlock.c + * Acquires write access to a read-write lock or waits for a timeout. + */ + +#include + +int pthread_rwlock_clocklock(pthread_rwlock_t* rwlock, clockid_t clock, + const struct timespec* abstime) +{ + pthread_mutex_lock(&rwlock->request_mutex); + rwlock->pending_writers++; + int ret = 0; + while ( !ret && (rwlock->num_readers || rwlock->num_writers) ) + ret = pthread_cond_clockwait(&rwlock->writer_condition, + &rwlock->request_mutex, clock, abstime); + rwlock->pending_writers--; + if ( !ret ) + rwlock->num_writers = 1; + pthread_mutex_unlock(&rwlock->request_mutex); + return ret; +} diff --git a/libc/pthread/pthread_rwlock_rdlock.c b/libc/pthread/pthread_rwlock_rdlock.c index da363705..aa7b8ec8 100644 --- a/libc/pthread/pthread_rwlock_rdlock.c +++ b/libc/pthread/pthread_rwlock_rdlock.c @@ -21,12 +21,5 @@ int pthread_rwlock_rdlock(pthread_rwlock_t* rwlock) { - pthread_mutex_lock(&rwlock->request_mutex); - rwlock->pending_readers++; - while ( rwlock->num_writers || rwlock->pending_writers ) - pthread_cond_wait(&rwlock->reader_condition, &rwlock->request_mutex); - rwlock->pending_readers--; - rwlock->num_readers++; - pthread_mutex_unlock(&rwlock->request_mutex); - return 0; + return pthread_rwlock_timedrdlock(rwlock, NULL); } diff --git a/libc/pthread/pthread_rwlock_timedrdlock.c b/libc/pthread/pthread_rwlock_timedrdlock.c new file mode 100644 index 00000000..fb7e451c --- /dev/null +++ b/libc/pthread/pthread_rwlock_timedrdlock.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2013, 2024 Jonas 'Sortie' Termansen. + * + * Permission to use, copy, modify, and 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. + * + * pthread/pthread_rwlock_timedrdlock.c + * Acquires read access to a read-write lock or waits for a timeout. + */ + +#include + +int pthread_rwlock_timedrdlock(pthread_rwlock_t* rwlock, + const struct timespec* abstime) +{ + return pthread_rwlock_clockrdlock(rwlock, CLOCK_REALTIME, abstime); +} diff --git a/libc/pthread/pthread_rwlock_timedwrlock.c b/libc/pthread/pthread_rwlock_timedwrlock.c new file mode 100644 index 00000000..2741f2c3 --- /dev/null +++ b/libc/pthread/pthread_rwlock_timedwrlock.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2013, 2024 Jonas 'Sortie' Termansen. + * + * Permission to use, copy, modify, and 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. + * + * pthread/pthread_rwlock_timedwrlock.c + * Acquires write access to a read-write lock or waits for a timeout. + */ + +#include + +int pthread_rwlock_timedrwlock(pthread_rwlock_t* rwlock, + const struct timespec* abstime) +{ + return pthread_rwlock_clockwrlock(rwlock, CLOCK_REALTIME, abstime); +} diff --git a/libc/pthread/pthread_rwlock_wrlock.c b/libc/pthread/pthread_rwlock_wrlock.c index 46fa65f4..cd745c6f 100644 --- a/libc/pthread/pthread_rwlock_wrlock.c +++ b/libc/pthread/pthread_rwlock_wrlock.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Jonas 'Sortie' Termansen. + * Copyright (c) 2013, 2024 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -21,12 +21,5 @@ int pthread_rwlock_wrlock(pthread_rwlock_t* rwlock) { - pthread_mutex_lock(&rwlock->request_mutex); - rwlock->pending_writers++; - while ( rwlock->num_readers || rwlock->num_writers ) - pthread_cond_wait(&rwlock->writer_condition, &rwlock->request_mutex); - rwlock->pending_writers--; - rwlock->num_writers = 1; - pthread_mutex_unlock(&rwlock->request_mutex); - return 0; + return pthread_rwlock_timedwrlock(rwlock, NULL); } diff --git a/libc/semaphore/sem_clockwait.c b/libc/semaphore/sem_clockwait.c new file mode 100644 index 00000000..800bafe6 --- /dev/null +++ b/libc/semaphore/sem_clockwait.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014, 2021, 2024 Jonas 'Sortie' Termansen. + * + * Permission to use, copy, modify, and 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. + * + * semaphore/sem_clockwait.c + * Lock a semaphore with a timeout. + */ + +#include + +#include +#include +#include +#include + +int sem_clockwait(sem_t* restrict sem, clockid_t clock, + const struct timespec* restrict abstime) +{ + while ( true ) + { + int old = __atomic_load_n(&sem->value, __ATOMIC_SEQ_CST); + int new = old != -1 ? old - 1 : -1; + bool waiting = new == -1; + if ( waiting ) + __atomic_add_fetch(&sem->waiters, 1, __ATOMIC_SEQ_CST); + if ( old != new && + !__atomic_compare_exchange_n(&sem->value, &old, new, false, + __ATOMIC_SEQ_CST, __ATOMIC_RELAXED) ) + { + if ( waiting ) + __atomic_sub_fetch(&sem->waiters, 1, __ATOMIC_SEQ_CST); + continue; + } + if ( !waiting ) + return 0; + int op = FUTEX_WAIT | FUTEX_ABSOLUTE | FUTEX_CLOCK(clock); + int ret = futex(&sem->value, op, -1, abstime); + __atomic_sub_fetch(&sem->waiters, 1, __ATOMIC_SEQ_CST); + if ( ret < 0 && errno != EAGAIN ) + return -1; + } +} diff --git a/libc/semaphore/sem_timedwait.c b/libc/semaphore/sem_timedwait.c index d7fcbb28..47815677 100644 --- a/libc/semaphore/sem_timedwait.c +++ b/libc/semaphore/sem_timedwait.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021 Jonas 'Sortie' Termansen. + * Copyright (c) 2014, 2021, 2024 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,36 +17,9 @@ * Lock a semaphore with a timeout. */ -#include - -#include #include -#include -#include int sem_timedwait(sem_t* restrict sem, const struct timespec* restrict abstime) { - while ( true ) - { - int old = __atomic_load_n(&sem->value, __ATOMIC_SEQ_CST); - int new = old != -1 ? old - 1 : -1; - bool waiting = new == -1; - if ( waiting ) - __atomic_add_fetch(&sem->waiters, 1, __ATOMIC_SEQ_CST); - if ( old != new && - !__atomic_compare_exchange_n(&sem->value, &old, new, false, - __ATOMIC_SEQ_CST, __ATOMIC_RELAXED) ) - { - if ( waiting ) - __atomic_sub_fetch(&sem->waiters, 1, __ATOMIC_SEQ_CST); - continue; - } - if ( !waiting ) - return 0; - int op = FUTEX_WAIT | FUTEX_ABSOLUTE | FUTEX_CLOCK(CLOCK_REALTIME); - int ret = futex(&sem->value, op, -1, abstime); - __atomic_sub_fetch(&sem->waiters, 1, __ATOMIC_SEQ_CST); - if ( ret < 0 && errno != EAGAIN ) - return -1; - } + return sem_clockwait(sem, CLOCK_REALTIME, abstime); }