~mingw-w64/pthreads-w32/w64-patch

552 by rpj
''
1
/*
2
 * -------------------------------------------------------------
3
 *
4
 * Module: sem_timedwait.c
5
 *
6
 * Purpose:
7
 *	Semaphores aren't actually part of the PThreads standard.
8
 *	They are defined by the POSIX Standard:
9
 *
10
 *		POSIX 1003.1b-1993	(POSIX.1b)
11
 *
12
 * -------------------------------------------------------------
13
 *
14
 * --------------------------------------------------------------------------
15
 *
16
 *      Pthreads-win32 - POSIX Threads Library for Win32
17
 *      Copyright(C) 1998 John E. Bossom
18
 *      Copyright(C) 1999,2005 Pthreads-win32 contributors
19
 * 
20
 *      Contact Email: rpj@callisto.canberra.edu.au
21
 * 
22
 *      The current list of contributors is contained
23
 *      in the file CONTRIBUTORS included with the source
24
 *      code distribution. The list can also be seen at the
25
 *      following World Wide Web location:
26
 *      http://sources.redhat.com/pthreads-win32/contributors.html
27
 * 
28
 *      This library is free software; you can redistribute it and/or
29
 *      modify it under the terms of the GNU Lesser General Public
30
 *      License as published by the Free Software Foundation; either
31
 *      version 2 of the License, or (at your option) any later version.
32
 * 
33
 *      This library is distributed in the hope that it will be useful,
34
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
35
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
36
 *      Lesser General Public License for more details.
37
 * 
38
 *      You should have received a copy of the GNU Lesser General Public
39
 *      License along with this library in the file COPYING.LIB;
40
 *      if not, write to the Free Software Foundation, Inc.,
41
 *      59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
42
 */
43
44
#include "pthread.h"
45
#include "semaphore.h"
46
#include "implement.h"
47
48
49
typedef struct {
50
  sem_t sem;
51
  int * resultPtr;
52
} sem_timedwait_cleanup_args_t;
53
54
55
static void PTW32_CDECL
56
ptw32_sem_timedwait_cleanup (void * args)
57
{
58
  sem_timedwait_cleanup_args_t * a = (sem_timedwait_cleanup_args_t *)args;
59
  sem_t s = a->sem;
60
61
  if (pthread_mutex_lock (&s->lock) == 0)
62
    {
63
      /*
64
       * We either timed out or were cancelled.
557 by rpj
''
65
       * If someone has posted between then and now we try to take the semaphore.
552 by rpj
''
66
       * Otherwise the semaphore count may be wrong after we
67
       * return. In the case of a cancellation, it is as if we
68
       * were cancelled just before we return (after taking the semaphore)
69
       * which is ok.
70
       */
71
      if (WaitForSingleObject(s->sem, 0) == WAIT_OBJECT_0)
72
	{
73
	  /* We got the semaphore on the second attempt */
74
	  *(a->resultPtr) = 0;
75
	}
76
      else
77
	{
78
	  /* Indicate we're no longer waiting */
79
	  s->value++;
80
#ifdef NEED_SEM
81
	  if (s->value > 0)
82
	    {
83
	      s->leftToUnblock = 0;
84
	    }
85
#else
86
          /*
87
           * Don't release the W32 sema, it doesn't need adjustment
88
           * because it doesn't record the number of waiters.
89
           */
90
#endif
91
	}
92
      (void) pthread_mutex_unlock (&s->lock);
93
    }
94
}
95
96
97
int
98
sem_timedwait (sem_t * sem, const struct timespec *abstime)
99
     /*
100
      * ------------------------------------------------------
101
      * DOCPUBLIC
102
      *      This function waits on a semaphore possibly until
103
      *      'abstime' time.
104
      *
105
      * PARAMETERS
106
      *      sem
107
      *              pointer to an instance of sem_t
108
      *
109
      *      abstime
110
      *              pointer to an instance of struct timespec
111
      *
112
      * DESCRIPTION
113
      *      This function waits on a semaphore. If the
114
      *      semaphore value is greater than zero, it decreases
115
      *      its value by one. If the semaphore value is zero, then
116
      *      the calling thread (or process) is blocked until it can
117
      *      successfully decrease the value or until interrupted by
118
      *      a signal.
119
      *
120
      *      If 'abstime' is a NULL pointer then this function will
121
      *      block until it can successfully decrease the value or
122
      *      until interrupted by a signal.
123
      *
124
      * RESULTS
125
      *              0               successfully decreased semaphore,
126
      *              -1              failed, error in errno
127
      * ERRNO
128
      *              EINVAL          'sem' is not a valid semaphore,
129
      *              ENOSYS          semaphores are not supported,
130
      *              EINTR           the function was interrupted by a signal,
131
      *              EDEADLK         a deadlock condition was detected.
132
      *              ETIMEDOUT       abstime elapsed before success.
133
      *
134
      * ------------------------------------------------------
135
      */
