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