OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 207 jeremybenn
/* Linuxthreads - a simple clone()-based implementation of Posix        */
2
/* threads for Linux.                                                   */
3
/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
4
/*                                                                      */
5
/* This program is free software; you can redistribute it and/or        */
6
/* modify it under the terms of the GNU Library General Public License  */
7
/* as published by the Free Software Foundation; either version 2       */
8
/* of the License, or (at your option) any later version.               */
9
/*                                                                      */
10
/* This program is distributed in the hope that it will be useful,      */
11
/* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
12
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
13
/* GNU Library General Public License for more details.                 */
14
 
15
/* Semaphores a la POSIX 1003.1b */
16
 
17
#include <errno.h>
18
#include "pthread.h"
19
#include "semaphore.h"
20
#include "internals.h"
21
#include "spinlock.h"
22
#include "restart.h"
23
#include "queue.h"
24
#include <shlib-compat.h>
25
 
26
int __new_sem_init(sem_t *sem, int pshared, unsigned int value)
27
{
28
  if (value > SEM_VALUE_MAX) {
29
    errno = EINVAL;
30
    return -1;
31
  }
32
  if (pshared) {
33
    errno = ENOSYS;
34
    return -1;
35
  }
36
  __pthread_init_lock(&sem->__sem_lock);
37
  sem->__sem_value = value;
38
  sem->__sem_waiting = NULL;
39
  return 0;
40
}
41
 
42
/* Function called by pthread_cancel to remove the thread from
43
   waiting inside __new_sem_wait. */
44
 
45
static int new_sem_extricate_func(void *obj, pthread_descr th)
46
{
47
  volatile pthread_descr self = thread_self();
48
  sem_t *sem = obj;
49
  int did_remove = 0;
50
 
51
  __pthread_lock(&sem->__sem_lock, self);
52
  did_remove = remove_from_queue(&sem->__sem_waiting, th);
53
  __pthread_unlock(&sem->__sem_lock);
54
 
55
  return did_remove;
56
}
57
 