136
{
137
  int result = 0;
138
  sem_t s = *sem;
139
605 by rpj
''
140
  pthread_testcancel();
141
552 by rpj
''
142
  if (sem == NULL)
143
    {
144
      result = EINVAL;
145
    }
146
  else
147
    {
148
      DWORD milliseconds;
149
150
      if (abstime == NULL)
151
	{
152
	  milliseconds = INFINITE;
153
	}
154
      else
155
	{
156
	  /* 
157
	   * Calculate timeout as milliseconds from current system time. 
158
	   */
159
	  milliseconds = ptw32_relmillisecs (abstime);
160
	}
161
162
      if ((result = pthread_mutex_lock (&s->lock)) == 0)
163
	{
605 by rpj
''
164
	  int v;
165
166
	  /* See sem_destroy.c
167
	   */
168
	  if (*sem == NULL)
169
	    {
170
	      (void) pthread_mutex_unlock (&s->lock);
171
	      errno = EINVAL;
172
	      return -1;
173
	    }
174
175
	  v = --s->value;
552 by rpj
''
176
	  (void) pthread_mutex_unlock (&s->lock);
177
178
	  if (v < 0)
179
	    {
180
#ifdef NEED_SEM
181
	      int timedout;
182
#endif
183
	      sem_timedwait_cleanup_args_t cleanup_args;
184
185
	      cleanup_args.sem = s;
186
	      cleanup_args.resultPtr = &result;
187
188
#ifdef _MSC_VER
189
#pragma inline_depth(0)
190
#endif
191
	      /* Must wait */
192
              pthread_cleanup_push(ptw32_sem_timedwait_cleanup, (void *) &cleanup_args);
193
#ifdef NEED_SEM
194
	      timedout =
195
#endif
196
	      result = pthreadCancelableTimedWait (s->sem, milliseconds);
197
	      pthread_cleanup_pop(result);
198
#ifdef _MSC_VER
199
#pragma inline_depth()
200
#endif
201
202
#ifdef NEED_SEM
203
204
	      if (!timedout && pthread_mutex_lock (&s->lock) == 0)
205
	        {
605 by rpj
''
206
        	  if (*sem == NULL)
207
        	    {
208
        	      (void) pthread_mutex_unlock (&s->lock);
209
        	      errno = EINVAL;
210
        	      return -1;
211
        	    }
212
552 by rpj
''
213
	          if (s->leftToUnblock > 0)
214
	            {
215
		      --s->leftToUnblock;
216
		      SetEvent(s->sem);
217
		    }
218
	          (void) pthread_mutex_unlock (&s->lock);
219
	        }
220
221
#endif /* NEED_SEM */
222
223
	    }
224
	}
225
226
    }
227
228
  if (result != 0)
229
    {
230
231
      errno = result;
232
      return -1;
233
234
    }
235
236
  return 0;
237
238
}				/* sem_timedwait */