timer.c 3.1 KB
Newer Older
1 2 3 4 5
/*-------------------------------------------------------------------------
 *
 * timer.c
 *	  Microsoft Windows Win32 Timer Implementation
 *
6
 *	  Limitations of this implementation:
7
 *
8 9
 *	  - Does not support interval timer (value->it_interval)
 *	  - Only supports ITIMER_REAL
10
 *
11
 * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
12 13
 *
 * IDENTIFICATION
B
Bruce Momjian 已提交
14
 *	  $PostgreSQL: pgsql/src/backend/port/win32/timer.c,v 1.9 2006/08/09 17:33:52 momjian Exp $
15 16 17 18 19 20 21 22 23
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include "libpq/pqsignal.h"


24
/* Communication area for inter-thread communication */
25 26
typedef struct timerCA
{
27
	struct itimerval value;
28
	HANDLE		event;
29
	CRITICAL_SECTION crit_sec;
30
}	timerCA;
31 32 33

static timerCA timerCommArea;
static HANDLE timerThreadHandle = INVALID_HANDLE_VALUE;
34

35 36 37 38

/* Timer management thread */
static DWORD WINAPI
pg_timer_thread(LPVOID param)
B
Bruce Momjian 已提交
39
{
40
	DWORD		waittime;
41 42

	Assert(param == NULL);
43

44 45 46 47
	waittime = INFINITE;

	for (;;)
	{
48
		int			r;
49 50 51 52 53 54 55 56

		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)
57
				waittime = INFINITE;	/* Cancel the interrupt */
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
			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;
}
78 79

/*
80 81
 * Win32 setitimer emulation by creating a persistent thread
 * to handle the timer setting and notification upon timeout.
82
 */
B
Bruce Momjian 已提交
83
int
B
Bruce Momjian 已提交
84
setitimer(int which, const struct itimerval *value, struct itimerval *ovalue)
B
Bruce Momjian 已提交
85
{
86 87 88 89
	Assert(value != NULL);
	Assert(value->it_interval.tv_sec == 0 && value->it_interval.tv_usec == 0);
	Assert(which == ITIMER_REAL);

90
	if (timerThreadHandle == INVALID_HANDLE_VALUE)
B
Bruce Momjian 已提交
91
	{
92 93 94
		/* First call in this backend, create event and the timer thread */
		timerCommArea.event = CreateEvent(NULL, TRUE, FALSE, NULL);
		if (timerCommArea.event == NULL)
95
			ereport(FATAL,
96 97
					(errmsg_internal("failed to create timer event: %d",
									 (int) GetLastError())));
98

99 100 101
		MemSet(&timerCommArea.value, 0, sizeof(struct itimerval));

		InitializeCriticalSection(&timerCommArea.crit_sec);
102

103 104 105 106 107 108
		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())));
	}
109

110 111 112 113 114 115 116
	/* 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);
117 118 119

	return 0;
}