OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [newlib-1.18.0/] [newlib/] [libc/] [sys/] [linux/] [linuxthreads/] [oldsemaphore.c] - Blame information for rev 207

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 207 jeremybenn
/*
2
 * This file contains the old semaphore code that we need to
3
 * preserve for glibc-2.0 backwards compatibility. Port to glibc 2.1
4
 * done by Cristian Gafton.
5
 */
6
 
7
/* Linuxthreads - a simple clone()-based implementation of Posix        */
8
/* threads for Linux.                                                   */
9
/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
10
/*                                                                      */
11
/* This program is free software; you can redistribute it and/or        */
12
/* modify it under the terms of the GNU Library General Public License  */
13
/* as published by the Free Software Foundation; either version 2       */
14
/* of the License, or (at your option) any later version.               */
15
/*                                                                      */
16
/* This program is distributed in the hope that it will be useful,      */
17
/* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
18
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
19
/* GNU Library General Public License for more details.                 */
20
 
21
/* Semaphores a la POSIX 1003.1b */
22
#include <shlib-compat.h>
23
#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
24
 
25
#include <errno.h>
26
#include "pthread.h"
27
#include "internals.h"
28
#include "spinlock.h"
29
#include "restart.h"
30
#include "queue.h"
31
 
32
typedef struct {
33
    long int sem_status;
34
    int sem_spinlock;
35
} old_sem_t;
36
 
37
extern int __old_sem_init (old_sem_t *__sem, int __pshared, unsigned int __value);
38
extern int __old_sem_wait (old_sem_t *__sem);
39
extern int __old_sem_trywait (old_sem_t *__sem);
40
extern int __old_sem_post (old_sem_t *__sem);
41
extern int __old_sem_getvalue (old_sem_t *__sem, int *__sval);
42
extern int __old_sem_destroy (old_sem_t *__sem);
43
 
44
 
45
/* Maximum value the semaphore can have.  */
46
#define SEM_VALUE_MAX   ((int) ((~0u) >> 1))
47
 
48
static inline int sem_compare_and_swap(old_sem_t *sem, long oldval, long newval)
49
{
50
    return compare_and_swap(&sem->sem_status, oldval, newval, &sem->sem_spinlock);
51
}
52
 
53
/* The state of a semaphore is represented by a long int encoding
54
   either the semaphore count if >= 0 and no thread is waiting on it,
55
   or the head of the list of threads waiting for the semaphore.
56
   To distinguish the two cases, we encode the semaphore count N
57
   as 2N+1, so that it has the lowest bit set.
58
 
59
   A sequence of sem_wait operations on a semaphore initialized to N
60
   result in the following successive states:
61
     2N+1, 2N-1, ..., 3, 1, &first_waiting_thread, &second_waiting_thread, ...
62
*/
63
 
64
static void sem_restart_list(pthread_descr waiting);
65
 
66
int __old_sem_init(old_sem_t *sem, int pshared, unsigned int value)
67
{
68
    if (value > SEM_VALUE_MAX) {
69
        errno = EINVAL;
70
        return -1;
71
    }
72
    if (pshared) {
73
        errno = ENOSYS;
74
        return -1;
75
    }
76
  sem->sem_spinlock = __LT_SPINLOCK_INIT;
77
  sem->sem_status = ((long)value << 1) + 1;
78
  return 0;
79
}
80
 
81
/* Function called by pthread_cancel to remove the thread from
82
   waiting inside __old_sem_wait. Here we simply unconditionally
83
   indicate that the thread is to be woken, by returning 1. */
84
 
85
static int old_sem_extricate_func(void *obj, pthread_descr th)
86
{
87
    return 1;
88
}
89
 
