|
@@ -1,241 +0,0 @@
|
|
|
-
|
|
|
- * This file contains the old semaphore code that we need to
|
|
|
- * preserve for glibc-2.0 backwards compatibility. Port to glibc 2.1
|
|
|
- * done by Cristian Gafton.
|
|
|
- */
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-#include <errno.h>
|
|
|
-#include "pthread.h"
|
|
|
-#include "internals.h"
|
|
|
-#include "spinlock.h"
|
|
|
-#include "restart.h"
|
|
|
-#include "queue.h"
|
|
|
-
|
|
|
-typedef struct {
|
|
|
- long int sem_status;
|
|
|
- int sem_spinlock;
|
|
|
-} old_sem_t;
|
|
|
-
|
|
|
-
|
|
|
-#define SEM_VALUE_MAX ((int) ((~0u) >> 1))
|
|
|
-
|
|
|
-static __inline__ int sem_compare_and_swap(old_sem_t *sem, long oldval, long newval)
|
|
|
-{
|
|
|
- return compare_and_swap(&sem->sem_status, oldval, newval, &sem->sem_spinlock);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- either the semaphore count if >= 0 and no thread is waiting on it,
|
|
|
- or the head of the list of threads waiting for the semaphore.
|
|
|
- To distinguish the two cases, we encode the semaphore count N
|
|
|
- as 2N+1, so that it has the lowest bit set.
|
|
|
-
|
|
|
- A sequence of sem_wait operations on a semaphore initialized to N
|
|
|
- result in the following successive states:
|
|
|
- 2N+1, 2N-1, ..., 3, 1, &first_waiting_thread, &second_waiting_thread, ...
|
|
|
-*/
|
|
|
-
|
|
|
-static void sem_restart_list(pthread_descr waiting);
|
|
|
-
|
|
|
-int __old_sem_init(old_sem_t *sem, int pshared, unsigned int value);
|
|
|
-int __old_sem_init(old_sem_t *sem, int pshared, unsigned int value)
|
|
|
-{
|
|
|
- if (value > SEM_VALUE_MAX) {
|
|
|
- errno = EINVAL;
|
|
|
- return -1;
|
|
|
- }
|
|
|
- if (pshared) {
|
|
|
- errno = ENOSYS;
|
|
|
- return -1;
|
|
|
- }
|
|
|
- sem->sem_spinlock = 0;
|
|
|
- sem->sem_status = ((long)value << 1) + 1;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- waiting inside __old_sem_wait. Here we simply unconditionally
|
|
|
- indicate that the thread is to be woken, by returning 1. */
|
|
|
-
|
|
|
-static int old_sem_extricate_func(void *obj attribute_unused, pthread_descr th attribute_unused)
|
|
|
-{
|
|
|
- return 1;
|
|
|
-}
|
|
|
-
|
|
|
-int __old_sem_wait(old_sem_t * sem);
|
|
|
-int __old_sem_wait(old_sem_t * sem)
|
|
|
-{
|
|
|
- long oldstatus, newstatus;
|
|
|
- volatile pthread_descr self = thread_self();
|
|
|
- pthread_descr * th;
|
|
|
- pthread_extricate_if extr;
|
|
|
-
|
|
|
-
|
|
|
- extr.pu_object = 0;
|
|
|
- extr.pu_extricate_func = old_sem_extricate_func;
|
|
|
-
|
|
|
- while (1) {
|
|
|
-
|
|
|
- __pthread_set_own_extricate_if(self, &extr);
|
|
|
- do {
|
|
|
- oldstatus = sem->sem_status;
|
|
|
- if ((oldstatus & 1) && (oldstatus != 1))
|
|
|
- newstatus = oldstatus - 2;
|
|
|
- else {
|
|
|
- newstatus = (long) self;
|
|
|
- self->p_nextwaiting = (pthread_descr) oldstatus;
|
|
|
- }
|
|
|
- }
|
|
|
- while (! sem_compare_and_swap(sem, oldstatus, newstatus));
|
|
|
- if (newstatus & 1) {
|
|
|
-
|
|
|
- __pthread_set_own_extricate_if(self, 0);
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- suspend(self);
|
|
|
- __pthread_set_own_extricate_if(self, 0);
|
|
|
-
|
|
|
-
|
|
|
- if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) {
|
|
|
-
|
|
|
-
|
|
|
- do {
|
|
|
- oldstatus = sem->sem_status;
|
|
|
- if (oldstatus != (long) self) break;
|
|
|
- newstatus = (long) self->p_nextwaiting;
|
|
|
- }
|
|
|
- while (! sem_compare_and_swap(sem, oldstatus, newstatus));
|
|
|
-
|
|
|
- There's a race condition with sem_post here, but it does not matter:
|
|
|
- the net result is that at the time pthread_exit is called,
|
|
|
- self is no longer reachable from sem->sem_status. */
|
|
|
- if (oldstatus != (long) self && (oldstatus & 1) == 0) {
|
|
|
- for (th = &(((pthread_descr) oldstatus)->p_nextwaiting);
|
|
|
- *th != NULL && *th != (pthread_descr) 1;
|
|
|
- th = &((*th)->p_nextwaiting)) {
|
|
|
- if (*th == self) {
|
|
|
- *th = self->p_nextwaiting;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-int __old_sem_trywait(old_sem_t * sem);
|
|
|
-int __old_sem_trywait(old_sem_t * sem)
|
|
|
-{
|
|
|
- long oldstatus, newstatus;
|
|
|
-
|
|
|
- do {
|
|
|
- oldstatus = sem->sem_status;
|
|
|
- if ((oldstatus & 1) == 0 || (oldstatus == 1)) {
|
|
|
- errno = EAGAIN;
|
|
|
- return -1;
|
|
|
- }
|
|
|
- newstatus = oldstatus - 2;
|
|
|
- }
|
|
|
- while (! sem_compare_and_swap(sem, oldstatus, newstatus));
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-int __old_sem_post(old_sem_t * sem);
|
|
|
-int __old_sem_post(old_sem_t * sem)
|
|
|
-{
|
|
|
- long oldstatus, newstatus;
|
|
|
-
|
|
|
- do {
|
|
|
- oldstatus = sem->sem_status;
|
|
|
- if ((oldstatus & 1) == 0)
|
|
|
- newstatus = 3;
|
|
|
- else {
|
|
|
- if (oldstatus >= SEM_VALUE_MAX) {
|
|
|
-
|
|
|
- errno = ERANGE;
|
|
|
- return -1;
|
|
|
- }
|
|
|
- newstatus = oldstatus + 2;
|
|
|
- }
|
|
|
- }
|
|
|
- while (! sem_compare_and_swap(sem, oldstatus, newstatus));
|
|
|
- if ((oldstatus & 1) == 0)
|
|
|
- sem_restart_list((pthread_descr) oldstatus);
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-int __old_sem_getvalue(old_sem_t * sem, int * sval);
|
|
|
-int __old_sem_getvalue(old_sem_t * sem, int * sval)
|
|
|
-{
|
|
|
- long status = sem->sem_status;
|
|
|
- if (status & 1)
|
|
|
- *sval = (int)((unsigned long) status >> 1);
|
|
|
- else
|
|
|
- *sval = 0;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-int __old_sem_destroy(old_sem_t * sem);
|
|
|
-int __old_sem_destroy(old_sem_t * sem)
|
|
|
-{
|
|
|
- if ((sem->sem_status & 1) == 0) {
|
|
|
- errno = EBUSY;
|
|
|
- return -1;
|
|
|
- }
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- in priority order. */
|
|
|
-
|
|
|
-static void sem_restart_list(pthread_descr waiting)
|
|
|
-{
|
|
|
- pthread_descr th, towake, *p;
|
|
|
-
|
|
|
-
|
|
|
- towake = NULL;
|
|
|
- while (waiting != (pthread_descr) 1) {
|
|
|
- th = waiting;
|
|
|
- waiting = waiting->p_nextwaiting;
|
|
|
- p = &towake;
|
|
|
- while (*p != NULL && th->p_priority < (*p)->p_priority)
|
|
|
- p = &((*p)->p_nextwaiting);
|
|
|
- th->p_nextwaiting = *p;
|
|
|
- *p = th;
|
|
|
- }
|
|
|
-
|
|
|
- while (towake != NULL) {
|
|
|
- th = towake;
|
|
|
- towake = towake->p_nextwaiting;
|
|
|
- th->p_nextwaiting = NULL;
|
|
|
- restart(th);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-#if defined __PIC__ && defined DO_VERSIONING
|
|
|
-symbol_version (__old_sem_init, sem_init, GLIBC_2.0);
|
|
|
-symbol_version (__old_sem_wait, sem_wait, GLIBC_2.0);
|
|
|
-symbol_version (__old_sem_trywait, sem_trywait, GLIBC_2.0);
|
|
|
-symbol_version (__old_sem_post, sem_post, GLIBC_2.0);
|
|
|
-symbol_version (__old_sem_getvalue, sem_getvalue, GLIBC_2.0);
|
|
|
-symbol_version (__old_sem_destroy, sem_destroy, GLIBC_2.0);
|
|
|
-#endif
|
|
|
-
|