diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2005-10-25 15:15:16 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2005-10-25 15:15:16 +0000 |
commit | 25777f6fd312b3f3e32edb921d79e3d8c7b499a6 (patch) | |
tree | d69976608fc3d97df70ed1f50a944f4e1a2ec036 /src/backend/port/win32/timer.c | |
parent | b83547201fb321bca43276911d6839ab7ad7e7f7 (diff) | |
download | postgresql-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.c | 113 |
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; } |