Skip to content

Commit 25777f6

Browse files
committed
Fix Windows setitimer() emulation to not depend on delivering an APC
to the main thread. This allows removal of WaitForSingleObjectEx() calls from the main thread, thereby allowing us to re-enable Qingqing Zhou's CHECK_FOR_INTERRUPTS performance improvement. Qingqing, Magnus, et al.
1 parent b835472 commit 25777f6

File tree

5 files changed

+87
-50
lines changed

5 files changed

+87
-50
lines changed

src/backend/port/win32/signal.c

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
77
*
88
* IDENTIFICATION
9-
* $PostgreSQL: pgsql/src/backend/port/win32/signal.c,v 1.13 2005/10/21 21:43:45 tgl Exp $
9+
* $PostgreSQL: pgsql/src/backend/port/win32/signal.c,v 1.14 2005/10/25 15:15:16 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -89,16 +89,6 @@ pgwin32_signal_initialize(void)
8989
(errmsg_internal("failed to set console control handler")));
9090
}
9191

92-
/*
93-
* Support routine for CHECK_FOR_INTERRUPTS() macro
94-
*/
95-
void
96-
pgwin32_check_queued_signals(void)
97-
{
98-
if (WaitForSingleObjectEx(pgwin32_signal_event, 0, TRUE) == WAIT_OBJECT_0)
99-
pgwin32_dispatch_queued_signals();
100-
}
101-
10292
/*
10393
* Dispatch all signals currently queued and not blocked
10494
* Blocked signals are ignored, and will be fired at the time of

src/backend/port/win32/socket.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
77
*
88
* IDENTIFICATION
9-
* $PostgreSQL: pgsql/src/backend/port/win32/socket.c,v 1.9 2005/10/15 02:49:23 momjian Exp $
9+
* $PostgreSQL: pgsql/src/backend/port/win32/socket.c,v 1.10 2005/10/25 15:15:16 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -93,7 +93,7 @@ TranslateSocketError(void)
9393
static int
9494
pgwin32_poll_signals(void)
9595
{
96-
if (WaitForSingleObjectEx(pgwin32_signal_event, 0, TRUE) == WAIT_OBJECT_0)
96+
if (UNBLOCKED_SIGNAL_QUEUE())
9797
{
9898
pgwin32_dispatch_queued_signals();
9999
errno = EINTR;

src/backend/port/win32/timer.c

Lines changed: 80 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,15 @@
33
* timer.c
44
* Microsoft Windows Win32 Timer Implementation
55
*
6+
* Limitations of this implementation:
7+
*
8+
* - Does not support interval timer (value->it_interval)
9+
* - Only supports ITIMER_REAL
10+
*
611
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
712
*
813
* IDENTIFICATION
9-
* $PostgreSQL: pgsql/src/backend/port/win32/timer.c,v 1.5 2004/12/31 22:00:37 pgsql Exp $
14+
* $PostgreSQL: pgsql/src/backend/port/win32/timer.c,v 1.6 2005/10/25 15:15:16 tgl Exp $
1015
*
1116
*-------------------------------------------------------------------------
1217
*/
@@ -16,56 +21,98 @@
1621
#include "libpq/pqsignal.h"
1722

1823

19-
static HANDLE timerHandle = INVALID_HANDLE_VALUE;
24+
/* Communication area for inter-thread communication */
25+
typedef struct timerCA {
26+
struct itimerval value;
27+
HANDLE event;
28+
CRITICAL_SECTION crit_sec;
29+
} timerCA;
30+
31+
static timerCA timerCommArea;
32+
static HANDLE timerThreadHandle = INVALID_HANDLE_VALUE;
2033

21-
static VOID CALLBACK
22-
timer_completion(LPVOID arg, DWORD timeLow, DWORD timeHigh)
34+
35+
/* Timer management thread */
36+
static DWORD WINAPI
37+
pg_timer_thread(LPVOID param)
2338
{
24-
pg_queue_signal(SIGALRM);
25-
}
39+
DWORD waittime;
40+
41+
Assert(param == NULL);
2642

43+
waittime = INFINITE;
44+
45+
for (;;)
46+
{
47+
int r;
48+
49+
r = WaitForSingleObjectEx(timerCommArea.event, waittime, FALSE);
50+
if (r == WAIT_OBJECT_0)
51+
{
52+
/* Event signalled from main thread, change the timer */
53+
EnterCriticalSection(&timerCommArea.crit_sec);
54+
if (timerCommArea.value.it_value.tv_sec == 0 &&
55+
timerCommArea.value.it_value.tv_usec == 0)
56+
waittime = INFINITE; /* Cancel the interrupt */
57+
else
58+
waittime = timerCommArea.value.it_value.tv_usec / 10 + timerCommArea.value.it_value.tv_sec * 1000;
59+
ResetEvent(timerCommArea.event);
60+
LeaveCriticalSection(&timerCommArea.crit_sec);
61+
}
62+
else if (r == WAIT_TIMEOUT)
63+
{
64+
/* Timeout expired, signal SIGALRM and turn it off */
65+
pg_queue_signal(SIGALRM);
66+
waittime = INFINITE;
67+
}
68+
else
69+
{
70+
/* Should never happen */
71+
Assert(false);
72+
}
73+
}
74+
75+
return 0;
76+
}
2777

