xref: /relibc/pthreads-emb/sem_timedwait.c (revision 062c5bc4dfeed2c1bed58ed4810dd27adb32c68d)
1*062c5bc4SJason Schmidlapp /*
2*062c5bc4SJason Schmidlapp  * -------------------------------------------------------------
3*062c5bc4SJason Schmidlapp  *
4*062c5bc4SJason Schmidlapp  * Module: sem_timedwait.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 typedef struct
58*062c5bc4SJason Schmidlapp   {
59*062c5bc4SJason Schmidlapp     sem_t sem;
60*062c5bc4SJason Schmidlapp     int * resultPtr;
61*062c5bc4SJason Schmidlapp   } sem_timedwait_cleanup_args_t;
62*062c5bc4SJason Schmidlapp 
63*062c5bc4SJason Schmidlapp static void
pte_sem_timedwait_cleanup(void * args)64*062c5bc4SJason Schmidlapp pte_sem_timedwait_cleanup (void * args)
65*062c5bc4SJason Schmidlapp {
66*062c5bc4SJason Schmidlapp   sem_timedwait_cleanup_args_t * a = (sem_timedwait_cleanup_args_t *)args;
67*062c5bc4SJason Schmidlapp   sem_t s = a->sem;
68*062c5bc4SJason Schmidlapp 
69*062c5bc4SJason Schmidlapp   if (pthread_mutex_lock (&s->lock) == 0)
70*062c5bc4SJason Schmidlapp     {
71*062c5bc4SJason Schmidlapp       /*
72*062c5bc4SJason Schmidlapp        * We either timed out or were cancelled.
73*062c5bc4SJason Schmidlapp        * If someone has posted between then and now we try to take the semaphore.
74*062c5bc4SJason Schmidlapp        * Otherwise the semaphore count may be wrong after we
75*062c5bc4SJason Schmidlapp        * return. In the case of a cancellation, it is as if we
76*062c5bc4SJason Schmidlapp        * were cancelled just before we return (after taking the semaphore)
77*062c5bc4SJason Schmidlapp        * which is ok.
78*062c5bc4SJason Schmidlapp        */
79*062c5bc4SJason Schmidlapp       unsigned int timeout = 0;
80*062c5bc4SJason Schmidlapp       if (pte_osSemaphorePend(s->sem, &timeout) == PTE_OS_OK)
81*062c5bc4SJason Schmidlapp         {
82*062c5bc4SJason Schmidlapp           /* We got the semaphore on the second attempt */
83*062c5bc4SJason Schmidlapp           *(a->resultPtr) = 0;
84*062c5bc4SJason Schmidlapp         }
85*062c5bc4SJason Schmidlapp       else
86*062c5bc4SJason Schmidlapp         {
87*062c5bc4SJason Schmidlapp           /* Indicate we're no longer waiting */
88*062c5bc4SJason Schmidlapp           s->value++;
89*062c5bc4SJason Schmidlapp 
90*062c5bc4SJason Schmidlapp           /*
91*062c5bc4SJason Schmidlapp            * Don't release the OS sema, it doesn't need adjustment
92*062c5bc4SJason Schmidlapp            * because it doesn't record the number of waiters.
93*062c5bc4SJason Schmidlapp            */
94*062c5bc4SJason Schmidlapp 
95*062c5bc4SJason Schmidlapp         }
96*062c5bc4SJason Schmidlapp       (void) pthread_mutex_unlock (&s->lock);
97*062c5bc4SJason Schmidlapp     }
98*062c5bc4SJason Schmidlapp }
99*062c5bc4SJason Schmidlapp 
100*062c5bc4SJason Schmidlapp 
101*062c5bc4SJason Schmidlapp int
sem_timedwait(sem_t * sem,const struct timespec * abstime)102*062c5bc4SJason Schmidlapp sem_timedwait (sem_t * sem, const struct timespec *abstime)
103*062c5bc4SJason Schmidlapp /*
104*062c5bc4SJason Schmidlapp  * ------------------------------------------------------
105*062c5bc4SJason Schmidlapp  * DOCPUBLIC
106*062c5bc4SJason Schmidlapp  *      This function waits on a semaphore possibly until
107*062c5bc4SJason Schmidlapp  *      'abstime' time.
108*062c5bc4SJason Schmidlapp  *
109*062c5bc4SJason Schmidlapp  * PARAMETERS
110*062c5bc4SJason Schmidlapp  *      sem
111*062c5bc4SJason Schmidlapp  *              pointer to an instance of sem_t
112*062c5bc4SJason Schmidlapp  *
113*062c5bc4SJason Schmidlapp  *      abstime
114*062c5bc4SJason Schmidlapp  *              pointer to an instance of struct timespec
115*062c5bc4SJason Schmidlapp  *
116*062c5bc4SJason Schmidlapp  * DESCRIPTION
117*062c5bc4SJason Schmidlapp  *      This function waits on a semaphore. If the
118*062c5bc4SJason Schmidlapp  *      semaphore value is greater than zero, it decreases
119*062c5bc4SJason Schmidlapp  *      its value by one. If the semaphore value is zero, then
120*062c5bc4SJason Schmidlapp  *      the calling thread (or process) is blocked until it can
121*062c5bc4SJason Schmidlapp  *      successfully decrease the value or until interrupted by
122*062c5bc4SJason Schmidlapp  *      a signal.
123*062c5bc4SJason Schmidlapp  *
124*062c5bc4SJason Schmidlapp  *      If 'abstime' is a NULL pointer then this function will
125*062c5bc4SJason Schmidlapp  *      block until it can successfully decrease the value or
126*062c5bc4SJason Schmidlapp  *      until interrupted by a signal.
127*062c5bc4SJason Schmidlapp  *
128*062c5bc4SJason Schmidlapp  * RESULTS
129*062c5bc4SJason Schmidlapp  *              0               successfully decreased semaphore,
130*062c5bc4SJason Schmidlapp  *              -1              failed, error in errno
131*062c5bc4SJason Schmidlapp  * ERRNO
132*062c5bc4SJason Schmidlapp  *              EINVAL          'sem' is not a valid semaphore,
133*062c5bc4SJason Schmidlapp  *              ENOSYS          semaphores are not supported,
134*062c5bc4SJason Schmidlapp  *              EINTR           the function was interrupted by a signal,
135*062c5bc4SJason Schmidlapp  *              EDEADLK         a deadlock condition was detected.
136*062c5bc4SJason Schmidlapp  *              ETIMEDOUT       abstime elapsed before success.
137*062c5bc4SJason Schmidlapp  *
138*062c5bc4SJason Schmidlapp  * ------------------------------------------------------
139*062c5bc4SJason Schmidlapp  */
140*062c5bc4SJason Schmidlapp {
141*062c5bc4SJason Schmidlapp   int result = 0;
142*062c5bc4SJason Schmidlapp   sem_t s = *sem;
143*062c5bc4SJason Schmidlapp 
144*062c5bc4SJason Schmidlapp 
145*062c5bc4SJason Schmidlapp   pthread_testcancel();
146*062c5bc4SJason Schmidlapp 
147*062c5bc4SJason Schmidlapp   if (sem == NULL)
148*062c5bc4SJason Schmidlapp     {
149*062c5bc4SJason Schmidlapp       result = EINVAL;
150*062c5bc4SJason Schmidlapp     }
151*062c5bc4SJason Schmidlapp   else
152*062c5bc4SJason Schmidlapp     {
153*062c5bc4SJason Schmidlapp       unsigned int milliseconds;
154*062c5bc4SJason Schmidlapp       unsigned int *pTimeout;
155*062c5bc4SJason Schmidlapp 
156*062c5bc4SJason Schmidlapp       if (abstime == NULL)
157*062c5bc4SJason Schmidlapp         {
158*062c5bc4SJason Schmidlapp           pTimeout = NULL;
159*062c5bc4SJason Schmidlapp         }
160*062c5bc4SJason Schmidlapp       else
161*062c5bc4SJason Schmidlapp         {
162*062c5bc4SJason Schmidlapp           /*
163*062c5bc4SJason Schmidlapp            * Calculate timeout as milliseconds from current system time.
164*062c5bc4SJason Schmidlapp            */
165*062c5bc4SJason Schmidlapp           milliseconds = pte_relmillisecs (abstime);
166*062c5bc4SJason Schmidlapp           pTimeout = &milliseconds;
167*062c5bc4SJason Schmidlapp         }
168*062c5bc4SJason Schmidlapp 
169*062c5bc4SJason Schmidlapp       if ((result = pthread_mutex_lock (&s->lock)) == 0)
170*062c5bc4SJason Schmidlapp         {
171*062c5bc4SJason Schmidlapp           int v;
172*062c5bc4SJason Schmidlapp 
173*062c5bc4SJason Schmidlapp           /* See sem_destroy.c
174*062c5bc4SJason Schmidlapp            */
175*062c5bc4SJason Schmidlapp           if (*sem == NULL)
176*062c5bc4SJason Schmidlapp             {
177*062c5bc4SJason Schmidlapp               (void) pthread_mutex_unlock (&s->lock);
178*062c5bc4SJason Schmidlapp               errno = EINVAL;
179*062c5bc4SJason Schmidlapp               return -1;
180*062c5bc4SJason Schmidlapp             }
181*062c5bc4SJason Schmidlapp 
182*062c5bc4SJason Schmidlapp           v = --s->value;
183*062c5bc4SJason Schmidlapp           (void) pthread_mutex_unlock (&s->lock);
184*062c5bc4SJason Schmidlapp 
185*062c5bc4SJason Schmidlapp           if (v < 0)
186*062c5bc4SJason Schmidlapp             {
187*062c5bc4SJason Schmidlapp 
188*062c5bc4SJason Schmidlapp               {
189*062c5bc4SJason Schmidlapp                 sem_timedwait_cleanup_args_t cleanup_args;
190*062c5bc4SJason Schmidlapp 
191*062c5bc4SJason Schmidlapp                 cleanup_args.sem = s;
192*062c5bc4SJason Schmidlapp                 cleanup_args.resultPtr = &result;
193*062c5bc4SJason Schmidlapp 
194*062c5bc4SJason Schmidlapp                 /* Must wait */
195*062c5bc4SJason Schmidlapp                 pthread_cleanup_push(pte_sem_timedwait_cleanup, (void *) &cleanup_args);
196*062c5bc4SJason Schmidlapp 
197*062c5bc4SJason Schmidlapp                 result = pte_cancellable_wait(s->sem,pTimeout);
198*062c5bc4SJason Schmidlapp 
199*062c5bc4SJason Schmidlapp                 pthread_cleanup_pop(result);
200*062c5bc4SJason Schmidlapp               }
201*062c5bc4SJason Schmidlapp             }
202*062c5bc4SJason Schmidlapp         }
203*062c5bc4SJason Schmidlapp 
204*062c5bc4SJason Schmidlapp     }
205*062c5bc4SJason Schmidlapp 
206*062c5bc4SJason Schmidlapp   if (result != 0)
207*062c5bc4SJason Schmidlapp     {
208*062c5bc4SJason Schmidlapp 
209*062c5bc4SJason Schmidlapp       errno = result;
210*062c5bc4SJason Schmidlapp       return -1;
211*062c5bc4SJason Schmidlapp 
212*062c5bc4SJason Schmidlapp     }
213*062c5bc4SJason Schmidlapp 
214*062c5bc4SJason Schmidlapp   return 0;
215*062c5bc4SJason Schmidlapp 
216*062c5bc4SJason Schmidlapp }				/* sem_timedwait */
217