]>
Commit | Line | Data |
---|---|---|
4ae63783 CF |
1 | /* cygwait.h |
2 | ||
3 | Copyright 2011, 2012 Red Hat, Inc. | |
4 | ||
5 | This file is part of Cygwin. | |
6 | ||
7 | This software is a copyrighted work licensed under the terms of the | |
8 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
9 | details. */ | |
10 | ||
11 | #include "winsup.h" | |
12 | #include "sigproc.h" | |
13 | #include "cygwait.h" | |
14 | #include "ntdll.h" | |
15 | ||
16 | #define is_cw_cancel (mask & cw_cancel) | |
17 | #define is_cw_cancel_self (mask & cw_cancel_self) | |
18 | #define is_cw_sig (mask & cw_sig) | |
19 | #define is_cw_sig_eintr (mask & cw_sig_eintr) | |
20 | #define is_cw_sig_return (mask & cw_sig_return) | |
21 | ||
22 | #define is_cw_sig_handle (mask & (is_cw_sig | is_cw_sig_eintr)) | |
23 | ||
962f9a2c CF |
24 | LARGE_INTEGER cw_nowait_storage; |
25 | ||
4ae63783 CF |
26 | DWORD |
27 | cancelable_wait (HANDLE object, PLARGE_INTEGER timeout, unsigned mask) | |
28 | { | |
29 | DWORD res; | |
30 | DWORD num = 0; | |
31 | HANDLE wait_objects[4]; | |
32 | pthread_t thread = pthread::self (); | |
33 | ||
34 | /* Do not change the wait order. | |
35 | The object must have higher priority than the cancel event, | |
36 | because WaitForMultipleObjects will return the smallest index | |
37 | if both objects are signaled. */ | |
38 | if (object) | |
39 | wait_objects[num++] = object; | |
40 | ||
962f9a2c CF |
41 | set_thread_waiting thread_waiting (is_cw_sig_handle, wait_objects[num]); |
42 | debug_printf ("thread waiting %d, signal_arrived %p", (int) thread_waiting, _my_tls.signal_arrived); | |
4ae63783 | 43 | DWORD sig_n; |
962f9a2c | 44 | if (!thread_waiting) |
4ae63783 CF |
45 | sig_n = WAIT_TIMEOUT + 1; |
46 | else | |
962f9a2c | 47 | sig_n = WAIT_OBJECT_0 + num++; |
4ae63783 CF |
48 | |
49 | DWORD cancel_n; | |
50 | if (!is_cw_cancel || !pthread::is_good_object (&thread) || | |
51 | thread->cancelstate == PTHREAD_CANCEL_DISABLE) | |
52 | cancel_n = WAIT_TIMEOUT + 1; | |
53 | else | |
54 | { | |
55 | cancel_n = WAIT_OBJECT_0 + num++; | |
56 | wait_objects[cancel_n] = thread->cancel_event; | |
57 | } | |
58 | ||
59 | DWORD timeout_n; | |
60 | if (!timeout) | |
61 | timeout_n = WAIT_TIMEOUT + 1; | |
62 | else | |
63 | { | |
64 | timeout_n = WAIT_OBJECT_0 + num++; | |
65 | if (!_my_tls.locals.cw_timer) | |
66 | NtCreateTimer (&_my_tls.locals.cw_timer, TIMER_ALL_ACCESS, NULL, | |
67 | NotificationTimer); | |
68 | NtSetTimer (_my_tls.locals.cw_timer, timeout, NULL, NULL, FALSE, 0, NULL); | |
69 | wait_objects[timeout_n] = _my_tls.locals.cw_timer; | |
70 | } | |
71 | ||
72 | while (1) | |
73 | { | |
74 | res = WaitForMultipleObjects (num, wait_objects, FALSE, INFINITE); | |
75 | if (res == cancel_n) | |
6ec05d23 | 76 | res = WAIT_CANCELED; |
4ae63783 CF |
77 | else if (res == timeout_n) |
78 | res = WAIT_TIMEOUT; | |
79 | else if (res != sig_n) | |
80 | /* all set */; | |
81 | else if (is_cw_sig_eintr) | |
6ec05d23 | 82 | res = WAIT_SIGNALED; /* caller will deal with signals */ |
962f9a2c | 83 | else if (_my_tls.call_signal_handler ()) |
2addde8c | 84 | continue; |
4ae63783 CF |
85 | break; |
86 | } | |
87 | ||
88 | if (timeout) | |
89 | { | |
90 | TIMER_BASIC_INFORMATION tbi; | |
91 | ||
92 | NtQueryTimer (_my_tls.locals.cw_timer, TimerBasicInformation, &tbi, | |
93 | sizeof tbi, NULL); | |
94 | /* if timer expired, TimeRemaining is negative and represents the | |
95 | system uptime when signalled */ | |
96 | if (timeout->QuadPart < 0LL) | |
97 | timeout->QuadPart = tbi.SignalState ? 0LL : tbi.TimeRemaining.QuadPart; | |
98 | NtCancelTimer (_my_tls.locals.cw_timer, NULL); | |
99 | } | |
100 | ||
6ec05d23 CF |
101 | if (res == WAIT_CANCELED && is_cw_cancel_self) |
102 | pthread::static_cancel_self (); | |
103 | ||
4ae63783 CF |
104 | return res; |
105 | } |