2878
/*
29-
* Limitations of this implementation:
30-
*
31-
* - Does not support setting ovalue
32-
* - Does not support interval timer (value->it_interval)
33-
* - Only supports ITIMER_REAL
79+
* Win32 setitimer emulation by creating a persistent thread
80+
* to handle the timer setting and notification upon timeout.
3481
*/
3582
int
3683
setitimer(int which, const struct itimerval * value, struct itimerval * ovalue)
3784
{
38-
LARGE_INTEGER dueTime;
39-
40-
Assert(ovalue == NULL);
4185
Assert(value != NULL);
4286
Assert(value->it_interval.tv_sec == 0 && value->it_interval.tv_usec == 0);
4387
Assert(which == ITIMER_REAL);
4488

45-
if (timerHandle == INVALID_HANDLE_VALUE)
89+
if (timerThreadHandle == INVALID_HANDLE_VALUE)
4690
{
47-
/* First call in this backend, create new timer object */
48-
timerHandle = CreateWaitableTimer(NULL, TRUE, NULL);
49-
if (timerHandle == NULL)
91+
/* First call in this backend, create event and the timer thread */
92+
timerCommArea.event = CreateEvent(NULL, TRUE, FALSE, NULL);
93+
if (timerCommArea.event == NULL)
5094
ereport(FATAL,
51-
(errmsg_internal("failed to create waitable timer: %i", (int) GetLastError())));
52-
}
95+
(errmsg_internal("failed to create timer event: %d",
96+
(int) GetLastError())));
5397

54-
if (value->it_value.tv_sec == 0 &&
55-
value->it_value.tv_usec == 0)
56-
{
57-
/* Turn timer off */
58-
CancelWaitableTimer(timerHandle);
59-
return 0;
60-
}
98+
MemSet(&timerCommArea.value, 0, sizeof(struct itimerval));
99+
100+
InitializeCriticalSection(&timerCommArea.crit_sec);
61101

62-
/* Negative time to SetWaitableTimer means relative time */
63-
dueTime.QuadPart = -(value->it_value.tv_usec * 10 + value->it_value.tv_sec * 10000000L);
102+
timerThreadHandle = CreateThread(NULL, 0, pg_timer_thread, NULL, 0, NULL);
103+
if (timerThreadHandle == INVALID_HANDLE_VALUE)
104+
ereport(FATAL,
105+
(errmsg_internal("failed to create timer thread: %d",
106+
(int) GetLastError())));
107+
}
64108

65-
/* Turn timer on, or change timer */
66-
if (!SetWaitableTimer(timerHandle, &dueTime, 0, timer_completion, NULL, FALSE))
67-
ereport(FATAL,
68-
(errmsg_internal("failed to set waitable timer: %i", (int) GetLastError())));
109+
/* Request the timer thread to change settings */
110+
EnterCriticalSection(&timerCommArea.crit_sec);
111+
if (ovalue)
112+
*ovalue = timerCommArea.value;
113+
timerCommArea.value = *value;
114+
LeaveCriticalSection(&timerCommArea.crit_sec);
115+
SetEvent(timerCommArea.event);
69116

70117
return 0;
71118
}

src/include/miscadmin.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
1414
* Portions Copyright (c) 1994, Regents of the University of California
1515
*
16-
* $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.182 2005/10/22 17:09:48 tgl Exp $
16+
* $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.183 2005/10/25 15:15:16 tgl Exp $
1717
*
1818
* NOTES
1919
* some of the information in this file should be moved to other files.
@@ -88,7 +88,8 @@ do { \
8888

8989
#define CHECK_FOR_INTERRUPTS() \
9090
do { \
91-
pgwin32_check_queued_signals(); \
91+
if (UNBLOCKED_SIGNAL_QUEUE()) \
92+
pgwin32_dispatch_queued_signals(); \
9293
if (InterruptPending) \
9394
ProcessInterrupts(); \
9495
} while(0)

src/include/port/win32.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $PostgreSQL: pgsql/src/include/port/win32.h,v 1.48 2005/10/21 21:43:46 tgl Exp $ */
1+
/* $PostgreSQL: pgsql/src/include/port/win32.h,v 1.49 2005/10/25 15:15:16 tgl Exp $ */
22

33
/* undefine and redefine after #include */
44
#undef mkdir
@@ -224,7 +224,6 @@ extern HANDLE pgwin32_initial_signal_pipe;
224224

225225
void pgwin32_signal_initialize(void);
226226
HANDLE pgwin32_create_signal_listener(pid_t pid);
227-
void pgwin32_check_queued_signals(void);
228227
void pgwin32_dispatch_queued_signals(void);
229228
void pg_queue_signal(int signum);
230229

0 commit comments

Comments
 (0)