/* cygwait.h Copyright 2011, 2012 Red Hat, Inc. 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_return (mask & cw_sig_return) #define is_cw_sig_handle (mask & (is_cw_sig | is_cw_sig_eintr)) DWORD cancelable_wait (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; DWORD sig_n; if (!is_cw_sig_handle) sig_n = WAIT_TIMEOUT + 1; else { sig_n = WAIT_OBJECT_0 + num++; wait_objects[sig_n] = signal_arrived; } 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); if (res == cancel_n) res = WAIT_CANCELED; else if (res == timeout_n) res = WAIT_TIMEOUT; else if (res != sig_n) /* all set */; else if (is_cw_sig_eintr) res = WAIT_SIGNALED; /* caller will deal with signals */ else if (_my_tls.call_signal_handler () || &_my_tls != _main_tls) continue; 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; }