xref: /relibc/pthreads-emb/sem_wait.c (revision 062c5bc4dfeed2c1bed58ed4810dd27adb32c68d)
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