1 /**
2 * Emulation of the Posix function `alarm()`
3 * using `CreateTimerQueueTimer()`.
4 *
5 * \ref https://docs.microsoft.com/en-us/windows/win32/api/threadpoollegacyapiset/nf-threadpoollegacyapiset-createtimerqueuetimer
6 */
7 #include <stdio.h>
8 #include "compat_alarm.h"
9
10 #ifdef HAVE_win_alarm /* rest of file */
11
12 static HANDLE alarm_hnd = INVALID_HANDLE_VALUE;
13 static int alarm_countdown;
14
15 /**
16 * The timer-callback that performs the countdown.
17 */
alarm_handler(PVOID param,BOOLEAN timer_fired)18 void CALLBACK alarm_handler(PVOID param, BOOLEAN timer_fired)
19 {
20 if (alarm_countdown > 0) {
21 alarm_countdown--;
22 if (alarm_countdown == 0)
23 raise(SIGALRM);
24 }
25 (void) timer_fired;
26 (void) param;
27 }
28
29 /**
30 * Destroy the timer.<br>
31 * Called as an `atexit()` function.
32 */
alarm_delete(void)33 static void alarm_delete(void)
34 {
35 if (!alarm_hnd || alarm_hnd == INVALID_HANDLE_VALUE)
36 return;
37 signal(SIGALRM, SIG_IGN);
38 DeleteTimerQueueTimer(NULL, alarm_hnd, NULL);
39 alarm_hnd = INVALID_HANDLE_VALUE;
40 }
41
42 /**
43 * Create a kernel32 timer once.
44 */
alarm_create(void)45 static void alarm_create(void)
46 {
47 if (alarm_hnd && alarm_hnd != INVALID_HANDLE_VALUE)
48 return;
49
50 if (!CreateTimerQueueTimer(&alarm_hnd, NULL, alarm_handler,
51 NULL,
52 1000, /* call alarm_handler() after 1 sec */
53 1000, /* an do it periodically every seconds */
54 WT_EXECUTEDEFAULT | WT_EXECUTEINTIMERTHREAD)) {
55 fprintf(stderr, "CreateTimerQueueTimer() failed %lu\n", GetLastError());
56 alarm_hnd = NULL;
57 }
58 else
59 atexit(alarm_delete);
60 }
61
62 /**
63 * Emulate an `alarm(sec)` function.
64 *
65 * @param[in] seconds the number of seconds to countdown before a `raise(SIGALRM)` is done.<br>
66 * if `seconds == 0` the `alarm_handler()` will do nothing.
67 */
win_alarm(unsigned seconds)68 int win_alarm(unsigned seconds)
69 {
70 alarm_countdown = seconds;
71 alarm_create();
72 return (0);
73 }
74 #else
75
76 /*
77 * Just so this compilation unit isn't empty.
78 */
79 int win_alarm(unsigned seconds);
win_alarm(unsigned seconds)80 int win_alarm(unsigned seconds)
81 {
82 (void) seconds;
83 return (0);
84 }
85 #endif /* HAVE_win_alarm */
86