Commit 25777f6f authored by Tom Lane's avatar Tom Lane

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.
parent b8354720
......@@ -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
......
......@@ -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;
......
......@@ -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 VOID CALLBACK
timer_completion(LPVOID arg, DWORD timeLow, DWORD timeHigh)
static timerCA timerCommArea;
static HANDLE timerThreadHandle = INVALID_HANDLE_VALUE;
/* Timer management thread */
static DWORD WINAPI
pg_timer_thread(LPVOID param)
{
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));
/* Negative time to SetWaitableTimer means relative time */
dueTime.QuadPart = -(value->it_value.tv_usec * 10 + value->it_value.tv_sec * 10000000L);
InitializeCriticalSection(&timerCommArea.crit_sec);
/* Turn timer on, or change timer */
if (!SetWaitableTimer(timerHandle, &dueTime, 0, timer_completion, NULL, FALSE))
timerThreadHandle = CreateThread(NULL, 0, pg_timer_thread, NULL, 0, NULL);
if (timerThreadHandle == INVALID_HANDLE_VALUE)
ereport(FATAL,
(errmsg_internal("failed to set waitable timer: %i", (int) GetLastError())));
(errmsg_internal("failed to create timer thread: %d",
(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;
}
......@@ -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)
......
/* $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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment