1*062c5bc4SJason Schmidlapp /*
2*062c5bc4SJason Schmidlapp * -------------------------------------------------------------
3*062c5bc4SJason Schmidlapp *
4*062c5bc4SJason Schmidlapp * Module: sem_wait.c
5*062c5bc4SJason Schmidlapp *
6*062c5bc4SJason Schmidlapp * Purpose:
7*062c5bc4SJason Schmidlapp * Semaphores aren't actually part of the PThreads standard.
8*062c5bc4SJason Schmidlapp * They are defined by the POSIX Standard:
9*062c5bc4SJason Schmidlapp *
10*062c5bc4SJason Schmidlapp * POSIX 1003.1b-1993 (POSIX.1b)
11*062c5bc4SJason Schmidlapp *
12*062c5bc4SJason Schmidlapp * -------------------------------------------------------------
13*062c5bc4SJason Schmidlapp *
14*062c5bc4SJason Schmidlapp * --------------------------------------------------------------------------
15*062c5bc4SJason Schmidlapp *
16*062c5bc4SJason Schmidlapp * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
17*062c5bc4SJason Schmidlapp * Copyright(C) 2008 Jason Schmidlapp
18*062c5bc4SJason Schmidlapp *
19*062c5bc4SJason Schmidlapp * Contact Email: jschmidlapp@users.sourceforge.net
20*062c5bc4SJason Schmidlapp *
21*062c5bc4SJason Schmidlapp *
22*062c5bc4SJason Schmidlapp * Based upon Pthreads-win32 - POSIX Threads Library for Win32
23*062c5bc4SJason Schmidlapp * Copyright(C) 1998 John E. Bossom
24*062c5bc4SJason Schmidlapp * Copyright(C) 1999,2005 Pthreads-win32 contributors
25*062c5bc4SJason Schmidlapp *
26*062c5bc4SJason Schmidlapp * Contact Email: rpj@callisto.canberra.edu.au
27*062c5bc4SJason Schmidlapp *
28*062c5bc4SJason Schmidlapp * The original list of contributors to the Pthreads-win32 project
29*062c5bc4SJason Schmidlapp * is contained in the file CONTRIBUTORS.ptw32 included with the
30*062c5bc4SJason Schmidlapp * source code distribution. The list can also be seen at the
31*062c5bc4SJason Schmidlapp * following World Wide Web location:
32*062c5bc4SJason Schmidlapp * http://sources.redhat.com/pthreads-win32/contributors.html
33*062c5bc4SJason Schmidlapp *
34*062c5bc4SJason Schmidlapp * This library is free software; you can redistribute it and/or
35*062c5bc4SJason Schmidlapp * modify it under the terms of the GNU Lesser General Public
36*062c5bc4SJason Schmidlapp * License as published by the Free Software Foundation; either
37*062c5bc4SJason Schmidlapp * version 2 of the License, or (at your option) any later version.
38*062c5bc4SJason Schmidlapp *
39*062c5bc4SJason Schmidlapp * This library is distributed in the hope that it will be useful,
40*062c5bc4SJason Schmidlapp * but WITHOUT ANY WARRANTY; without even the implied warranty of
41*062c5bc4SJason Schmidlapp * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
42*062c5bc4SJason Schmidlapp * Lesser General Public License for more details.
43*062c5bc4SJason Schmidlapp *
44*062c5bc4SJason Schmidlapp * You should have received a copy of the GNU Lesser General Public
45*062c5bc4SJason Schmidlapp * License along with this library in the file COPYING.LIB;
46*062c5bc4SJason Schmidlapp * if not, write to the Free Software Foundation, Inc.,
47*062c5bc4SJason Schmidlapp * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
48*062c5bc4SJason Schmidlapp */
49*062c5bc4SJason Schmidlapp
50*062c5bc4SJason Schmidlapp #include <stdio.h>
51*062c5bc4SJason Schmidlapp #include <stdlib.h>
52*062c5bc4SJason Schmidlapp
53*062c5bc4SJason Schmidlapp #include "pthread.h"
54*062c5bc4SJason Schmidlapp #include "semaphore.h"
55*062c5bc4SJason Schmidlapp #include "implement.h"
56*062c5bc4SJason Schmidlapp
57*062c5bc4SJason Schmidlapp
58*062c5bc4SJason Schmidlapp static void
pte_sem_wait_cleanup(void * sem)59*062c5bc4SJason Schmidlapp pte_sem_wait_cleanup(void * sem)
60*062c5bc4SJason Schmidlapp {
61*062c5bc4SJason Schmidlapp sem_t s = (sem_t) sem;
62*062c5bc4SJason Schmidlapp unsigned int timeout;
63*062c5bc4SJason Schmidlapp
64*062c5bc4SJason Schmidlapp if (pthread_mutex_lock (&s->lock) == 0)
65*062c5bc4SJason Schmidlapp {
66*062c5bc4SJason Schmidlapp /*
67*062c5bc4SJason Schmidlapp * If sema is destroyed do nothing, otherwise:-
68*062c5bc4SJason Schmidlapp * If the sema is posted between us being cancelled and us locking
69*062c5bc4SJason Schmidlapp * the sema again above then we need to consume that post but cancel
70*062c5bc4SJason Schmidlapp * anyway. If we don't get the semaphore we indicate that we're no
71*062c5bc4SJason Schmidlapp * longer waiting.
72*062c5bc4SJason Schmidlapp */
73*062c5bc4SJason Schmidlapp timeout = 0;
74*062c5bc4SJason Schmidlapp if (pte_osSemaphorePend(s->sem, &timeout) != PTE_OS_OK)
75*062c5bc4SJason Schmidlapp {
76*062c5bc4SJason Schmidlapp ++s->value;
77*062c5bc4SJason Schmidlapp
78*062c5bc4SJason Schmidlapp /*
79*062c5bc4SJason Schmidlapp * Don't release the W32 sema, it doesn't need adjustment
80*062c5bc4SJason Schmidlapp * because it doesn't record the number of waiters.
81*062c5bc4SJason Schmidlapp */
82*062c5bc4SJason Schmidlapp
83*062c5bc4SJason Schmidlapp }
84*062c5bc4SJason Schmidlapp (void) pthread_mutex_unlock (&s->lock);
85*062c5bc4SJason Schmidlapp }
86*062c5bc4SJason Schmidlapp }
87*062c5bc4SJason Schmidlapp
88*062c5bc4SJason Schmidlapp
89*062c5bc4SJason Schmidlapp int
sem_wait(sem_t * sem)90*062c5bc4SJason Schmidlapp sem_wait (sem_t * sem)
91*062c5bc4SJason Schmidlapp /*
92*062c5bc4SJason Schmidlapp * ------------------------------------------------------
93*062c5bc4SJason Schmidlapp * DOCPUBLIC
94*062c5bc4SJason Schmidlapp * This function waits on a semaphore.
95*062c5bc4SJason Schmidlapp *
96*062c5bc4SJason Schmidlapp * PARAMETERS
97*062c5bc4SJason Schmidlapp * sem
98*062c5bc4SJason Schmidlapp * pointer to an instance of sem_t
99*062c5bc4SJason Schmidlapp *
100*062c5bc4SJason Schmidlapp * DESCRIPTION
101*062c5bc4SJason Schmidlapp * This function waits on a semaphore. If the
102*062c5bc4SJason Schmidlapp * semaphore value is greater than zero, it decreases
103*062c5bc4SJason Schmidlapp * its value by one. If the semaphore value is zero, then
104*062c5bc4SJason Schmidlapp * the calling thread (or process) is blocked until it can
105*062c5bc4SJason Schmidlapp * successfully decrease the value or until interrupted by
106*062c5bc4SJason Schmidlapp * a signal.
107*062c5bc4SJason Schmidlapp *
108*062c5bc4SJason Schmidlapp * RESULTS
109*062c5bc4SJason Schmidlapp * 0 successfully decreased semaphore,
110*062c5bc4SJason Schmidlapp * -1 failed, error in errno
111*062c5bc4SJason Schmidlapp * ERRNO
112*062c5bc4SJason Schmidlapp * EINVAL 'sem' is not a valid semaphore,
113*062c5bc4SJason Schmidlapp * ENOSYS semaphores are not supported,
114*062c5bc4SJason Schmidlapp * EINTR the function was interrupted by a signal,
115*062c5bc4SJason Schmidlapp * EDEADLK a deadlock condition was detected.
116*062c5bc4SJason Schmidlapp *
117*062c5bc4SJason Schmidlapp * ------------------------------------------------------
118*062c5bc4SJason Schmidlapp */
119*062c5bc4SJason Schmidlapp {
120*062c5bc4SJason Schmidlapp int result = 0;
121*062c5bc4SJason Schmidlapp sem_t s = *sem;
122*062c5bc4SJason Schmidlapp
123*062c5bc4SJason Schmidlapp pthread_testcancel();
124*062c5bc4SJason Schmidlapp
125*062c5bc4SJason Schmidlapp if (s == NULL)
126*062c5bc4SJason Schmidlapp {
127*062c5bc4SJason Schmidlapp result = EINVAL;
128*062c5bc4SJason Schmidlapp }
129*062c5bc4SJason Schmidlapp else
130*062c5bc4SJason Schmidlapp {
131*062c5bc4SJason Schmidlapp if ((result = pthread_mutex_lock (&s->lock)) == 0)
132*062c5bc4SJason Schmidlapp {
133*062c5bc4SJason Schmidlapp int v;
134*062c5bc4SJason Schmidlapp
135*062c5bc4SJason Schmidlapp /* See sem_destroy.c
136*062c5bc4SJason Schmidlapp */
137*062c5bc4SJason Schmidlapp if (*sem == NULL)
138*062c5bc4SJason Schmidlapp {
139*062c5bc4SJason Schmidlapp (void) pthread_mutex_unlock (&s->lock);
140*062c5bc4SJason Schmidlapp errno = EINVAL;
141*062c5bc4SJason Schmidlapp return -1;
142*062c5bc4SJason Schmidlapp }
143*062c5bc4SJason Schmidlapp
144*062c5bc4SJason Schmidlapp v = --s->value;
145*062c5bc4SJason Schmidlapp (void) pthread_mutex_unlock (&s->lock);
146*062c5bc4SJason Schmidlapp
147*062c5bc4SJason Schmidlapp if (v < 0)
148*062c5bc4SJason Schmidlapp {
149*062c5bc4SJason Schmidlapp /* Must wait */
150*062c5bc4SJason Schmidlapp pthread_cleanup_push(pte_sem_wait_cleanup, (void *) s);
151*062c5bc4SJason Schmidlapp result = pte_cancellable_wait(s->sem,NULL);
152*062c5bc4SJason Schmidlapp /* Cleanup if we're canceled or on any other error */
153*062c5bc4SJason Schmidlapp pthread_cleanup_pop(result);
154*062c5bc4SJason Schmidlapp
155*062c5bc4SJason Schmidlapp // Wait was cancelled, indicate that we're no longer waiting on this semaphore.
156*062c5bc4SJason Schmidlapp /*
157*062c5bc4SJason Schmidlapp if (result == PTE_OS_INTERRUPTED)
158*062c5bc4SJason Schmidlapp {
159*062c5bc4SJason Schmidlapp result = EINTR;
160*062c5bc4SJason Schmidlapp ++s->value;
161*062c5bc4SJason Schmidlapp }
162*062c5bc4SJason Schmidlapp */
163*062c5bc4SJason Schmidlapp }
164*062c5bc4SJason Schmidlapp }
165*062c5bc4SJason Schmidlapp
166*062c5bc4SJason Schmidlapp }
167*062c5bc4SJason Schmidlapp
168*062c5bc4SJason Schmidlapp if (result != 0)
169*062c5bc4SJason Schmidlapp {
170*062c5bc4SJason Schmidlapp errno = result;
171*062c5bc4SJason Schmidlapp return -1;
172*062c5bc4SJason Schmidlapp }
173*062c5bc4SJason Schmidlapp
174*062c5bc4SJason Schmidlapp return 0;
175*062c5bc4SJason Schmidlapp
176*062c5bc4SJason Schmidlapp } /* sem_wait */
177*062c5bc4SJason Schmidlapp
178*062c5bc4SJason Schmidlapp
179*062c5bc4SJason Schmidlapp int
sem_wait_nocancel(sem_t * sem)180*062c5bc4SJason Schmidlapp sem_wait_nocancel (sem_t * sem)
181*062c5bc4SJason Schmidlapp /*
182*062c5bc4SJason Schmidlapp * ------------------------------------------------------
183*062c5bc4SJason Schmidlapp * DOCPUBLIC
184*062c5bc4SJason Schmidlapp * This function waits on a semaphore, and doesn't
185*062c5bc4SJason Schmidlapp * allow cancellation.
186*062c5bc4SJason Schmidlapp *
187*062c5bc4SJason Schmidlapp * PARAMETERS
188*062c5bc4SJason Schmidlapp * sem
189*062c5bc4SJason Schmidlapp * pointer to an instance of sem_t
190*062c5bc4SJason Schmidlapp *
191*062c5bc4SJason Schmidlapp * DESCRIPTION
192*062c5bc4SJason Schmidlapp * This function waits on a semaphore. If the
193*062c5bc4SJason Schmidlapp * semaphore value is greater than zero, it decreases
194*062c5bc4SJason Schmidlapp * its value by one. If the semaphore value is zero, then
195*062c5bc4SJason Schmidlapp * the calling thread (or process) is blocked until it can
196*062c5bc4SJason Schmidlapp * successfully decrease the value or until interrupted by
197*062c5bc4SJason Schmidlapp * a signal.
198*062c5bc4SJason Schmidlapp *
199*062c5bc4SJason Schmidlapp * RESULTS
200*062c5bc4SJason Schmidlapp * 0 successfully decreased semaphore,
201*062c5bc4SJason Schmidlapp * -1 failed, error in errno
202*062c5bc4SJason Schmidlapp * ERRNO
203*062c5bc4SJason Schmidlapp * EINVAL 'sem' is not a valid semaphore,
204*062c5bc4SJason Schmidlapp * ENOSYS semaphores are not supported,
205*062c5bc4SJason Schmidlapp * EINTR the function was interrupted by a signal,
206*062c5bc4SJason Schmidlapp * EDEADLK a deadlock condition was detected.
207*062c5bc4SJason Schmidlapp *
208*062c5bc4SJason Schmidlapp * ------------------------------------------------------
209*062c5bc4SJason Schmidlapp */
210*062c5bc4SJason Schmidlapp {
211*062c5bc4SJason Schmidlapp int result = 0;
212*062c5bc4SJason Schmidlapp sem_t s = *sem;
213*062c5bc4SJason Schmidlapp
214*062c5bc4SJason Schmidlapp pthread_testcancel();
215*062c5bc4SJason Schmidlapp
216*062c5bc4SJason Schmidlapp if (s == NULL)
217*062c5bc4SJason Schmidlapp {
218*062c5bc4SJason Schmidlapp result = EINVAL;
219*062c5bc4SJason Schmidlapp }
220*062c5bc4SJason Schmidlapp else
221*062c5bc4SJason Schmidlapp {
222*062c5bc4SJason Schmidlapp if ((result = pthread_mutex_lock (&s->lock)) == 0)
223*062c5bc4SJason Schmidlapp {
224*062c5bc4SJason Schmidlapp int v;
225*062c5bc4SJason Schmidlapp
226*062c5bc4SJason Schmidlapp /* See sem_destroy.c
227*062c5bc4SJason Schmidlapp */
228*062c5bc4SJason Schmidlapp if (*sem == NULL)
229*062c5bc4SJason Schmidlapp {
230*062c5bc4SJason Schmidlapp (void) pthread_mutex_unlock (&s->lock);
231*062c5bc4SJason Schmidlapp errno = EINVAL;
232*062c5bc4SJason Schmidlapp return -1;
233*062c5bc4SJason Schmidlapp }
234*062c5bc4SJason Schmidlapp
235*062c5bc4SJason Schmidlapp v = --s->value;
236*062c5bc4SJason Schmidlapp (void) pthread_mutex_unlock (&s->lock);
237*062c5bc4SJason Schmidlapp
238*062c5bc4SJason Schmidlapp if (v < 0)
239*062c5bc4SJason Schmidlapp {
240*062c5bc4SJason Schmidlapp pte_osSemaphorePend(s->sem, NULL);
241*062c5bc4SJason Schmidlapp }
242*062c5bc4SJason Schmidlapp }
243*062c5bc4SJason Schmidlapp
244*062c5bc4SJason Schmidlapp }
245*062c5bc4SJason Schmidlapp
246*062c5bc4SJason Schmidlapp if (result != 0)
247*062c5bc4SJason Schmidlapp {
248*062c5bc4SJason Schmidlapp errno = result;
249*062c5bc4SJason Schmidlapp return -1;
250*062c5bc4SJason Schmidlapp }
251*062c5bc4SJason Schmidlapp
252*062c5bc4SJason Schmidlapp return 0;
253*062c5bc4SJason Schmidlapp
254*062c5bc4SJason Schmidlapp } /* sem_wait_nocancel */
255