diff -cr postgresql-snapshot/src/backend/commands/async.c postgresql-win32/src/backend/commands/async.c *** postgresql-snapshot/src/backend/commands/async.c Wed Jan 7 19:56:25 2004 --- postgresql-win32/src/backend/commands/async.c Sun Jan 25 22:19:33 2004 *************** *** 83,88 **** --- 83,89 ---- #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,503 **** * 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) { /* * Get rid of pg_listener entry if it refers to a PID that --- 498,504 ---- * 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 (pqkill(listenerPID, SIGUSR2) < 0) { /* * Get rid of pg_listener entry if it refers to a PID that diff -cr postgresql-snapshot/src/backend/libpq/pqsignal.c postgresql-win32/src/backend/libpq/pqsignal.c *** postgresql-snapshot/src/backend/libpq/pqsignal.c Sat Nov 29 20:51:49 2003 --- postgresql-win32/src/backend/libpq/pqsignal.c Sun Jan 25 22:30:50 2004 *************** *** 38,46 **** --- 38,55 ---- * 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 + #else + #include + #endif #include "libpq/pqsignal.h" *************** *** 127,132 **** --- 136,142 ---- } + #ifndef WIN32 /* * Set up a signal handler */ *************** *** 149,151 **** --- 159,392 ---- 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 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 -cr postgresql-snapshot/src/backend/main/main.c postgresql-win32/src/backend/main/main.c *** postgresql-snapshot/src/backend/main/main.c Sun Jan 11 04:49:31 2004 --- postgresql-win32/src/backend/main/main.c Sun Jan 25 22:38:38 2004 *************** *** 40,45 **** --- 40,48 ---- #include "utils/help_config.h" #include "utils/ps_status.h" #include "pgstat.h" + #ifdef WIN32 + #include "libpq/pqsignal.h" + #endif *************** *** 97,102 **** --- 100,107 ---- argv[0], err); exit(1); } + + pgwin32_signal_initialize(); } #endif diff -cr postgresql-snapshot/src/backend/port/sysv_sema.c postgresql-win32/src/backend/port/sysv_sema.c *** postgresql-snapshot/src/backend/port/sysv_sema.c Mon Dec 1 23:15:37 2003 --- postgresql-win32/src/backend/port/sysv_sema.c Sun Jan 25 22:37:57 2004 *************** *** 31,36 **** --- 31,37 ---- #include "miscadmin.h" #include "storage/ipc.h" #include "storage/pg_sema.h" + #include "libpq/pqsignal.h" #ifndef HAVE_UNION_SEMUN *************** *** 232,238 **** continue; /* oops, GETPID failed */ if (creatorPID != getpid()) { ! if (kill(creatorPID, 0) == 0 || errno != ESRCH) continue; /* sema belongs to a live process */ } --- 233,239 ---- continue; /* oops, GETPID failed */ if (creatorPID != getpid()) { ! if (pqkill(creatorPID, 0) == 0 || errno != ESRCH) continue; /* sema belongs to a live process */ } diff -cr postgresql-snapshot/src/backend/port/sysv_shmem.c postgresql-win32/src/backend/port/sysv_shmem.c *** postgresql-snapshot/src/backend/port/sysv_shmem.c Wed Jan 7 19:56:27 2004 --- postgresql-win32/src/backend/port/sysv_shmem.c Sun Jan 25 21:30:25 2004 *************** *** 33,38 **** --- 33,39 ---- #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,290 **** hdr = (PGShmemHeader *) memAddress; if (hdr->creatorPID != getpid()) { ! if (kill(hdr->creatorPID, 0) == 0 || errno != ESRCH) { shmdt(memAddress); continue; /* segment belongs to a live process */ --- 285,291 ---- hdr = (PGShmemHeader *) memAddress; if (hdr->creatorPID != getpid()) { ! if (pqkill(hdr->creatorPID, 0) == 0 || errno != ESRCH) { shmdt(memAddress); continue; /* segment belongs to a live process */ diff -cr postgresql-snapshot/src/backend/postmaster/postmaster.c postgresql-win32/src/backend/postmaster/postmaster.c *** postgresql-snapshot/src/backend/postmaster/postmaster.c Sun Jan 11 04:49:31 2004 --- postgresql-win32/src/backend/postmaster/postmaster.c Sun Jan 25 21:32:30 2004 *************** *** 1532,1538 **** ereport(DEBUG2, (errmsg_internal("processing cancel request: sending SIGINT to process %d", backendPID))); ! kill(bp->pid, SIGINT); } else /* Right PID, wrong key: no way, Jose */ --- 1532,1538 ---- ereport(DEBUG2, (errmsg_internal("processing cancel request: sending SIGINT to process %d", backendPID))); ! pqkill(bp->pid, SIGINT); } else /* Right PID, wrong key: no way, Jose */ *************** *** 1704,1710 **** * will start a new one with a possibly changed config */ if (BgWriterPID != 0) ! kill(BgWriterPID, SIGTERM); } PG_SETMASK(&UnBlockSig); --- 1704,1710 ---- * will start a new one with a possibly changed config */ if (BgWriterPID != 0) ! pqkill(BgWriterPID, SIGTERM); } PG_SETMASK(&UnBlockSig); *************** *** 1738,1744 **** * Wait for children to end their work and ShutdownDataBase. */ if (BgWriterPID != 0) ! kill(BgWriterPID, SIGTERM); if (Shutdown >= SmartShutdown) break; Shutdown = SmartShutdown; --- 1738,1744 ---- * Wait for children to end their work and ShutdownDataBase. */ if (BgWriterPID != 0) ! pqkill(BgWriterPID, SIGTERM); if (Shutdown >= SmartShutdown) break; Shutdown = SmartShutdown; *************** *** 1772,1778 **** * and exit) and ShutdownDataBase when they are gone. */ if (BgWriterPID != 0) ! kill(BgWriterPID, SIGTERM); if (Shutdown >= FastShutdown) break; ereport(LOG, --- 1772,1778 ---- * and exit) and ShutdownDataBase when they are gone. */ if (BgWriterPID != 0) ! pqkill(BgWriterPID, SIGTERM); if (Shutdown >= FastShutdown) break; ereport(LOG, *************** *** 1820,1832 **** * properly shutdown data base system. */ if (BgWriterPID != 0) ! kill(BgWriterPID, SIGQUIT); ereport(LOG, (errmsg("received immediate shutdown request"))); if (ShutdownPID > 0) ! kill(ShutdownPID, SIGQUIT); if (StartupPID > 0) ! kill(StartupPID, SIGQUIT); if (DLGetHead(BackendList)) SignalChildren(SIGQUIT); ExitPostmaster(0); --- 1820,1832 ---- * properly shutdown data base system. */ if (BgWriterPID != 0) ! pqkill(BgWriterPID, SIGQUIT); ereport(LOG, (errmsg("received immediate shutdown request"))); if (ShutdownPID > 0) ! pqkill(ShutdownPID, SIGQUIT); if (StartupPID > 0) ! pqkill(StartupPID, SIGQUIT); if (DLGetHead(BackendList)) SignalChildren(SIGQUIT); ExitPostmaster(0); *************** *** 2084,2090 **** (errmsg_internal("sending %s to process %d", (SendStop ? "SIGSTOP" : "SIGQUIT"), (int) bp->pid))); ! kill(bp->pid, (SendStop ? SIGSTOP : SIGQUIT)); } } else --- 2084,2090 ---- (errmsg_internal("sending %s to process %d", (SendStop ? "SIGSTOP" : "SIGQUIT"), (int) bp->pid))); ! pqkill(bp->pid, (SendStop ? SIGSTOP : SIGQUIT)); } } else *************** *** 2176,2182 **** (errmsg_internal("sending signal %d to process %d", signal, (int) bp->pid))); ! kill(bp->pid, signal); } curr = next; --- 2176,2182 ---- (errmsg_internal("sending signal %d to process %d", signal, (int) bp->pid))); ! pqkill(bp->pid, signal); } curr = next; diff -cr postgresql-snapshot/src/backend/storage/ipc/pmsignal.c postgresql-win32/src/backend/storage/ipc/pmsignal.c *** postgresql-snapshot/src/backend/storage/ipc/pmsignal.c Sun Jan 11 04:49:31 2004 --- postgresql-win32/src/backend/storage/ipc/pmsignal.c Sun Jan 25 22:37:18 2004 *************** *** 20,25 **** --- 20,26 ---- #include "miscadmin.h" #include "storage/pmsignal.h" #include "storage/shmem.h" + #include "libpq/pqsignal.h" /* *************** *** 64,70 **** /* Atomically set the proper flag */ PMSignalFlags[reason] = true; /* Send signal to postmaster (assume it is our direct parent) */ ! kill(getppid(), SIGUSR1); } /* --- 65,71 ---- /* Atomically set the proper flag */ PMSignalFlags[reason] = true; /* Send signal to postmaster (assume it is our direct parent) */ ! pqkill(getppid(), SIGUSR1); } /* diff -cr postgresql-snapshot/src/backend/storage/lmgr/proc.c postgresql-win32/src/backend/storage/lmgr/proc.c *** postgresql-snapshot/src/backend/storage/lmgr/proc.c Wed Jan 7 19:56:27 2004 --- postgresql-win32/src/backend/storage/lmgr/proc.c Sun Jan 25 21:34:48 2004 *************** *** 51,56 **** --- 51,57 ---- #include "storage/proc.h" #include "storage/sinval.h" #include "storage/spin.h" + #include "libpq/pqsignal.h" /* GUC variables */ int DeadlockTimeout = 1000; *************** *** 1130,1136 **** { /* Time to die */ statement_timeout_active = false; ! kill(MyProcPid, SIGINT); } else { --- 1131,1137 ---- { /* Time to die */ statement_timeout_active = false; ! pqkill(MyProcPid, SIGINT); } else { diff -cr postgresql-snapshot/src/backend/utils/init/miscinit.c postgresql-win32/src/backend/utils/init/miscinit.c *** postgresql-snapshot/src/backend/utils/init/miscinit.c Thu Jan 8 07:01:21 2004 --- postgresql-win32/src/backend/utils/init/miscinit.c Sun Jan 25 21:36:15 2004 *************** *** 32,37 **** --- 32,38 ---- #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,537 **** */ if (other_pid != my_pid) { ! if (kill(other_pid, 0) == 0 || (errno != ESRCH #ifdef __BEOS__ && errno != EINVAL --- 532,538 ---- */ if (other_pid != my_pid) { ! if (pqkill(other_pid, 0) == 0 || (errno != ESRCH #ifdef __BEOS__ && errno != EINVAL diff -cr postgresql-snapshot/src/include/libpq/pqsignal.h postgresql-win32/src/include/libpq/pqsignal.h *** postgresql-snapshot/src/include/libpq/pqsignal.h Sat Nov 29 23:41:03 2003 --- postgresql-win32/src/include/libpq/pqsignal.h Sun Jan 25 22:00:43 2004 *************** *** 18,24 **** --- 18,35 ---- #ifndef PQSIGNAL_H #define PQSIGNAL_H + #ifndef WIN32 #include + #endif + + #ifndef WIN32 + #define pqkill(pid,sig) kill(pid,sig) + #define pqsigsetmask(mask) sigsetmask(mask) + #else + int pqkill(int pid, int sig); + int pqsigsetmask(int mask); + #endif + #ifdef HAVE_SIGPROCMASK extern sigset_t UnBlockSig, *************** *** 31,37 **** BlockSig, AuthBlockSig; ! #define PG_SETMASK(mask) sigsetmask(*((int*)(mask))) #endif typedef void (*pqsigfunc) (int); --- 42,48 ---- BlockSig, AuthBlockSig; ! #define PG_SETMASK(mask) pqsigsetmask(*((int*)(mask))) #endif typedef void (*pqsigfunc) (int); *************** *** 39,43 **** --- 50,170 ---- extern void pqinitmask(void); extern pqsigfunc pqsignal(int signo, pqsigfunc func); + + #ifdef WIN32 + #define sigmask(sig) ( 1 << (sig-1) ) + + void pgwin32_signal_initialize(void); + extern HANDLE pgwin32_main_thread_handle; + #define PG_POLL_SIGNALS() WaitForSingleObjectEx(pgwin32_main_thread_handle,0,TRUE); + + /* Define signal numbers. Override system values, since they are not + complete anyway */ + + #undef SIGHUP + #define SIGHUP 1 /* hangup */ + + #undef SIGINT + #define SIGINT 2 /* interrupt */ + + #undef SIGQUIT + #define SIGQUIT 3 /* quit */ + + #undef SIGILL + #define SIGILL 4 /* illegal instruction (not reset when caught) */ + + #undef SIGTRAP + #define SIGTRAP 5 /* trace trap (not reset when caught) */ + + #undef SIGABRT + #define SIGABRT 6 /* abort(void) */ + + #undef SIGIOT + #define SIGIOT SIGABRT /* compatibility */ + + #undef SIGEMT + #define SIGEMT 7 /* EMT instruction */ + + #undef SIGFPE + #define SIGFPE 8 /* floating point exception */ + + #undef SIGKILL + #define SIGKILL 9 /* kill (cannot be caught or ignored) */ + + #undef SIGBUS + #define SIGBUS 10 /* bus error */ + + #undef SIGSEGV + #define SIGSEGV 11 /* segmentation violation */ + + #undef SIGSYS + #define SIGSYS 12 /* non-existent system call invoked */ + + #undef SIGSYS + #define SIGPIPE 13 /* write on a pipe with no one to read it */ + + #undef SIGALRM + #define SIGALRM 14 /* alarm clock */ + + #undef SIGTERM + #define SIGTERM 15 /* software termination signal from kill */ + + #undef SIGURG + #define SIGURG 16 /* urgent condition on IO channel */ + + #undef SIGSTOP + #define SIGSTOP 17 /* sendable stop signal not from tty */ + + #undef SIGTSTP + #define SIGTSTP 18 /* stop signal from tty */ + + #undef SIGCONT + #define SIGCONT 19 /* continue a stopped process */ + + #undef SIGCHLD + #define SIGCHLD 20 /* to parent on child stop or exit */ + + #undef SIGTTIN + #define SIGTTIN 21 /* to readers pgrp upon background tty read */ + + #undef SIGTTOU + #define SIGTTOU 22 /* like TTIN for output if (tp->t_local<OSTOP) */ + + #undef SIGIO + #define SIGIO 23 /* input/output possible signal */ + + #undef SIGXCPU + #define SIGXCPU 24 /* exceeded CPU time limit */ + + #undef SIGXFSZ + #define SIGXFSZ 25 /* exceeded file size limit */ + + #undef SIGVTALR + #define SIGVTALRM 26 /* virtual time alarm */ + + #undef SIGPROF + #define SIGPROF 27 /* profiling time alarm */ + + #undef SIGWINCH + #define SIGWINCH 28 /* window size changes */ + + #undef SIGINFO + #define SIGINFO 29 /* information request */ + + #undef SIGUSR1 + #define SIGUSR1 30 /* user defined signal 1 */ + + #undef SIGUSR2 + #define SIGUSR2 31 /* user defined signal 2 */ + + #undef SIG_DFL + #undef SIG_ERR + #undef SIG_IGN + #define SIG_DFL ((pqsigfunc)0) + #define SIG_ERR ((pqsigfunc)-1) + #define SIG_IGN ((pqsigfunc)1) + + #endif #endif /* PQSIGNAL_H */