summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorBruce Momjian2004-01-27 00:45:26 +0000
committerBruce Momjian2004-01-27 00:45:26 +0000
commit50491963cb6e439f09e4ade608c0c177ed6e6527 (patch)
treeecf63f05e07665bd493eff04a463b1350ad07742 /src/backend
parenteec08b95e74b6065efa5bc1ea5fd5844e7a95bbd (diff)
Here's the latest win32 signals code, this time in the form of a patch
against the latest shapshot. It also includes the replacement of kill() with pqkill() and sigsetmask() with pqsigsetmask(). Passes all tests fine on my linux machine once applied. Still doesn't link completely on Win32 - there are a few things still required. But much closer than before. At Bruce's request, I'm goint to write up a README file about the method of signals delivery chosen and why the others were rejected (basically a summary of the mailinglist discussions). I'll finish that up once/if the patch is accepted. Magnus Hagander
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/commands/async.c5
-rw-r--r--src/backend/libpq/pqsignal.c243
-rw-r--r--src/backend/main/main.c7
-rw-r--r--src/backend/port/sysv_sema.c5
-rw-r--r--src/backend/port/sysv_shmem.c5
-rw-r--r--src/backend/postmaster/postmaster.c20
-rw-r--r--src/backend/storage/ipc/pmsignal.c5
-rw-r--r--src/backend/storage/lmgr/proc.c5
-rw-r--r--src/backend/utils/init/miscinit.c5
9 files changed, 276 insertions, 24 deletions
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index bd90961315c..cbc7ee5146e 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/async.c,v 1.107 2004/01/07 18:56:25 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/async.c,v 1.108 2004/01/27 00:45:26 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -83,6 +83,7 @@
#include "commands/async.h"
#include "libpq/libpq.h"
#include "libpq/pqformat.h"
+#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "storage/ipc.h"
#include "tcop/tcopprot.h"
@@ -497,7 +498,7 @@ AtCommit_Notify(void)
* for some reason. It's OK to send the signal first, because
* the other guy can't read pg_listener until we unlock it.
*/
- if (kill(listenerPID, SIGUSR2) < 0)
+ if (pqkill(listenerPID, SIGUSR2) < 0)
{
/*
* Get rid of pg_listener entry if it refers to a PID that
diff --git a/src/backend/libpq/pqsignal.c b/src/backend/libpq/pqsignal.c
index 497201e0a77..79d31b4ec73 100644
--- a/src/backend/libpq/pqsignal.c
+++ b/src/backend/libpq/pqsignal.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/libpq/pqsignal.c,v 1.28 2003/11/29 19:51:49 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/libpq/pqsignal.c,v 1.29 2004/01/27 00:45:26 momjian Exp $
*
* NOTES
* This shouldn't be in libpq, but the monitor and some other
@@ -38,9 +38,18 @@
* is to do signal-handler reinstallation, which doesn't work well
* at all.
* ------------------------------------------------------------------------*/
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#define _WIN32_WINNT 0x0400
+#endif
+
#include "postgres.h"
+#ifndef WIN32
#include <signal.h>
+#else
+#include <windows.h>
+#endif
#include "libpq/pqsignal.h"
@@ -127,6 +136,7 @@ pqinitmask(void)
}
+#ifndef WIN32
/*
* Set up a signal handler
*/
@@ -149,3 +159,234 @@ pqsignal(int signo, pqsigfunc func)
return oact.sa_handler;
#endif /* !HAVE_POSIX_SIGNALS */
}
+
+
+#else
+
+
+/* Win32 specific signals code */
+
+/* pg_signal_crit_sec is used to protect only pg_signal_queue. That is the only
+ * variable that can be accessed from the signal sending threads! */
+static CRITICAL_SECTION pg_signal_crit_sec;
+static int pg_signal_queue;
+
+#define PG_SIGNAL_COUNT 32
+static pqsigfunc pg_signal_array[PG_SIGNAL_COUNT];
+static pqsigfunc pg_signal_defaults[PG_SIGNAL_COUNT];
+static int pg_signal_mask;
+
+HANDLE pgwin32_main_thread_handle;
+
+/* Signal handling thread function */
+static DWORD WINAPI pg_signal_thread(LPVOID param);
+
+/* Initialization */
+void pgwin32_signal_initialize(void) {
+ int i;
+ HANDLE signal_thread_handle;
+ InitializeCriticalSection(&pg_signal_crit_sec);
+
+ for (i = 0; i < PG_SIGNAL_COUNT; i++) {
+ pg_signal_array[i] = SIG_DFL;
+ pg_signal_defaults[i] = SIG_IGN;
+ }
+ pg_signal_mask = 0;
+ pg_signal_queue = 0;
+
+ /* Get handle to main thread so we can post calls to it later */
+ if (!DuplicateHandle(GetCurrentProcess(),GetCurrentThread(),
+ GetCurrentProcess(),&pgwin32_main_thread_handle,
+ 0,FALSE,DUPLICATE_SAME_ACCESS)) {
+ fprintf(stderr,gettext("Failed to get main thread handle!\n"));
+ exit(1);
+ }
+
+ /* Create thread for handling signals */
+ signal_thread_handle = CreateThread(NULL,0,pg_signal_thread,NULL,0,NULL);
+ if (signal_thread_handle == NULL) {
+ fprintf(stderr,gettext("Failed to create signal handler thread!\n"));
+ exit(1);
+ }
+}
+
+
+/* Dispatch all signals currently queued and not blocked
+ * Blocked signals are ignored, and will be fired at the time of
+ * the sigsetmask() call. */
+static void dispatch_queued_signals(void) {
+ int i;
+
+ EnterCriticalSection(&pg_signal_crit_sec);
+ while (pg_signal_queue & ~pg_signal_mask) {
+ /* One or more unblocked signals queued for execution */
+
+ int exec_mask = pg_signal_queue & ~pg_signal_mask;
+
+ for (i = 0; i < PG_SIGNAL_COUNT; i++) {
+ if (exec_mask & sigmask(i)) {
+ /* Execute this signal */
+ pqsigfunc sig = pg_signal_array[i];
+ if (sig == SIG_DFL)
+ sig = pg_signal_defaults[i];
+ pg_signal_queue &= ~sigmask(i);
+ if (sig != SIG_ERR && sig != SIG_IGN && sig != SIG_DFL) {
+ LeaveCriticalSection(&pg_signal_crit_sec);
+ sig(i);
+ EnterCriticalSection(&pg_signal_crit_sec);
+ break; /* Restart outer loop, in case signal mask or queue
+ has been modified inside signal handler */
+ }
+ }
+ }
+ }
+ LeaveCriticalSection(&pg_signal_crit_sec);
+}
+
+/* signal masking. Only called on main thread, no sync required */
+int pqsigsetmask(int mask) {
+ int prevmask;
+ prevmask = pg_signal_mask;
+ pg_signal_mask = mask;
+
+ /* Dispatch any signals queued up right away, in case we have
+ unblocked one or more signals previously queued */
+ dispatch_queued_signals();
+
+ return prevmask;
+}
+
+
+/* signal manipulation. Only called on main thread, no sync required */
+pqsigfunc pqsignal(int signum, pqsigfunc handler) {
+ pqsigfunc prevfunc;
+ if (signum >= PG_SIGNAL_COUNT || signum < 0)
+ return SIG_ERR;
+ prevfunc = pg_signal_array[signum];
+ pg_signal_array[signum] = handler;
+ return prevfunc;
+}
+
+/* signal sending */
+int pqkill(int pid, int sig) {
+ char pipename[128];
+ BYTE sigData = sig;
+ BYTE sigRet = 0;
+ DWORD bytes;
+
+ if (sig >= PG_SIGNAL_COUNT || sig <= 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (pid <= 0) {
+ /* No support for process groups */
+ errno = EINVAL;
+ return -1;
+ }
+ wsprintf(pipename,"\\\\.\\pipe\\pgsignal_%i",pid);
+ if (!CallNamedPipe(pipename,&sigData,1,&sigRet,1,&bytes,1000)) {
+ if (GetLastError() == ERROR_FILE_NOT_FOUND)
+ errno = ESRCH;
+ else if (GetLastError() == ERROR_ACCESS_DENIED)
+ errno = EPERM;
+ else
+ errno = EINVAL;
+ return -1;
+ }
+ if (bytes != 1 || sigRet != sig) {
+ errno = ESRCH;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* APC callback scheduled on main thread when signals are fired */
+static void CALLBACK pg_signal_apc(ULONG_PTR param) {
+ dispatch_queued_signals();
+}
+
+/*
+ * All functions below execute on the signal handler thread
+ * and must be synchronized as such!
+ * NOTE! The only global variable that can be used is
+ * pg_signal_queue!
+ */
+
+
+static void pg_queue_signal(int signum) {
+ if (signum >= PG_SIGNAL_COUNT || signum < 0)
+ return;
+
+ EnterCriticalSection(&pg_signal_crit_sec);
+ pg_signal_queue |= sigmask(signum);
+ LeaveCriticalSection(&pg_signal_crit_sec);
+
+ QueueUserAPC(pg_signal_apc,pgwin32_main_thread_handle,(ULONG_PTR)NULL);
+}
+
+/* Signal dispatching thread */
+static DWORD WINAPI pg_signal_dispatch_thread(LPVOID param) {
+ HANDLE pipe = (HANDLE)param;
+ BYTE sigNum;
+ DWORD bytes;
+
+ if (!ReadFile(pipe,&sigNum,1,&bytes,NULL)) {
+ /* Client died before sending */
+ CloseHandle(pipe);
+ return 0;
+ }
+ if (bytes != 1) {
+ /* Received <bytes> bytes over signal pipe (should be 1) */
+ CloseHandle(pipe);
+ return 0;
+ }
+ WriteFile(pipe,&sigNum,1,&bytes,NULL); /* Don't care if it works or not.. */
+ FlushFileBuffers(pipe);
+ DisconnectNamedPipe(pipe);
+ CloseHandle(pipe);
+
+ pg_queue_signal(sigNum);
+ return 0;
+}
+
+/* Signal handling thread */
+static DWORD WINAPI pg_signal_thread(LPVOID param) {
+ char pipename[128];
+ HANDLE pipe = INVALID_HANDLE_VALUE;
+
+ wsprintf(pipename,"\\\\.\\pipe\\pgsignal_%i",GetCurrentProcessId());
+
+ for (;;) {
+ BOOL fConnected;
+ HANDLE hThread;
+
+ pipe = CreateNamedPipe(pipename,PIPE_ACCESS_DUPLEX,
+ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES,16,16,1000,NULL);
+ if (pipe == INVALID_HANDLE_VALUE) {
+ fprintf(stderr,gettext("Failed to create signal listener pipe: %i. Retrying.\n"),(int)GetLastError());
+ SleepEx(500,TRUE);
+ continue;
+ }
+
+ fConnected = ConnectNamedPipe(pipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
+ if (fConnected) {
+ hThread = CreateThread(NULL, 0,
+ (LPTHREAD_START_ROUTINE)pg_signal_dispatch_thread,
+ (LPVOID)pipe,0,NULL);
+ if (hThread == INVALID_HANDLE_VALUE) {
+ fprintf(stderr,gettext("Failed to create signal dispatch thread: %i\n"),(int)GetLastError());
+ }
+ else
+ CloseHandle(hThread);
+ }
+ else
+ /* Connection failed. Cleanup and try again */
+ CloseHandle(pipe);
+ }
+ return 0;
+}
+
+
+#endif
diff --git a/src/backend/main/main.c b/src/backend/main/main.c
index fe8879940ef..90a1a35a3a5 100644
--- a/src/backend/main/main.c
+++ b/src/backend/main/main.c
@@ -13,7 +13,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/main/main.c,v 1.71 2004/01/11 03:49:31 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/main/main.c,v 1.72 2004/01/27 00:45:26 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -40,6 +40,9 @@
#include "utils/help_config.h"
#include "utils/ps_status.h"
#include "pgstat.h"
+#ifdef WIN32
+#include "libpq/pqsignal.h"
+#endif
@@ -97,6 +100,8 @@ main(int argc, char *argv[])
argv[0], err);
exit(1);
}
+
+ pgwin32_signal_initialize();
}
#endif
diff --git a/src/backend/port/sysv_sema.c b/src/backend/port/sysv_sema.c
index 20f0d6bc514..82d6ded95ba 100644
--- a/src/backend/port/sysv_sema.c
+++ b/src/backend/port/sysv_sema.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/port/sysv_sema.c,v 1.12 2003/12/01 22:15:37 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/port/sysv_sema.c,v 1.13 2004/01/27 00:45:26 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -31,6 +31,7 @@
#include "miscadmin.h"
#include "storage/ipc.h"
#include "storage/pg_sema.h"
+#include "libpq/pqsignal.h"
#ifndef HAVE_UNION_SEMUN
@@ -232,7 +233,7 @@ IpcSemaphoreCreate(int numSems)
continue; /* oops, GETPID failed */
if (creatorPID != getpid())
{
- if (kill(creatorPID, 0) == 0 ||
+ if (pqkill(creatorPID, 0) == 0 ||
errno != ESRCH)
continue; /* sema belongs to a live process */
}
diff --git a/src/backend/port/sysv_shmem.c b/src/backend/port/sysv_shmem.c
index 519714938a1..18b4a193f3f 100644
--- a/src/backend/port/sysv_shmem.c
+++ b/src/backend/port/sysv_shmem.c
@@ -10,7 +10,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/port/sysv_shmem.c,v 1.28 2004/01/07 18:56:27 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/port/sysv_shmem.c,v 1.29 2004/01/27 00:45:26 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -33,6 +33,7 @@
#include "miscadmin.h"
#include "storage/ipc.h"
#include "storage/pg_shmem.h"
+#include "libpq/pqsignal.h"
typedef key_t IpcMemoryKey; /* shared memory key passed to shmget(2) */
@@ -284,7 +285,7 @@ PGSharedMemoryCreate(uint32 size, bool makePrivate, int port)
hdr = (PGShmemHeader *) memAddress;
if (hdr->creatorPID != getpid())
{
- if (kill(hdr->creatorPID, 0) == 0 || errno != ESRCH)
+ if (pqkill(hdr->creatorPID, 0) == 0 || errno != ESRCH)
{
shmdt(memAddress);
continue; /* segment belongs to a live process */
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index ccbffab5617..ada86268e38 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -37,7 +37,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.362 2004/01/26 22:59:53 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.363 2004/01/27 00:45:26 momjian Exp $
*
* NOTES
*
@@ -1566,7 +1566,7 @@ processCancelRequest(Port *port, void *pkt)
ereport(DEBUG2,
(errmsg_internal("processing cancel request: sending SIGINT to process %d",
backendPID)));
- kill(bp->pid, SIGINT);
+ pqkill(bp->pid, SIGINT);
}
else
/* Right PID, wrong key: no way, Jose */
@@ -1738,7 +1738,7 @@ SIGHUP_handler(SIGNAL_ARGS)
* will start a new one with a possibly changed config
*/
if (BgWriterPID != 0)
- kill(BgWriterPID, SIGTERM);
+ pqkill(BgWriterPID, SIGTERM);
}
PG_SETMASK(&UnBlockSig);
@@ -1772,7 +1772,7 @@ pmdie(SIGNAL_ARGS)
* Wait for children to end their work and ShutdownDataBase.
*/
if (BgWriterPID != 0)
- kill(BgWriterPID, SIGTERM);
+ pqkill(BgWriterPID, SIGTERM);
if (Shutdown >= SmartShutdown)
break;
Shutdown = SmartShutdown;
@@ -1806,7 +1806,7 @@ pmdie(SIGNAL_ARGS)
* and exit) and ShutdownDataBase when they are gone.
*/
if (BgWriterPID != 0)
- kill(BgWriterPID, SIGTERM);
+ pqkill(BgWriterPID, SIGTERM);
if (Shutdown >= FastShutdown)
break;
ereport(LOG,
@@ -1854,13 +1854,13 @@ pmdie(SIGNAL_ARGS)
* properly shutdown data base system.
*/
if (BgWriterPID != 0)
- kill(BgWriterPID, SIGQUIT);
+ pqkill(BgWriterPID, SIGQUIT);
ereport(LOG,
(errmsg("received immediate shutdown request")));
if (ShutdownPID > 0)
- kill(ShutdownPID, SIGQUIT);
+ pqkill(ShutdownPID, SIGQUIT);
if (StartupPID > 0)
- kill(StartupPID, SIGQUIT);
+ pqkill(StartupPID, SIGQUIT);
if (DLGetHead(BackendList))
SignalChildren(SIGQUIT);
ExitPostmaster(0);
@@ -2130,7 +2130,7 @@ CleanupProc(int pid,
(errmsg_internal("sending %s to process %d",
(SendStop ? "SIGSTOP" : "SIGQUIT"),
(int) bp->pid)));
- kill(bp->pid, (SendStop ? SIGSTOP : SIGQUIT));
+ pqkill(bp->pid, (SendStop ? SIGSTOP : SIGQUIT));
}
}
else
@@ -2225,7 +2225,7 @@ SignalChildren(int signal)
(errmsg_internal("sending signal %d to process %d",
signal,
(int) bp->pid)));
- kill(bp->pid, signal);
+ pqkill(bp->pid, signal);
}
curr = next;
diff --git a/src/backend/storage/ipc/pmsignal.c b/src/backend/storage/ipc/pmsignal.c
index 2d6252b66ca..58eb80fef08 100644
--- a/src/backend/storage/ipc/pmsignal.c
+++ b/src/backend/storage/ipc/pmsignal.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/ipc/pmsignal.c,v 1.11 2004/01/26 22:59:53 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/ipc/pmsignal.c,v 1.12 2004/01/27 00:45:26 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,6 +20,7 @@
#include "miscadmin.h"
#include "storage/pmsignal.h"
#include "storage/shmem.h"
+#include "libpq/pqsignal.h"
/*
@@ -64,7 +65,7 @@ SendPostmasterSignal(PMSignalReason reason)
/* Atomically set the proper flag */
PMSignalFlags[reason] = true;
/* Send signal to postmaster */
- kill(PostmasterPid, SIGUSR1);
+ pqkill(PostmasterPid, SIGUSR1);
}
/*
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 682cc741f35..a3d4ad08874 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.144 2004/01/07 18:56:27 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.145 2004/01/27 00:45:26 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -51,6 +51,7 @@
#include "storage/proc.h"
#include "storage/sinval.h"
#include "storage/spin.h"
+#include "libpq/pqsignal.h"
/* GUC variables */
int DeadlockTimeout = 1000;
@@ -1130,7 +1131,7 @@ CheckStatementTimeout(void)
{
/* Time to die */
statement_timeout_active = false;
- kill(MyProcPid, SIGINT);
+ pqkill(MyProcPid, SIGINT);
}
else
{
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index 98de05c0b8f..2380cbb9dba 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.120 2004/01/26 22:35:32 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.121 2004/01/27 00:45:26 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -32,6 +32,7 @@
#include "catalog/catname.h"
#include "catalog/pg_shadow.h"
#include "libpq/libpq-be.h"
+#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "storage/ipc.h"
#include "storage/pg_shmem.h"
@@ -531,7 +532,7 @@ CreateLockFile(const char *filename, bool amPostmaster,
*/
if (other_pid != my_pid)
{
- if (kill(other_pid, 0) == 0 ||
+ if (pqkill(other_pid, 0) == 0 ||
(errno != ESRCH
#ifdef __BEOS__
&& errno != EINVAL