Add thread wait functions with clock support.

- pthread_cond_clockwait(2)
- pthread_mutex_clocklock(2)
- pthread_mutex_timedlock(2)
- pthread_rwlock_clockrdlock(2)
- pthread_rwlock_clockwrlock(2)
- pthread_rwlock_timedrdlock(2)
- pthread_rwlock_timedwrlock(2)
- sem_clockwait(2)
This commit is contained in:
Jonas 'Sortie' Termansen 2024-06-23 19:05:00 +02:00
parent f460bb78aa
commit 64fc6b5f6d
16 changed files with 378 additions and 132 deletions

View File

@ -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 \

View File

@ -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

View File

@ -22,7 +22,7 @@
#include <sys/cdefs.h>
#include <sortix/timespec.h>
#include <time.h>
#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

View File

@ -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 <sys/futex.h>
#include <errno.h>
#include <pthread.h>
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;
}

View File

@ -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 <sys/futex.h>
#include <errno.h>
#include <pthread.h>
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);
}

View File

@ -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 <sys/futex.h>
#include <errno.h>
#include <limits.h>
#include <pthread.h>
#include <stdbool.h>
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;
}

View File

@ -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 <sys/futex.h>
#include <errno.h>
#include <limits.h>
#include <pthread.h>
#include <stdbool.h>
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);
}

View File

@ -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 <pthread.h>
int pthread_mutex_timedlock(pthread_mutex_t* mutex,
const struct timespec* abstime)
{
return pthread_mutex_clocklock(mutex, CLOCK_REALTIME, abstime);
}

View File

@ -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 <pthread.h>
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;
}

View File

@ -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 <pthread.h>
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;
}

View File

@ -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);
}

View File

@ -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 <pthread.h>
int pthread_rwlock_timedrdlock(pthread_rwlock_t* rwlock,
const struct timespec* abstime)
{
return pthread_rwlock_clockrdlock(rwlock, CLOCK_REALTIME, abstime);
}

View File

@ -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 <pthread.h>
int pthread_rwlock_timedrwlock(pthread_rwlock_t* rwlock,
const struct timespec* abstime)
{
return pthread_rwlock_clockwrlock(rwlock, CLOCK_REALTIME, abstime);
}

View File

@ -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);
}

View File

@ -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 <sys/futex.h>
#include <errno.h>
#include <semaphore.h>
#include <stdbool.h>
#include <time.h>
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;
}
}

View File

@ -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 <sys/futex.h>
#include <errno.h>
#include <semaphore.h>
#include <stdbool.h>
#include <time.h>
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);
}