Merge pull request #1447 from hardening/server-side-rail
[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 HAVE_PTHREAD_GNU_EXT
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] %s\n",
97                                                 status, strerror(status));
98
99                         if (thread_status)
100                                 thread->dwExitCode = ((DWORD) (size_t) thread_status);
101                 }
102         }
103         else if (Type == HANDLE_TYPE_MUTEX)
104         {
105                 WINPR_MUTEX* mutex;
106
107                 mutex = (WINPR_MUTEX*) Object;
108
109 #if HAVE_PTHREAD_GNU_EXT
110                 if (dwMilliseconds != INFINITE)
111                 {
112                         struct timespec timeout;
113
114                         clock_gettime(CLOCK_REALTIME, &timeout);
115                         ts_add_ms(&timeout, dwMilliseconds);    
116
117                         pthread_mutex_timedlock(&mutex->mutex, &timeout);
118                 }
119                 else
120 #endif
121                 {
122                         pthread_mutex_lock(&mutex->mutex);
123                 }
124         }
125         else if (Type == HANDLE_TYPE_EVENT)
126         {
127                 int status;
128                 fd_set rfds;
129                 WINPR_EVENT* event;
130                 struct timeval timeout;
131
132                 event = (WINPR_EVENT*) Object;
133
134                 FD_ZERO(&rfds);
135                 FD_SET(event->pipe_fd[0], &rfds);
136                 ZeroMemory(&timeout, sizeof(timeout));
137
138                 if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0))
139                 {
140                         timeout.tv_usec = dwMilliseconds * 1000;
141                 }
142
143                 status = select(event->pipe_fd[0] + 1, &rfds, NULL, NULL,
144                                 (dwMilliseconds == INFINITE) ? NULL : &timeout);
145
146                 if (status < 0)
147                         return WAIT_FAILED;
148
149                 if (status != 1)
150                         return WAIT_TIMEOUT;
151         }
152         else if (Type == HANDLE_TYPE_SEMAPHORE)
153         {
154                 WINPR_SEMAPHORE* semaphore;
155
156                 semaphore = (WINPR_SEMAPHORE*) Object;
157
158 #ifdef WINPR_PIPE_SEMAPHORE
159                 if (semaphore->pipe_fd[0] != -1)
160                 {
161                         int status;
162                         int length;
163                         fd_set rfds;
164                         struct timeval timeout;
165
166                         FD_ZERO(&rfds);
167                         FD_SET(semaphore->pipe_fd[0], &rfds);
168                         ZeroMemory(&timeout, sizeof(timeout));
169
170                         if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0))
171                         {
172                                 timeout.tv_usec = dwMilliseconds * 1000;
173                         }
174
175                         status = select(semaphore->pipe_fd[0] + 1, &rfds, 0, 0,
176                                         (dwMilliseconds == INFINITE) ? NULL : &timeout);
177
178                         if (status < 0)
179                                 return WAIT_FAILED;
180
181                         if (status != 1)
182                                 return WAIT_TIMEOUT;
183
184                         length = read(semaphore->pipe_fd[0], &length, 1);
185
186                         if (length != 1)
187                                 return WAIT_FAILED;
188                 }
189 #else
190
191 #if defined __APPLE__
192                 semaphore_wait(*((winpr_sem_t*) semaphore->sem));
193 #else
194                 sem_wait((winpr_sem_t*) semaphore->sem);
195 #endif
196
197 #endif
198         }
199         else if (Type == HANDLE_TYPE_TIMER)
200         {
201                 WINPR_TIMER* timer;
202
203                 timer = (WINPR_TIMER*) Object;
204
205 #ifdef HAVE_EVENTFD_H
206                 if (timer->fd != -1)
207                 {
208                         int status;
209                         fd_set rfds;
210                         UINT64 expirations;
211                         struct timeval timeout;
212
213                         FD_ZERO(&rfds);
214                         FD_SET(timer->fd, &rfds);
215                         ZeroMemory(&timeout, sizeof(timeout));
216
217                         if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0))
218                         {
219                                 timeout.tv_usec = dwMilliseconds * 1000;
220                         }
221
222                         status = select(timer->fd + 1, &rfds, 0, 0,
223                                         (dwMilliseconds == INFINITE) ? NULL : &timeout);
224
225                         if (status < 0)
226                                 return WAIT_FAILED;
227
228                         if (status != 1)
229                                 return WAIT_TIMEOUT;
230
231                         status = read(timer->fd, (void*) &expirations, sizeof(UINT64));
232
233                         if (status != 8)
234                                 return WAIT_TIMEOUT;
235                 }
236                 else
237                 {
238                         return WAIT_FAILED;
239                 }
240 #else
241                 return WAIT_FAILED;
242 #endif
243         }
244         else
245         {
246                 fprintf(stderr, "WaitForSingleObject: unknown handle type %lu\n", Type);
247         }
248
249         return WAIT_OBJECT_0;
250 }
251
252 DWORD WaitForSingleObjectEx(HANDLE hHandle, DWORD dwMilliseconds, BOOL bAlertable)
253 {
254         fprintf(stderr, "[ERROR] %s: Function not implemented.\n", __func__);
255         assert(0);
256         return WAIT_OBJECT_0;
257 }
258
259 DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAll, DWORD dwMilliseconds)
260 {
261         int fd = -1;
262         int maxfd;
263         int index;
264         int status;
265         fd_set fds;
266         ULONG Type;
267         PVOID Object;
268         struct timeval timeout;
269
270         if (!nCount)
271                 return WAIT_FAILED;
272
273         maxfd = 0;
274         FD_ZERO(&fds);
275         ZeroMemory(&timeout, sizeof(timeout));
276
277         if (bWaitAll)
278         {
279                 fprintf(stderr, "WaitForMultipleObjects: bWaitAll not yet implemented\n");
280                 assert(0);
281         }
282
283         for (index = 0; index < nCount; index++)
284         {
285                 if (!winpr_Handle_GetInfo(lpHandles[index], &Type, &Object))
286                         return WAIT_FAILED;
287
288                 if (Type == HANDLE_TYPE_EVENT)
289                 {
290                         fd = ((WINPR_EVENT*) Object)->pipe_fd[0];
291                 }
292                 else if (Type == HANDLE_TYPE_SEMAPHORE)
293                 {
294 #ifdef WINPR_PIPE_SEMAPHORE
295                         fd = ((WINPR_SEMAPHORE*) Object)->pipe_fd[0];
296 #else
297                         return WAIT_FAILED;
298 #endif
299                 }
300                 else if (Type == HANDLE_TYPE_TIMER)
301                 {
302                         WINPR_TIMER* timer = (WINPR_TIMER*) Object;
303                         fd = timer->fd;
304                 }
305                 else
306                 {
307                         return WAIT_FAILED;
308                 }
309
310                 if (fd == -1)
311                         return WAIT_FAILED;
312
313                 FD_SET(fd, &fds);
314
315                 if (fd > maxfd)
316                         maxfd = fd;
317         }
318
319         if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0))
320         {
321                 timeout.tv_usec = dwMilliseconds * 1000;
322         }
323
324         status = select(maxfd + 1, &fds, 0, 0,
325                         (dwMilliseconds == INFINITE) ? NULL : &timeout);
326
327         if (status < 0)
328                 return WAIT_FAILED;
329
330         if (status == 0)
331                 return WAIT_TIMEOUT;
332
333         for (index = 0; index < nCount; index++)
334         {
335                 winpr_Handle_GetInfo(lpHandles[index], &Type, &Object);
336
337                 if (Type == HANDLE_TYPE_EVENT)
338                 {
339                         fd = ((WINPR_EVENT*) Object)->pipe_fd[0];
340                 }
341                 else if (Type == HANDLE_TYPE_SEMAPHORE)
342                 {
343                         fd = ((WINPR_SEMAPHORE*) Object)->pipe_fd[0];
344                 }
345                 else if (Type == HANDLE_TYPE_TIMER)
346                 {
347                         WINPR_TIMER* timer = (WINPR_TIMER*) Object;
348                         fd = timer->fd;
349                 }
350
351                 if (FD_ISSET(fd, &fds))
352                 {
353                         if (Type == HANDLE_TYPE_SEMAPHORE)
354                         {
355                                 int length;
356
357                                 length = read(fd, &length, 1);
358
359                                 if (length != 1)
360                                         return WAIT_FAILED;
361                         }
362                         else if (Type == HANDLE_TYPE_TIMER)
363                         {
364                                 int length;
365                                 UINT64 expirations;
366
367                                 length = read(fd, (void*) &expirations, sizeof(UINT64));
368
369                                 if (length != 8)
370                                         return WAIT_FAILED;
371                         }
372
373                         return (WAIT_OBJECT_0 + index);
374                 }
375         }
376
377         return WAIT_FAILED;
378 }
379
380 DWORD WaitForMultipleObjectsEx(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAll, DWORD dwMilliseconds, BOOL bAlertable)
381 {
382         fprintf(stderr, "[ERROR] %s: Function not implemented.\n", __func__);
383         assert(0);
384         return 0;
385 }
386
387 DWORD SignalObjectAndWait(HANDLE hObjectToSignal, HANDLE hObjectToWaitOn, DWORD dwMilliseconds, BOOL bAlertable)
388 {
389         fprintf(stderr, "[ERROR] %s: Function not implemented.\n", __func__);
390         assert(0);
391         return 0;
392 }
393
394 #endif