58
int __new_sem_wait(sem_t * sem)
59
{
60
  volatile pthread_descr self = thread_self();
61
  pthread_extricate_if extr;
62
  int already_canceled = 0;
63
  int spurious_wakeup_count;
64
 
65
  /* Set up extrication interface */
66
  extr.pu_object = sem;
67
  extr.pu_extricate_func = new_sem_extricate_func;
68
 
69
  __pthread_lock(&sem->__sem_lock, self);
70
  if (sem->__sem_value > 0) {
71
    sem->__sem_value--;
72
    __pthread_unlock(&sem->__sem_lock);
73
    return 0;
74
  }
75
  /* Register extrication interface */
76
  THREAD_SETMEM(self, p_sem_avail, 0);
77
  __pthread_set_own_extricate_if(self, &extr);
78
  /* Enqueue only if not already cancelled. */
79
  if (!(THREAD_GETMEM(self, p_canceled)
80
      && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
81
    enqueue(&sem->__sem_waiting, self);
82
  else
83
    already_canceled = 1;
84
  __pthread_unlock(&sem->__sem_lock);
85
 
86
  if (already_canceled) {
87
    __pthread_set_own_extricate_if(self, 0);
88
    __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
89
  }
90
 
91
  /* Wait for sem_post or cancellation, or fall through if already canceled */
92
  spurious_wakeup_count = 0;
93
  while (1)
94
    {
95
      suspend(self);
96
      if (THREAD_GETMEM(self, p_sem_avail) == 0
97
          && (THREAD_GETMEM(self, p_woken_by_cancel) == 0
98
              || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
99
        {
100
          /* Count resumes that don't belong to us. */
101
          spurious_wakeup_count++;
102
          continue;
103
        }
104
      break;
105
    }
106
  __pthread_set_own_extricate_if(self, 0);
107
 
108
  /* Terminate only if the wakeup came from cancellation. */
109
  /* Otherwise ignore cancellation because we got the semaphore. */
110
 
111
  if (THREAD_GETMEM(self, p_woken_by_cancel)
112
      && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
113
    THREAD_SETMEM(self, p_woken_by_cancel, 0);
114
    __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
115
  }
116
  /* We got the semaphore */
117
  return 0;
118
}
119
 
120
int __new_sem_trywait(sem_t * sem)
121
{
122
  int retval;
123
 
124
  __pthread_lock(&sem->__sem_lock, NULL);
125
  if (sem->__sem_value == 0) {
126
    errno = EAGAIN;
127
    retval = -1;
128
  } else {
129
    sem->__sem_value--;
130
    retval = 0;
131
  }
132
  __pthread_unlock(&sem->__sem_lock);
133
  return retval;
134
}
135
 
136
int __new_sem_post(sem_t * sem)
137
{
138
  pthread_descr self = thread_self();
139
  pthread_descr th;
140
  struct pthread_request request;
141
 
142
  if (THREAD_GETMEM(self, p_in_sighandler) == NULL) {
143
    __pthread_lock(&sem->__sem_lock, self);
144
    if (sem->__sem_waiting == NULL) {
145
      if (sem->__sem_value >= SEM_VALUE_MAX) {
146
        /* Overflow */
147
        errno = ERANGE;
148
        __pthread_unlock(&sem->__sem_lock);
149
        return -1;
150
      }
151
      sem->__sem_value++;
152
      __pthread_unlock(&sem->__sem_lock);
153
    } else {
154
      th = dequeue(&sem->__sem_waiting);
155
      __pthread_unlock(&sem->__sem_lock);
156
      th->p_sem_avail = 1;
157
      WRITE_MEMORY_BARRIER();
158
      restart(th);
159
    }
160
  } else {
161
    /* If we're in signal handler, delegate post operation to
162
       the thread manager. */
163
    if (__pthread_manager_request < 0) {
164
      if (__pthread_initialize_manager() < 0) {
165
        errno = EAGAIN;
166
        return -1;
167
      }
168
    }
169
    request.req_kind = REQ_POST;
170
    request.req_args.post = sem;
171
    TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request,
172
                                    (char *) &request, sizeof(request)));
173
  }
174
  return 0;
175
}
176
 
177
int __new_sem_getvalue(sem_t * sem, int * sval)
178
{
179
  *sval = sem->__sem_value;
180
  return 0;
181
}
182
 
183
int __new_sem_destroy(sem_t * sem)
184
{
185
  if (sem->__sem_waiting != NULL) {
186
    __set_errno (EBUSY);
187
    return -1;
188
  }
189
  return 0;
190
}
191
 
192
sem_t *sem_open(const char *name, int oflag, ...)
193
{
194
  __set_errno (ENOSYS);
195
  return SEM_FAILED;
196
}
197
 
198
int sem_close(sem_t *sem)
199
{
200
  __set_errno (ENOSYS);
201
  return -1;
202
}
203
 
204
int sem_unlink(const char *name)
205
{
206
  __set_errno (ENOSYS);
207
  return -1;
208
}
209
 
210
int sem_timedwait(sem_t *sem, const struct timespec *abstime)
211
{
212
  pthread_descr self = thread_self();
213
  pthread_extricate_if extr;
214
  int already_canceled = 0;
215
  int spurious_wakeup_count;
216
 
217
  __pthread_lock(&sem->__sem_lock, self);
218
  if (sem->__sem_value > 0) {
219
    --sem->__sem_value;
220
    __pthread_unlock(&sem->__sem_lock);
221
    return 0;
222
  }
223
 
224
  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) {
225
    /* The standard requires that if the function would block and the
226
       time value is illegal, the function returns with an error.  */
227
    __pthread_unlock(&sem->__sem_lock);
228
    return EINVAL;
229
  }
230
 
231
  /* Set up extrication interface */
232
  extr.pu_object = sem;
233
  extr.pu_extricate_func = new_sem_extricate_func;
234
 
235
  /* Register extrication interface */
236
  THREAD_SETMEM(self, p_sem_avail, 0);
237
  __pthread_set_own_extricate_if(self, &extr);
238
  /* Enqueue only if not already cancelled. */
239
  if (!(THREAD_GETMEM(self, p_canceled)
240
      && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
241
    enqueue(&sem->__sem_waiting, self);
242
  else
243
    already_canceled = 1;
244
  __pthread_unlock(&sem->__sem_lock);
245
 
246
  if (already_canceled) {
247
    __pthread_set_own_extricate_if(self, 0);
248
    __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
249
  }
250
 
251
  spurious_wakeup_count = 0;
252
  while (1)
253
    {
254
      if (timedsuspend(self, abstime) == 0) {
255
        int was_on_queue;
256
 
257
        /* __pthread_lock will queue back any spurious restarts that
258
           may happen to it. */
259
 
260
        __pthread_lock(&sem->__sem_lock, self);
261
        was_on_queue = remove_from_queue(&sem->__sem_waiting, self);
262
        __pthread_unlock(&sem->__sem_lock);
263
 
264
        if (was_on_queue) {
265
          __pthread_set_own_extricate_if(self, 0);
266
          return ETIMEDOUT;
267
        }
268
 
269
        /* Eat the outstanding restart() from the signaller */
270
        suspend(self);
271
      }
272
 
273
      if (THREAD_GETMEM(self, p_sem_avail) == 0
274
          && (THREAD_GETMEM(self, p_woken_by_cancel) == 0
275
              || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
276
        {
277
          /* Count resumes that don't belong to us. */
278
          spurious_wakeup_count++;
279
          continue;
280
        }
281
      break;
282
    }
283
 
284
 __pthread_set_own_extricate_if(self, 0);
285
 
286
  /* Terminate only if the wakeup came from cancellation. */
287
  /* Otherwise ignore cancellation because we got the semaphore. */
288
 
289
  if (THREAD_GETMEM(self, p_woken_by_cancel)
290
      && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
291
    THREAD_SETMEM(self, p_woken_by_cancel, 0);
292
    __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
293
  }
294
  /* We got the semaphore */
295
  return 0;
296
}
297
 
298
 
299
versioned_symbol (libpthread, __new_sem_init, sem_init, GLIBC_2_1);
300
versioned_symbol (libpthread, __new_sem_wait, sem_wait, GLIBC_2_1);
301
versioned_symbol (libpthread, __new_sem_trywait, sem_trywait, GLIBC_2_1);
302
versioned_symbol (libpthread, __new_sem_post, sem_post, GLIBC_2_1);
303
versioned_symbol (libpthread, __new_sem_getvalue, sem_getvalue, GLIBC_2_1);
304
versioned_symbol (libpthread, __new_sem_destroy, sem_destroy, GLIBC_2_1);

powered by: WebSVN 2.1.0

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