21#include <winpr/config.h>
23#ifdef WINPR_HAVE_UNISTD_H
27#include <winpr/assert.h>
31#include <winpr/synch.h>
32#include <winpr/platform.h>
33#include <winpr/sysinfo.h>
37#include "../thread/thread.h"
38#include <winpr/thread.h>
39#include <winpr/debug.h>
42#define TAG WINPR_TAG("sync.wait")
58#include "../handle/handle.h"
60#include "../pipe/pipe.h"
62static struct timespec ts_from_ns(void)
64 const UINT64 ns = winpr_GetUnixTimeNS();
65 struct timespec timeout = WINPR_C_ARRAY_INIT;
66 timeout.tv_sec = WINPR_TIME_NS_TO_S(ns);
67 timeout.tv_nsec = WINPR_TIME_NS_REM_NS(ns);
76#if !defined(WINPR_HAVE_PTHREAD_MUTEX_TIMEDLOCK)
79static long long ts_difftime(
const struct timespec* o,
const struct timespec* n)
81 long long oldValue = o->tv_sec * 1000000000LL + o->tv_nsec;
82 long long newValue = n->tv_sec * 1000000000LL + n->tv_nsec;
83 return newValue - oldValue;
87#if (__ANDROID_API__ >= 21)
88#define CONST_NEEDED const
94#define CONST_NEEDED const
95#define STATIC_NEEDED static
98STATIC_NEEDED
int pthread_mutex_timedlock(pthread_mutex_t* mutex,
99 CONST_NEEDED
struct timespec* timeout)
101 struct timespec timenow = WINPR_C_ARRAY_INIT;
102 struct timespec sleepytime = WINPR_C_ARRAY_INIT;
103 unsigned long long diff = 0;
106 timenow = ts_from_ns();
107 diff = ts_difftime(&timenow, timeout);
108 sleepytime.tv_sec = diff / 1000000000LL;
109 sleepytime.tv_nsec = diff % 1000000000LL;
111 while ((retcode = pthread_mutex_trylock(mutex)) == EBUSY)
113 timenow = ts_from_ns();
115 if (ts_difftime(timeout, &timenow) >= 0)
120 nanosleep(&sleepytime,
nullptr);
127static void ts_add_ms(
struct timespec* ts, DWORD dwMilliseconds)
129 ts->tv_sec += dwMilliseconds / 1000L;
130 ts->tv_nsec += (dwMilliseconds % 1000L) * 1000000L;
131 ts->tv_sec += ts->tv_nsec / 1000000000L;
132 ts->tv_nsec = ts->tv_nsec % 1000000000L;
135DWORD WaitForSingleObjectEx(HANDLE hHandle, DWORD dwMilliseconds, BOOL bAlertable)
139 WINPR_POLL_SET pollset = WINPR_C_ARRAY_INIT;
141 if (!winpr_Handle_GetInfo(hHandle, &Type, &Object))
143 WLog_ERR(TAG,
"invalid hHandle.");
144 SetLastError(ERROR_INVALID_HANDLE);
148 if (Type == HANDLE_TYPE_PROCESS && winpr_Handle_getFd(hHandle) == -1)
157 int ret = waitpid(process->pid, &(process->status), WNOHANG);
158 if (ret == process->pid)
160 if (WIFEXITED(process->status))
161 process->dwExitCode = (DWORD)WEXITSTATUS(process->status);
162 else if (WIFSIGNALED(process->status))
163 process->dwExitCode = (DWORD)(128 + WTERMSIG(process->status));
165 process->dwExitCode = (DWORD)process->status;
166 return WAIT_OBJECT_0;
170 char ebuffer[256] = WINPR_C_ARRAY_INIT;
171 WLog_ERR(TAG,
"waitpid failure [%d] %s", errno,
172 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
173 SetLastError(ERROR_INTERNAL_ERROR);
177 if (dwMilliseconds == 0)
181 DWORD waitDelay = 50;
182 if (dwMilliseconds != INFINITE)
184 if (dwMilliseconds < 50)
185 waitDelay = dwMilliseconds;
186 dwMilliseconds -= waitDelay;
189 DWORD status = SleepEx(waitDelay, bAlertable);
195 if (Type == HANDLE_TYPE_MUTEX)
197 WINPR_MUTEX* mutex = (WINPR_MUTEX*)Object;
199 if (dwMilliseconds != INFINITE)
202 struct timespec timeout = ts_from_ns();
204 ts_add_ms(&timeout, dwMilliseconds);
205 status = pthread_mutex_timedlock(&mutex->mutex, &timeout);
207 if (ETIMEDOUT == status)
212 pthread_mutex_lock(&mutex->mutex);
215 return WAIT_OBJECT_0;
220 WINPR_THREAD* thread =
nullptr;
224 BOOL autoSignaled = FALSE;
228 thread = (WINPR_THREAD*)_GetCurrentThread();
233 if (thread->apc.treatingCompletions)
236 extraFds = thread->apc.length;
245 int fd = winpr_Handle_getFd(Object);
248 WLog_ERR(TAG,
"winpr_Handle_getFd did not return a fd!");
249 SetLastError(ERROR_INVALID_HANDLE);
253 if (!pollset_init(&pollset, 1 + extraFds))
255 WLog_ERR(TAG,
"unable to initialize pollset");
256 SetLastError(ERROR_INTERNAL_ERROR);
260 if (!pollset_add(&pollset, fd, Object->Mode))
262 WLog_ERR(TAG,
"unable to add fd in pollset");
266 if (bAlertable && !apc_collectFds(thread, &pollset, &autoSignaled))
268 WLog_ERR(TAG,
"unable to collect APC fds");
274 status = pollset_poll(&pollset, dwMilliseconds);
277 char ebuffer[256] = WINPR_C_ARRAY_INIT;
278 WLog_ERR(TAG,
"pollset_poll() failure [%d] %s", errno,
279 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
285 if (bAlertable && apc_executeCompletions(thread, &pollset, 1))
286 ret = WAIT_IO_COMPLETION;
288 isSet = pollset_isSignaled(&pollset, 0);
289 pollset_uninit(&pollset);
294 return winpr_Handle_cleanup(Object);
298 pollset_uninit(&pollset);
299 SetLastError(ERROR_INTERNAL_ERROR);
303DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)
305 return WaitForSingleObjectEx(hHandle, dwMilliseconds, FALSE);
308DWORD WaitForMultipleObjectsEx(DWORD nCount,
const HANDLE* lpHandles, BOOL bWaitAll,
309 DWORD dwMilliseconds, BOOL bAlertable)
313 DWORD poll_map[MAXIMUM_WAIT_OBJECTS] = WINPR_C_ARRAY_INIT;
314 BOOL signalled_handles[MAXIMUM_WAIT_OBJECTS] = { FALSE };
319 WINPR_THREAD* thread =
nullptr;
320 WINPR_POLL_SET pollset = WINPR_C_ARRAY_INIT;
321 DWORD ret = WAIT_FAILED;
326 if (!nCount || (nCount > MAXIMUM_WAIT_OBJECTS))
328 WLog_ERR(TAG,
"invalid handles count(%" PRIu32
")", nCount);
334 thread = winpr_GetCurrentThread();
339 if (thread->apc.treatingCompletions)
342 extraFds = thread->apc.length;
351 if (!pollset_init(&pollset, nCount + extraFds))
353 WLog_ERR(TAG,
"unable to initialize pollset for nCount=%" PRIu32
" extraCount=%" PRIuz
"",
360 now = GetTickCount64();
361 if (dwMilliseconds != INFINITE)
362 dueTime = now + dwMilliseconds;
364 dueTime = 0xFFFFFFFFFFFFFFFF;
368 BOOL autoSignaled = FALSE;
373 for (; idx < nCount; idx++)
377 if (signalled_handles[idx])
380 poll_map[polled] = idx;
383 if (!winpr_Handle_GetInfo(lpHandles[idx], &Type, &Object))
385 WLog_ERR(TAG,
"invalid event file descriptor at %" PRIu32, idx);
386 winpr_log_backtrace(TAG, WLOG_ERROR, 20);
387 SetLastError(ERROR_INVALID_HANDLE);
391 fd = winpr_Handle_getFd(Object);
394 WLog_ERR(TAG,
"invalid file descriptor at %" PRIu32, idx);
395 winpr_log_backtrace(TAG, WLOG_ERROR, 20);
396 SetLastError(ERROR_INVALID_HANDLE);
400 if (!pollset_add(&pollset, fd, Object->Mode))
402 WLog_ERR(TAG,
"unable to register fd in pollset at %" PRIu32, idx);
403 winpr_log_backtrace(TAG, WLOG_ERROR, 20);
404 SetLastError(ERROR_INVALID_HANDLE);
412 if (bAlertable && !apc_collectFds(thread, &pollset, &autoSignaled))
414 WLog_ERR(TAG,
"unable to register APC fds");
415 winpr_log_backtrace(TAG, WLOG_ERROR, 20);
416 SetLastError(ERROR_INTERNAL_ERROR);
426 if (dwMilliseconds == INFINITE)
429 waitTime = (DWORD)(dueTime - now);
431 status = pollset_poll(&pollset, waitTime);
434 char ebuffer[256] = WINPR_C_ARRAY_INIT;
435#ifdef WINPR_HAVE_POLL_H
436 WLog_ERR(TAG,
"poll() handle %" PRIu32
" (%" PRIu32
") failure [%d] %s", idx,
437 nCount, errno, winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
439 WLog_ERR(TAG,
"select() handle %" PRIu32
" (%" PRIu32
") failure [%d] %s", idx,
440 nCount, errno, winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
442 winpr_log_backtrace(TAG, WLOG_ERROR, 20);
443 SetLastError(ERROR_INTERNAL_ERROR);
449 if (bAlertable && apc_executeCompletions(thread, &pollset, polled))
451 ret = WAIT_IO_COMPLETION;
458 for (DWORD index = 0; index < polled; index++)
460 DWORD handlesIndex = 0;
461 BOOL signal_set = FALSE;
464 handlesIndex = poll_map[index];
466 handlesIndex = index;
468 signal_set = pollset_isSignaled(&pollset, index);
471 DWORD rc = winpr_Handle_cleanup(lpHandles[handlesIndex]);
472 if (rc != WAIT_OBJECT_0)
474 WLog_ERR(TAG,
"error in cleanup function for handle at index=%" PRIu32,
482 signalled_handles[handlesIndex] = TRUE;
485 for (; signalled < nCount; signalled++)
487 if (!signalled_handles[signalled])
493 ret = (WAIT_OBJECT_0 + handlesIndex);
497 if (signalled >= nCount)
506 if (bAlertable && thread->apc.length > extraFds)
508 pollset_uninit(&pollset);
509 extraFds = thread->apc.length;
510 if (!pollset_init(&pollset, nCount + extraFds))
512 WLog_ERR(TAG,
"unable reallocate pollset");
513 SetLastError(ERROR_INTERNAL_ERROR);
518 pollset_reset(&pollset);
520 now = GetTickCount64();
521 }
while (now < dueTime);
526 pollset_uninit(&pollset);
530DWORD WaitForMultipleObjects(DWORD nCount,
const HANDLE* lpHandles, BOOL bWaitAll,
531 DWORD dwMilliseconds)
533 return WaitForMultipleObjectsEx(nCount, lpHandles, bWaitAll, dwMilliseconds, FALSE);
536DWORD SignalObjectAndWait(HANDLE hObjectToSignal, HANDLE hObjectToWaitOn, DWORD dwMilliseconds,
539 if (!SetEvent(hObjectToSignal))
542 return WaitForSingleObjectEx(hObjectToWaitOn, dwMilliseconds, bAlertable);