summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/thread/sem_getvalue.c3
-rw-r--r--src/thread/sem_post.c12
-rw-r--r--src/thread/sem_timedwait.c10
-rw-r--r--src/thread/sem_trywait.c6
4 files changed, 19 insertions, 12 deletions
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 <semaphore.h>
+#include <limits.h>
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..5c2517f2 100644
--- a/src/thread/sem_post.c
+++ b/src/thread/sem_post.c
@@ -1,17 +1,21 @@
#include <semaphore.h>
+#include <limits.h>
#include "pthread_impl.h"
int sem_post(sem_t *sem)
{
- int val, waiters, priv = sem->__val[2];
+ int val, new, waiters, priv = sem->__val[2];
do {
val = sem->__val[0];
waiters = sem->__val[1];
- if (val == SEM_VALUE_MAX) {
+ if ((val & SEM_VALUE_MAX) == SEM_VALUE_MAX) {
errno = EOVERFLOW;
return -1;
}
- } while (a_cas(sem->__val, val, val+1+(val<0)) != val);
- if (val<0 || waiters) __wake(sem->__val, 1, priv);
+ new = val + 1;
+ if (waiters <= 1)
+ new &= ~0x80000000;
+ } while (a_cas(sem->__val, val, new) != val);
+ if (val<0) __wake(sem->__val, waiters>1 ? 1 : -1, priv);
return 0;
}
diff --git a/src/thread/sem_timedwait.c b/src/thread/sem_timedwait.c
index 58d3ebfe..aa67376c 100644
--- a/src/thread/sem_timedwait.c
+++ b/src/thread/sem_timedwait.c
@@ -1,4 +1,5 @@
#include <semaphore.h>
+#include <limits.h>
#include "pthread_impl.h"
static void cleanup(void *p)
@@ -13,14 +14,15 @@ 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, priv = sem->__val[2];
a_inc(sem->__val+1);
- a_cas(sem->__val, 0, -1);
+ a_cas(sem->__val, 0, 0x80000000);
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, 0x80000000, CLOCK_REALTIME, at, priv);
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 <semaphore.h>
+#include <limits.h>
#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;