diff --git a/include/limits.h b/include/limits.h index 53a27b9d..c4d3f42b 100644 --- a/include/limits.h +++ b/include/limits.h @@ -66,7 +66,7 @@ #define PTHREAD_KEYS_MAX 128 #define PTHREAD_STACK_MIN 2048 #define PTHREAD_DESTRUCTOR_ITERATIONS 4 -#define SEM_VALUE_MAX 0x7fffffff +#define SEM_VALUE_MAX 0x3fffffff #define SEM_NSEMS_MAX 256 #define DELAYTIMER_MAX 0x7fffffff #define MQ_PRIO_MAX 32768 diff --git a/src/thread/sem_getvalue.c b/src/thread/sem_getvalue.c index d9d83071..c0b7762d 100644 --- a/src/thread/sem_getvalue.c +++ b/src/thread/sem_getvalue.c @@ -1,8 +1,9 @@ #include +#include int sem_getvalue(sem_t *restrict sem, int *restrict valp) { int val = sem->__val[0]; - *valp = val < 0 ? 0 : val; + *valp = val & SEM_VALUE_MAX; return 0; } diff --git a/src/thread/sem_post.c b/src/thread/sem_post.c index 31e3293d..5051ec97 100644 --- a/src/thread/sem_post.c +++ b/src/thread/sem_post.c @@ -1,17 +1,38 @@ #include +#include #include "pthread_impl.h" int sem_post(sem_t *sem) { - int val, waiters, priv = sem->__val[2]; - do { + int val, new, priv = sem->__val[2], sync = 0; + for (;;) { + int cnt; val = sem->__val[0]; - waiters = sem->__val[1]; - if (val == SEM_VALUE_MAX) { - errno = EOVERFLOW; - return -1; + cnt = val & SEM_VALUE_MAX; + if (cnt < SEM_VALUE_MAX) { + if (!sync && val < 0 && !(val & 0x40000000) && !sem->__val[1]) { + new = cnt | 0x40000000; + if (a_cas(sem->__val, val, new) != val) + continue; + val = new; + sync = 1; + } + new = val + 1; + } else { + new = val; } - } while (a_cas(sem->__val, val, val+1+(val<0)) != val); - if (val<0 || waiters) __wake(sem->__val, 1, priv); + if (sync) { + if (sem->__val[1]) + new |= 0x80000000; + new &= ~0x40000000; + } + if (a_cas(sem->__val, val, new) == val) + break; + } + if ((val & SEM_VALUE_MAX) == SEM_VALUE_MAX) { + errno = EOVERFLOW; + return -1; + } + if (new < 0 || (new & 0x40000000)) __wake(sem->__val, 1, priv); return 0; } diff --git a/src/thread/sem_timedwait.c b/src/thread/sem_timedwait.c index 58d3ebfe..51f6a474 100644 --- a/src/thread/sem_timedwait.c +++ b/src/thread/sem_timedwait.c @@ -1,4 +1,5 @@ #include +#include #include "pthread_impl.h" static void cleanup(void *p) @@ -13,14 +14,18 @@ int sem_timedwait(sem_t *restrict sem, const struct timespec *restrict at) if (!sem_trywait(sem)) return 0; int spins = 100; - while (spins-- && sem->__val[0] <= 0 && !sem->__val[1]) a_spin(); + while (spins-- && !(sem->__val[0] & SEM_VALUE_MAX) && !sem->__val[1]) + a_spin(); while (sem_trywait(sem)) { - int r; + int r, t, val = sem->__val[0]; + if (val & SEM_VALUE_MAX) + continue; a_inc(sem->__val+1); - a_cas(sem->__val, 0, -1); + t = val | 0x80000000; + a_cas(sem->__val, val, t); pthread_cleanup_push(cleanup, (void *)(sem->__val+1)); - r = __timedwait_cp(sem->__val, -1, CLOCK_REALTIME, at, sem->__val[2]); + r = __timedwait_cp(sem->__val, t, CLOCK_REALTIME, at, sem->__val[2]); pthread_cleanup_pop(1); if (r) { errno = r; diff --git a/src/thread/sem_trywait.c b/src/thread/sem_trywait.c index 04edf46b..beb435da 100644 --- a/src/thread/sem_trywait.c +++ b/src/thread/sem_trywait.c @@ -1,12 +1,12 @@ #include +#include #include "pthread_impl.h" int sem_trywait(sem_t *sem) { int val; - while ((val=sem->__val[0]) > 0) { - int new = val-1-(val==1 && sem->__val[1]); - if (a_cas(sem->__val, val, new)==val) return 0; + while ((val=sem->__val[0]) & SEM_VALUE_MAX) { + if (a_cas(sem->__val, val, val-1)==val) return 0; } errno = EAGAIN; return -1;