Merge remote-tracking branch 'upstream/master'
[platform/upstream/freerdp.git] / winpr / libwinpr / synch / wait.c
1 /**
2  * WinPR: Windows Portable Runtime
3  * Synchronization Functions
4  *
5  * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #ifdef HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
27
28 #include <assert.h>
29
30 #include <winpr/crt.h>
31 #include <winpr/synch.h>
32
33 #include "synch.h"
34 #include "../thread/thread.h"
35 #include <winpr/thread.h>
36
37 /**
38  * WaitForSingleObject
39  * WaitForSingleObjectEx
40  * WaitForMultipleObjectsEx
41  * SignalObjectAndWait
42  */
43
44 #ifndef _WIN32
45
46 #include "../handle/handle.h"
47
48 static void ts_add_ms(struct timespec *ts, DWORD dwMilliseconds)
49 {
50         ts->tv_sec += dwMilliseconds / 1000L;
51         ts->tv_nsec += (dwMilliseconds % 1000L) * 1000000L;
52
53         while(ts->tv_nsec >= 1000000000L)
54         {
55                 ts->tv_sec ++;
56                 ts->tv_nsec -= 1000000000L;
57         }
58 }
59
60 DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)
61 {
62         ULONG Type;
63         PVOID Object;
64
65         if (!winpr_Handle_GetInfo(hHandle, &Type, &Object))
66                 return WAIT_FAILED;
67
68         if (Type == HANDLE_TYPE_THREAD)
69         {
70                 int status = 0;
71                 WINPR_THREAD* thread;
72                 void* thread_status = NULL;
73
74                 thread = (WINPR_THREAD*) Object;
75
76                 if (thread->started)
77                 {
78                         if (dwMilliseconds != INFINITE)
79                         {
80 #if _GNU_SOURCE
81                                 struct timespec timeout;
82
83                                 clock_gettime(CLOCK_REALTIME, &timeout);
84                                 ts_add_ms(&timeout, dwMilliseconds);
85
86                                 status = pthread_timedjoin_np(thread->thread, &thread_status, &timeout);
87 #else
88                                 fprintf(stderr, "[ERROR] %s: Thread timeouts not implemented.\n", __func__);
89                                 assert(0);
90 #endif
91                         }
92                         else
93                                 status = pthread_join(thread->thread, &thread_status);
94
95                         if (status != 0)
96                                 fprintf(stderr, "WaitForSingleObject: pthread_join failure: %d\n", status);
97
98                         if (thread_status)
99                                 thread->dwExitCode = ((DWORD) (size_t) thread_status);
100                 }
101         }
102         else if (Type == HANDLE_TYPE_MUTEX)
103         {
104                 WINPR_MUTEX* mutex;
105
106                 mutex = (WINPR_MUTEX*) Object;
107
108 #if _GNU_SOURCE
109                 if (dwMilliseconds != INFINITE)
110                 {
111                         struct timespec timeout;
112
113                         clock_gettime(CLOCK_REALTIME, &timeout);
114                         ts_add_ms(&timeout, dwMilliseconds);    
115
116                         pthread_mutex_timedlock(&mutex->mutex, &timeout);
117                 }
118                 else
119 #endif
120                 {
121                         pthread_mutex_lock(&mutex->mutex);
122                 }
123         }
124         else if (Type == HANDLE_TYPE_EVENT)
125         {
126                 int status;
127                 fd_set rfds;
128                 WINPR_EVENT* event;
129                 struct timeval timeout;
130
131                 event = (WINPR_EVENT*) Object;
132
133                 FD_ZERO(&rfds);
134                 FD_SET(event->pipe_fd[0], &rfds);
135                 ZeroMemory(&timeout, sizeof(timeout));
136
137                 if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0))
138                 {
139                         timeout.tv_usec = dwMilliseconds * 1000;
140                 }
141
142                 status = select(event->pipe_fd[0] + 1, &rfds, NULL, NULL,
143                                 (dwMilliseconds == INFINITE) ? NULL : &timeout);
144
145                 if (status < 0)
146                         return WAIT_FAILED;
147
148                 if (status != 1)
149                         return WAIT_TIMEOUT;
150         }
151         else if (Type == HANDLE_TYPE_SEMAPHORE)
152         {
153                 WINPR_SEMAPHORE* semaphore;
154
155                 semaphore = (WINPR_SEMAPHORE*) Object;
156
157 #ifdef WINPR_PIPE_SEMAPHORE
158                 if (semaphore->pipe_fd[0] != -1)
159                 {
160                         int status;
161                         int length;
162                         fd_set rfds;
163                         struct timeval timeout;
164
165                         FD_ZERO(&rfds);
166                         FD_SET(semaphore->pipe_fd[0], &rfds);
167                         ZeroMemory(&timeout, sizeof(timeout));
168
169                         if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0))
170                         {
171                                 timeout.tv_usec = dwMilliseconds * 1000;
172                         }
173
174                         status = select(semaphore->pipe_fd[0] + 1, &rfds, 0, 0,
175                                         (dwMilliseconds == INFINITE) ? NULL : &timeout);
176
177                         if (status < 0)
178                                 return WAIT_FAILED;
179
180                         if (status != 1)
181                                 return WAIT_TIMEOUT;
182
183                         length = read(semaphore->pipe_fd[0], &length, 1);
184
185                         if (length != 1)
186                                 return WAIT_FAILED;
187                 }
188 #else
189
190 #if defined __APPLE__
191                 semaphore_wait(*((winpr_sem_t*) semaphore->sem));
192 #else
193                 sem_wait((winpr_sem_t*) semaphore->sem);
194 #endif
195
196 #endif
197         }
198         else if (Type == HANDLE_TYPE_TIMER)
199         {
200                 WINPR_TIMER* timer;
201
202                 timer = (WINPR_TIMER*) Object;
203
204 #ifdef HAVE_EVENTFD_H
205                 if (timer->fd != -1)
206                 {
207                         int status;
208                         fd_set rfds;
209                         UINT64 expirations;
210                         struct timeval timeout;
211
212                         FD_ZERO(&rfds);
213                         FD_SET(timer->fd, &rfds);
214                         ZeroMemory(&timeout, sizeof(timeout));
215
216                         if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0))
217                         {
218                                 timeout.tv_usec = dwMilliseconds * 1000;
219                         }
220
221                         status = select(timer->fd + 1, &rfds, 0, 0,
222                                         (dwMilliseconds == INFINITE) ? NULL : &timeout);
223
224                         if (status < 0)
225                                 return WAIT_FAILED;
226
227                         if (status != 1)
228                                 return WAIT_TIMEOUT;
229
230                         status = read(timer->fd, (void*) &expirations, sizeof(UINT64));
231
232                         if (status != 8)
233                                 return WAIT_TIMEOUT;
234                 }
235                 else
236                 {
237                         return WAIT_FAILED;
238                 }
239 #else
240                 return WAIT_FAILED;
241 #endif
242         }
243         else
244         {
245                 fprintf(stderr, "WaitForSingleObject: unknown handle type %lu\n", Type);
246         }
247
248         return WAIT_OBJECT_0;
249 }
250
251 DWORD WaitForSingleObjectEx(HANDLE hHandle, DWORD dwMilliseconds, BOOL bAlertable)
252 {
253         fprintf(stderr, "[ERROR] %s: Function not implemented.\n", __func__);
254         assert(0);
255         return WAIT_OBJECT_0;
256 }
257
258 DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAll, DWORD dwMilliseconds)
259 {
260         int fd = -1;
261         int maxfd;
262         int index;
263         int status;
264         fd_set fds;
265         ULONG Type;
266         PVOID Object;
267         struct timeval timeout;
268
269         if (!nCount)
270                 return WAIT_FAILED;
271
272         maxfd = 0;
273         FD_ZERO(&fds);
274         ZeroMemory(&timeout, sizeof(timeout));
275
276         if (bWaitAll)
277         {
278                 fprintf(stderr, "WaitForMultipleObjects: bWaitAll not yet implemented\n");
279                 assert(0);
280         }
281
282         for (index = 0; index < nCount; index++)
283         {
284                 if (!winpr_Handle_GetInfo(lpHandles[index], &Type, &Object))
285                         return WAIT_FAILED;
286
287                 if (Type == HANDLE_TYPE_EVENT)
288                 {
289                         fd = ((WINPR_EVENT*) Object)->pipe_fd[0];
290                 }
291                 else if (Type == HANDLE_TYPE_SEMAPHORE)
292                 {
293 #ifdef WINPR_PIPE_SEMAPHORE
294                         fd = ((WINPR_SEMAPHORE*) Object)->pipe_fd[0];
295 #else
296                         return WAIT_FAILED;
297 #endif
298                 }
299                 else if (Type == HANDLE_TYPE_TIMER)
300                 {
301                         WINPR_TIMER* timer = (WINPR_TIMER*) Object;
302                         fd = timer->fd;
303                 }
304                 else
305                 {
306                         return WAIT_FAILED;
307                 }
308
309                 if (fd == -1)
310                         return WAIT_FAILED;
311
312                 FD_SET(fd, &fds);
313
314                 if (fd > maxfd)
315                         maxfd = fd;
316         }
317
318         if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0))
319         {
320                 timeout.tv_usec = dwMilliseconds * 1000;
321         }
322
323         status = select(maxfd + 1, &fds, 0, 0,
324                         (dwMilliseconds == INFINITE) ? NULL : &timeout);
325
326         if (status < 0)
327                 return WAIT_FAILED;
328
329         if (status == 0)
330                 return WAIT_TIMEOUT;
331
332         for (index = 0; index < nCount; index++)
333         {
334                 winpr_Handle_GetInfo(lpHandles[index], &Type, &Object);
335
336                 if (Type == HANDLE_TYPE_EVENT)
337                 {
338                         fd = ((WINPR_EVENT*) Object)->pipe_fd[0];
339                 }
340                 else if (Type == HANDLE_TYPE_SEMAPHORE)
341                 {
342                         fd = ((WINPR_SEMAPHORE*) Object)->pipe_fd[0];
343                 }
344                 else if (Type == HANDLE_TYPE_TIMER)
345                 {
346                         WINPR_TIMER* timer = (WINPR_TIMER*) Object;
347                         fd = timer->fd;
348                 }
349
350                 if (FD_ISSET(fd, &fds))
351                 {
352                         if (Type == HANDLE_TYPE_SEMAPHORE)
353                         {
354                                 int length;
355
356                                 length = read(fd, &length, 1);
357
358                                 if (length != 1)
359                                         return WAIT_FAILED;
360                         }
361                         else if (Type == HANDLE_TYPE_TIMER)
362                         {
363                                 int length;
364                                 UINT64 expirations;
365
366                                 length = read(fd, (void*) &expirations, sizeof(UINT64));
367
368                                 if (length != 8)
369                                         return WAIT_FAILED;
370                         }
371
372                         return (WAIT_OBJECT_0 + index);
373                 }
374         }
375
376         return WAIT_FAILED;
377 }
378
379 DWORD WaitForMultipleObjectsEx(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAll, DWORD dwMilliseconds, BOOL bAlertable)
380 {
381         fprintf(stderr, "[ERROR] %s: Function not implemented.\n", __func__);
382         assert(0);
383         return 0;
384 }
385
386 DWORD SignalObjectAndWait(HANDLE hObjectToSignal, HANDLE hObjectToWaitOn, DWORD dwMilliseconds, BOOL bAlertable)
387 {
388         fprintf(stderr, "[ERROR] %s: Function not implemented.\n", __func__);
389         assert(0);
390         return 0;
391 }
392
393 #endif