/* cygwait.h This file is part of Cygwin. This software is a copyrighted work licensed under the terms of the Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include "winsup.h" #include "sigproc.h" #include "cygwait.h" #include "ntdll.h" #define is_cw_cancel (mask & cw_cancel) #define is_cw_cancel_self (mask & cw_cancel_self) #define is_cw_sig (mask & cw_sig) #define is_cw_sig_eintr (mask & cw_sig_eintr) #define is_cw_sig_cont (mask & cw_sig_cont) #define is_cw_sig_restart (mask & cw_sig_restart) #define is_cw_sig_handle (mask & (cw_sig | cw_sig_eintr \ | cw_sig_cont | cw_sig_restart)) LARGE_INTEGER cw_nowait_storage; DWORD cygwait (HANDLE object, PLARGE_INTEGER timeout, unsigned mask) { DWORD res; DWORD num = 0; HANDLE wait_objects[4]; pthread_t thread = pthread::self (); /* Do not change the wait order. The object must have higher priority than the cancel event, because WaitForMultipleObjects will return the smallest index if both objects are signaled. */ if (object) wait_objects[num++] = object; wait_signal_arrived thread_waiting (is_cw_sig_handle, wait_objects[num]); debug_only_printf ("object %p, thread waiting %d, signal_arrived %p", object, (int) thread_waiting, _my_tls.signal_arrived); DWORD sig_n; if (!thread_waiting) sig_n = WAIT_TIMEOUT + 1; else sig_n = WAIT_OBJECT_0 + num++; DWORD cancel_n; if (!is_cw_cancel || !pthread::is_good_object (&thread) || thread->cancelstate == PTHREAD_CANCEL_DISABLE) cancel_n = WAIT_TIMEOUT + 1; else { cancel_n = WAIT_OBJECT_0 + num++; wait_objects[cancel_n] = thread->cancel_event; } DWORD timeout_n; if (!timeout) timeout_n = WAIT_TIMEOUT + 1; else { timeout_n = WAIT_OBJECT_0 + num++; if (!_my_tls.locals.cw_timer) NtCreateTimer (&_my_tls.locals.cw_timer, TIMER_ALL_ACCESS, NULL, NotificationTimer); NtSetTimer (_my_tls.locals.cw_timer, timeout, NULL, NULL, FALSE, 0, NULL); wait_objects[timeout_n] = _my_tls.locals.cw_timer; } while (1) { res = WaitForMultipleObjects (num, wait_objects, FALSE, INFINITE); debug_only_printf ("res %d", res); if (res == cancel_n) res = WAIT_CANCELED; else if (res == timeout_n) res = WAIT_TIMEOUT; else if (res != sig_n) /* all set */; else { int sig = _my_tls.sig; if (is_cw_sig_cont && sig == SIGCONT) _my_tls.sig = 0; if (!sig) continue; if (is_cw_sig_eintr || (is_cw_sig_cont && sig == SIGCONT)) ; else if (_my_tls.call_signal_handler () || is_cw_sig_restart) continue; res = WAIT_SIGNALED; /* caller will deal with signals */ } break; } if (timeout) { TIMER_BASIC_INFORMATION tbi; NtQueryTimer (_my_tls.locals.cw_timer, TimerBasicInformation, &tbi, sizeof tbi, NULL); /* if timer expired, TimeRemaining is negative and represents the system uptime when signalled */ if (timeout->QuadPart < 0LL) timeout->QuadPart = tbi.SignalState ? 0LL : tbi.TimeRemaining.QuadPart; NtCancelTimer (_my_tls.locals.cw_timer, NULL); } if (res == WAIT_CANCELED && is_cw_cancel_self) pthread::static_cancel_self (); return res; }