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