From 25777f6fd312b3f3e32edb921d79e3d8c7b499a6 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 25 Oct 2005 15:15:16 +0000 Subject: [PATCH] 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. --- src/backend/port/win32/signal.c | 12 +--- src/backend/port/win32/socket.c | 4 +- src/backend/port/win32/timer.c | 113 ++++++++++++++++++++++---------- src/include/miscadmin.h | 5 +- src/include/port/win32.h | 3 +- 5 files changed, 87 insertions(+), 50 deletions(-) diff --git a/src/backend/port/win32/signal.c b/src/backend/port/win32/signal.c index fa7d8cf6a2..3204c9c20e 100644 --- a/src/backend/port/win32/signal.c +++ b/src/backend/port/win32/signal.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/port/win32/signal.c,v 1.13 2005/10/21 21:43:45 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/port/win32/signal.c,v 1.14 2005/10/25 15:15:16 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -89,16 +89,6 @@ pgwin32_signal_initialize(void) (errmsg_internal("failed to set console control handler"))); } -/* - * Support routine for CHECK_FOR_INTERRUPTS() macro - */ -void -pgwin32_check_queued_signals(void) -{ - if (WaitForSingleObjectEx(pgwin32_signal_event, 0, TRUE) == WAIT_OBJECT_0) - pgwin32_dispatch_queued_signals(); -} - /* * Dispatch all signals currently queued and not blocked * Blocked signals are ignored, and will be fired at the time of diff --git a/src/backend/port/win32/socket.c b/src/backend/port/win32/socket.c index 808977a237..b4bd121ca9 100644 --- a/src/backend/port/win32/socket.c +++ b/src/backend/port/win32/socket.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/port/win32/socket.c,v 1.9 2005/10/15 02:49:23 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/port/win32/socket.c,v 1.10 2005/10/25 15:15:16 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -93,7 +93,7 @@ TranslateSocketError(void) static int pgwin32_poll_signals(void) { - if (WaitForSingleObjectEx(pgwin32_signal_event, 0, TRUE) == WAIT_OBJECT_0) + if (UNBLOCKED_SIGNAL_QUEUE()) { pgwin32_dispatch_queued_signals(); errno = EINTR; diff --git a/src/backend/port/win32/timer.c b/src/backend/port/win32/timer.c index c31c7bc114..b6c0b407e6 100644 --- a/src/backend/port/win32/timer.c +++ b/src/backend/port/win32/timer.c @@ -3,10 +3,15 @@ * timer.c * Microsoft Windows Win32 Timer Implementation * + * Limitations of this implementation: + * + * - Does not support interval timer (value->it_interval) + * - Only supports ITIMER_REAL + * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/port/win32/timer.c,v 1.5 2004/12/31 22:00:37 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/port/win32/timer.c,v 1.6 2005/10/25 15:15:16 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -16,56 +21,98 @@ #include "libpq/pqsignal.h" -static HANDLE timerHandle = INVALID_HANDLE_VALUE; +/* Communication area for inter-thread communication */ +typedef struct timerCA { + struct itimerval value; + HANDLE event; + CRITICAL_SECTION crit_sec; +} timerCA; + +static timerCA timerCommArea; +static HANDLE timerThreadHandle = INVALID_HANDLE_VALUE; -static VOID CALLBACK -timer_completion(LPVOID arg, DWORD timeLow, DWORD timeHigh) + +/* Timer management thread */ +static DWORD WINAPI +pg_timer_thread(LPVOID param) { - pg_queue_signal(SIGALRM); -} + DWORD waittime; + + Assert(param == NULL); + waittime = INFINITE; + + for (;;) + { + int r; + + r = WaitForSingleObjectEx(timerCommArea.event, waittime, FALSE); + if (r == WAIT_OBJECT_0) + { + /* Event signalled from main thread, change the timer */ + EnterCriticalSection(&timerCommArea.crit_sec); + if (timerCommArea.value.it_value.tv_sec == 0 && + timerCommArea.value.it_value.tv_usec == 0) + waittime = INFINITE; /* Cancel the interrupt */ + else + waittime = timerCommArea.value.it_value.tv_usec / 10 + timerCommArea.value.it_value.tv_sec * 1000; + ResetEvent(timerCommArea.event); + LeaveCriticalSection(&timerCommArea.crit_sec); + } + else if (r == WAIT_TIMEOUT) + { + /* Timeout expired, signal SIGALRM and turn it off */ + pg_queue_signal(SIGALRM); + waittime = INFINITE; + } + else + { + /* Should never happen */ + Assert(false); + } + } + + return 0; +} /* - * Limitations of this implementation: - * - * - Does not support setting ovalue - * - Does not support interval timer (value->it_interval) - * - Only supports ITIMER_REAL + * Win32 setitimer emulation by creating a persistent thread + * to handle the timer setting and notification upon timeout. */ int setitimer(int which, const struct itimerval * value, struct itimerval * ovalue) { - LARGE_INTEGER dueTime; - - Assert(ovalue == NULL); Assert(value != NULL); Assert(value->it_interval.tv_sec == 0 && value->it_interval.tv_usec == 0); Assert(which == ITIMER_REAL); - if (timerHandle == INVALID_HANDLE_VALUE) + if (timerThreadHandle == INVALID_HANDLE_VALUE) { - /* First call in this backend, create new timer object */ - timerHandle = CreateWaitableTimer(NULL, TRUE, NULL); - if (timerHandle == NULL) + /* First call in this backend, create event and the timer thread */ + timerCommArea.event = CreateEvent(NULL, TRUE, FALSE, NULL); + if (timerCommArea.event == NULL) ereport(FATAL, - (errmsg_internal("failed to create waitable timer: %i", (int) GetLastError()))); - } + (errmsg_internal("failed to create timer event: %d", + (int) GetLastError()))); - if (value->it_value.tv_sec == 0 && - value->it_value.tv_usec == 0) - { - /* Turn timer off */ - CancelWaitableTimer(timerHandle); - return 0; - } + MemSet(&timerCommArea.value, 0, sizeof(struct itimerval)); + + InitializeCriticalSection(&timerCommArea.crit_sec); - /* Negative time to SetWaitableTimer means relative time */ - dueTime.QuadPart = -(value->it_value.tv_usec * 10 + value->it_value.tv_sec * 10000000L); + timerThreadHandle = CreateThread(NULL, 0, pg_timer_thread, NULL, 0, NULL); + if (timerThreadHandle == INVALID_HANDLE_VALUE) + ereport(FATAL, + (errmsg_internal("failed to create timer thread: %d", + (int) GetLastError()))); + } - /* Turn timer on, or change timer */ - if (!SetWaitableTimer(timerHandle, &dueTime, 0, timer_completion, NULL, FALSE)) - ereport(FATAL, - (errmsg_internal("failed to set waitable timer: %i", (int) GetLastError()))); + /* Request the timer thread to change settings */ + EnterCriticalSection(&timerCommArea.crit_sec); + if (ovalue) + *ovalue = timerCommArea.value; + timerCommArea.value = *value; + LeaveCriticalSection(&timerCommArea.crit_sec); + SetEvent(timerCommArea.event); return 0; } diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index f82fffed77..fc13891e41 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -13,7 +13,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.182 2005/10/22 17:09:48 tgl Exp $ + * $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.183 2005/10/25 15:15:16 tgl Exp $ * * NOTES * some of the information in this file should be moved to other files. @@ -88,7 +88,8 @@ do { \ #define CHECK_FOR_INTERRUPTS() \ do { \ - pgwin32_check_queued_signals(); \ + if (UNBLOCKED_SIGNAL_QUEUE()) \ + pgwin32_dispatch_queued_signals(); \ if (InterruptPending) \ ProcessInterrupts(); \ } while(0) diff --git a/src/include/port/win32.h b/src/include/port/win32.h index 9d1a6da6c6..5bf6ce208f 100644 --- a/src/include/port/win32.h +++ b/src/include/port/win32.h @@ -1,4 +1,4 @@ -/* $PostgreSQL: pgsql/src/include/port/win32.h,v 1.48 2005/10/21 21:43:46 tgl Exp $ */ +/* $PostgreSQL: pgsql/src/include/port/win32.h,v 1.49 2005/10/25 15:15:16 tgl Exp $ */ /* undefine and redefine after #include */ #undef mkdir @@ -224,7 +224,6 @@ extern HANDLE pgwin32_initial_signal_pipe; void pgwin32_signal_initialize(void); HANDLE pgwin32_create_signal_listener(pid_t pid); -void pgwin32_check_queued_signals(void); void pgwin32_dispatch_queued_signals(void); void pg_queue_signal(int signum); -- 2.40.0