90
int __old_sem_wait(old_sem_t * sem)
91
{
92
    long oldstatus, newstatus;
93
    volatile pthread_descr self = thread_self();
94
    pthread_descr * th;
95
    pthread_extricate_if extr;
96
 
97
    /* Set up extrication interface */
98
    extr.pu_object = 0;
99
    extr.pu_extricate_func = old_sem_extricate_func;
100
 
101
    while (1) {
102
        /* Register extrication interface */
103
        __pthread_set_own_extricate_if(self, &extr);
104
        do {
105
            oldstatus = sem->sem_status;
106
            if ((oldstatus & 1) && (oldstatus != 1))
107
                newstatus = oldstatus - 2;
108
            else {
109
                newstatus = (long) self;
110
                self->p_nextwaiting = (pthread_descr) oldstatus;
111
            }
112
        }
113
        while (! sem_compare_and_swap(sem, oldstatus, newstatus));
114
        if (newstatus & 1) {
115
            /* We got the semaphore. */
116
            __pthread_set_own_extricate_if(self, 0);
117
            self->p_nextwaiting = NULL;
118
            return 0;
119
        }
120
        /* Wait for sem_post or cancellation */
121
        suspend(self);
122
        __pthread_set_own_extricate_if(self, 0);
123
 
124
        /* This is a cancellation point */
125
        if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) {
126
            /* Remove ourselves from the waiting list if we're still on it */
127
            /* First check if we're at the head of the list. */
128
            do {
129
                oldstatus = sem->sem_status;
130
                if (oldstatus != (long) self) break;
131
                newstatus = (long) self->p_nextwaiting;
132
            }
133
            while (! sem_compare_and_swap(sem, oldstatus, newstatus));
134
            /* Now, check if we're somewhere in the list.
135
               There's a race condition with sem_post here, but it does not matter:
136
               the net result is that at the time pthread_exit is called,
137
               self is no longer reachable from sem->sem_status. */
138
            if (oldstatus != (long) self && (oldstatus & 1) == 0) {
139
                for (th = &(((pthread_descr) oldstatus)->p_nextwaiting);
140
                     *th != NULL && *th != (pthread_descr) 1;
141
                     th = &((*th)->p_nextwaiting)) {
142
                    if (*th == self) {
143
                        *th = self->p_nextwaiting;
144
                        break;
145
                    }
146
                }
147
            }
148
            __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
149
        }
150
    }
151
}
152
 
153
int __old_sem_trywait(old_sem_t * sem)
154
{
155
  long oldstatus, newstatus;
156
 
157
  do {
158
    oldstatus = sem->sem_status;
159
    if ((oldstatus & 1) == 0 || (oldstatus == 1)) {
160
      errno = EAGAIN;
161
      return -1;
162
    }
163
    newstatus = oldstatus - 2;
164
  }
165
  while (! sem_compare_and_swap(sem, oldstatus, newstatus));
166
  return 0;
167
}
168
 
169
int __old_sem_post(old_sem_t * sem)
170
{
171
  long oldstatus, newstatus;
172
 
173
  do {
174
    oldstatus = sem->sem_status;
175
    if ((oldstatus & 1) == 0)
176
      newstatus = 3;
177
    else {
178
      if (oldstatus >= SEM_VALUE_MAX) {
179
        /* Overflow */
180
        errno = ERANGE;
181
        return -1;
182
      }
183
      newstatus = oldstatus + 2;
184
    }
185
  }
186
  while (! sem_compare_and_swap(sem, oldstatus, newstatus));
187
  if ((oldstatus & 1) == 0)
188
    sem_restart_list((pthread_descr) oldstatus);
189
  return 0;
190
}
191
 
192
int __old_sem_getvalue(old_sem_t * sem, int * sval)
193
{
194
  long status = sem->sem_status;
195
  if (status & 1)
196
    *sval = (int)((unsigned long) status >> 1);
197
  else
198
    *sval = 0;
199
  return 0;
200
}
201
 
202
int __old_sem_destroy(old_sem_t * sem)
203
{
204
  if ((sem->sem_status & 1) == 0) {
205
    errno = EBUSY;
206
    return -1;
207
  }
208
  return 0;
209
}
210
 
211
/* Auxiliary function for restarting all threads on a waiting list,
212
   in priority order. */
213
 
214
static void sem_restart_list(pthread_descr waiting)
215
{
216
  pthread_descr th, towake, *p;
217
 
218
  /* Sort list of waiting threads by decreasing priority (insertion sort) */
219
  towake = NULL;
220
  while (waiting != (pthread_descr) 1) {
221
    th = waiting;
222
    waiting = waiting->p_nextwaiting;
223
    p = &towake;
224
    while (*p != NULL && th->p_priority < (*p)->p_priority)
225
      p = &((*p)->p_nextwaiting);
226
    th->p_nextwaiting = *p;
227
    *p = th;
228
  }
229
  /* Wake up threads in priority order */
230
  while (towake != NULL) {
231
    th = towake;
232
    towake = towake->p_nextwaiting;
233
    th->p_nextwaiting = NULL;
234
    restart(th);
235
  }
236
}
237
 
238
compat_symbol (libpthread, __old_sem_init, sem_init, GLIBC_2_0);
239
compat_symbol (libpthread, __old_sem_wait, sem_wait, GLIBC_2_0);
240
compat_symbol (libpthread, __old_sem_trywait, sem_trywait, GLIBC_2_0);
241
compat_symbol (libpthread, __old_sem_post, sem_post, GLIBC_2_0);
242
compat_symbol (libpthread, __old_sem_getvalue, sem_getvalue, GLIBC_2_0);
243
compat_symbol (libpthread, __old_sem_destroy, sem_destroy, GLIBC_2_0);
244
 
245
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.