aboutsummaryrefslogtreecommitdiff
path: root/src/backend/port/win32/timer.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2005-10-25 15:15:16 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2005-10-25 15:15:16 +0000
commit25777f6fd312b3f3e32edb921d79e3d8c7b499a6 (patch)
treed69976608fc3d97df70ed1f50a944f4e1a2ec036 /src/backend/port/win32/timer.c
parentb83547201fb321bca43276911d6839ab7ad7e7f7 (diff)
downloadpostgresql-25777f6fd312b3f3e32edb921d79e3d8c7b499a6.tar.gz
postgresql-25777f6fd312b3f3e32edb921d79e3d8c7b499a6.zip
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.
Diffstat (limited to 'src/backend/port/win32/timer.c')
-rw-r--r--src/backend/port/win32/timer.c113
1 files changed, 80 insertions, 33 deletions
diff --git a/src/backend/port/win32/timer.c b/src/backend/port/win32/timer.c
index c31c7bc114e..b6c0b407e6e 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;
}