Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 5049196

Browse files
committed
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
1 parent eec08b9 commit 5049196

File tree

10 files changed

+404
-26
lines changed

10 files changed

+404
-26
lines changed

src/backend/commands/async.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
99
* IDENTIFICATION
10-
* $PostgreSQL: pgsql/src/backend/commands/async.c,v 1.107 2004/01/07 18:56:25 neilc Exp $
10+
* $PostgreSQL: pgsql/src/backend/commands/async.c,v 1.108 2004/01/27 00:45:26 momjian Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -83,6 +83,7 @@
8383
#include "commands/async.h"
8484
#include "libpq/libpq.h"
8585
#include "libpq/pqformat.h"
86+
#include "libpq/pqsignal.h"
8687
#include "miscadmin.h"
8788
#include "storage/ipc.h"
8889
#include "tcop/tcopprot.h"
@@ -497,7 +498,7 @@ AtCommit_Notify(void)
497498
* for some reason. It's OK to send the signal first, because
498499
* the other guy can't read pg_listener until we unlock it.
499500
*/
500-
if (kill(listenerPID, SIGUSR2) < 0)
501+
if (pqkill(listenerPID, SIGUSR2) < 0)
501502
{
502503
/*
503504
* Get rid of pg_listener entry if it refers to a PID that

src/backend/libpq/pqsignal.c

Lines changed: 242 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $PostgreSQL: pgsql/src/backend/libpq/pqsignal.c,v 1.28 2003/11/29 19:51:49 pgsql Exp $
12+
* $PostgreSQL: pgsql/src/backend/libpq/pqsignal.c,v 1.29 2004/01/27 00:45:26 momjian Exp $
1313
*
1414
* NOTES
1515
* This shouldn't be in libpq, but the monitor and some other
@@ -38,9 +38,18 @@
3838
* is to do signal-handler reinstallation, which doesn't work well
3939
* at all.
4040
* ------------------------------------------------------------------------*/
41+
#ifdef WIN32
42+
#define WIN32_LEAN_AND_MEAN
43+
#define _WIN32_WINNT 0x0400
44+
#endif
45+
4146
#include "postgres.h"
4247

48+
#ifndef WIN32
4349
#include <signal.h>
50+
#else
51+
#include <windows.h>
52+
#endif
4453

4554
#include "libpq/pqsignal.h"
4655

@@ -127,6 +136,7 @@ pqinitmask(void)
127136
}
128137

129138

139+
#ifndef WIN32
130140
/*
131141
* Set up a signal handler
132142
*/
@@ -149,3 +159,234 @@ pqsignal(int signo, pqsigfunc func)
149159
return oact.sa_handler;
150160
#endif /* !HAVE_POSIX_SIGNALS */
151161
}
162+
163+
164+
#else
165+
166+
167+
/* Win32 specific signals code */
168+
169+
/* pg_signal_crit_sec is used to protect only pg_signal_queue. That is the only
170+
* variable that can be accessed from the signal sending threads! */
171+
static CRITICAL_SECTION pg_signal_crit_sec;
172+
static int pg_signal_queue;
173+
174+
#define PG_SIGNAL_COUNT 32
175+
static pqsigfunc pg_signal_array[PG_SIGNAL_COUNT];
176+
static pqsigfunc pg_signal_defaults[PG_SIGNAL_COUNT];
177+
static int pg_signal_mask;
178+
179+
HANDLE pgwin32_main_thread_handle;
180+
181+
/* Signal handling thread function */
182+
static DWORD WINAPI pg_signal_thread(LPVOID param);
183+
184+
/* Initialization */
185+
void pgwin32_signal_initialize(void) {
186+
int i;
187+
HANDLE signal_thread_handle;
188+
InitializeCriticalSection(&pg_signal_crit_sec);
189+
190+
for (i = 0; i < PG_SIGNAL_COUNT; i++) {
191+
pg_signal_array[i] = SIG_DFL;
192+
pg_signal_defaults[i] = SIG_IGN;
193+
}
194+
pg_signal_mask = 0;
195+
pg_signal_queue = 0;
196+
197+
/* Get handle to main thread so we can post calls to it later */
198+
if (!DuplicateHandle(GetCurrentProcess(),GetCurrentThread(),
199+
GetCurrentProcess(),&pgwin32_main_thread_handle,
200+
0,FALSE,DUPLICATE_SAME_ACCESS)) {
201+
fprintf(stderr,gettext("Failed to get main thread handle!\n"));
202+
exit(1);
203+
}
204+
205+
/* Create thread for handling signals */
206+
signal_thread_handle = CreateThread(NULL,0,pg_signal_thread,NULL,0,NULL);
207+
if (signal_thread_handle == NULL) {
208+
fprintf(stderr,gettext("Failed to create signal handler thread!\n"));
209+
exit(1);
210+
}
211+
}
212+
213+
214+
/* Dispatch all signals currently queued and not blocked
215+
* Blocked signals are ignored, and will be fired at the time of
216+
* the sigsetmask() call. */
217+
static void dispatch_queued_signals(void) {
218+
int i;
219+
220+
EnterCriticalSection(&pg_signal_crit_sec);
221+
while (pg_signal_queue & ~pg_signal_mask) {
222+
/* One or more unblocked signals queued for execution */
223+
224+
int exec_mask = pg_signal_queue & ~pg_signal_mask;
225+
226+
for (i = 0; i < PG_SIGNAL_COUNT; i++) {
227+
if (exec_mask & sigmask(i)) {
228+
/* Execute this signal */
229+
pqsigfunc sig = pg_signal_array[i];
230+
if (sig == SIG_DFL)
231+
sig = pg_signal_defaults[i];
232+
pg_signal_queue &= ~sigmask(i);
233+
if (sig != SIG_ERR && sig != SIG_IGN && sig != SIG_DFL) {
234+
LeaveCriticalSection(&pg_signal_crit_sec);
235+
sig(i);
236+
EnterCriticalSection(&pg_signal_crit_sec);
237+
break; /* Restart outer loop, in case signal mask or queue
238+
has been modified inside signal handler */
239+
}
240+
}
241+
}
242+
}
243+
LeaveCriticalSection(&pg_signal_crit_sec);
244+
}
245+
246+
/* signal masking. Only called on main thread, no sync required */
247+
int pqsigsetmask(int mask) {
248+
int prevmask;
249+
prevmask = pg_signal_mask;
250+
pg_signal_mask = mask;
251+
252+
/* Dispatch any signals queued up right away, in case we have
253+
unblocked one or more signals previously queued */
254+
dispatch_queued_signals();
255+
256+
return prevmask;
257+
}
258+
259+
260+
/* signal manipulation. Only called on main thread, no sync required */
261+
pqsigfunc pqsignal(int signum, pqsigfunc handler) {
262+
pqsigfunc prevfunc;
263+
if (signum >= PG_SIGNAL_COUNT || signum < 0)
264+
return SIG_ERR;
265+
prevfunc = pg_signal_array[signum];
266+
pg_signal_array[signum] = handler;
267+
return prevfunc;
268+
}
269+
270+
/* signal sending */
271+
int pqkill(int pid, int sig) {
272+
char pipename[128];
273+
BYTE sigData = sig;
274+
BYTE sigRet = 0;
275+
DWORD bytes;
276+
277+
if (sig >= PG_SIGNAL_COUNT || sig <= 0) {
278+
errno = EINVAL;
279+
return -1;
280+
}
281+
if (pid <= 0) {
282+
/* No support for process groups */
283+
errno = EINVAL;
284+
return -1;
285+
}
286+
wsprintf(pipename,"\\\\.\\pipe\\pgsignal_%i",pid);
287+
if (!CallNamedPipe(pipename,&sigData,1,&sigRet,1,&bytes,1000)) {
288+
if (GetLastError() == ERROR_FILE_NOT_FOUND)
289+
errno = ESRCH;
290+
else if (GetLastError() == ERROR_ACCESS_DENIED)
291+
errno = EPERM;
292+
else
293+
errno = EINVAL;
294+
return -1;
295+
}
296+
if (bytes != 1 || sigRet != sig) {
297+
errno = ESRCH;
298+
return -1;
299+
}
300+
301+
return 0;
302+
}
303+
304+
/* APC callback scheduled on main thread when signals are fired */
305+
static void CALLBACK pg_signal_apc(ULONG_PTR param) {
306+
dispatch_queued_signals();
307+
}
308+
309+
/*
310+
* All functions below execute on the signal handler thread
311+
* and must be synchronized as such!
312+
* NOTE! The only global variable that can be used is
313+
* pg_signal_queue!
314+
*/
315+
316+
317+
static void pg_queue_signal(int signum) {
318+
if (signum >= PG_SIGNAL_COUNT || signum < 0)
319+
return;
320+
321+
EnterCriticalSection(&pg_signal_crit_sec);
322+
pg_signal_queue |= sigmask(signum);
323+
LeaveCriticalSection(&pg_signal_crit_sec);
324+
325+
QueueUserAPC(pg_signal_apc,pgwin32_main_thread_handle,(ULONG_PTR)NULL);
326+
}
327+
328+
/* Signal dispatching thread */
329+
static DWORD WINAPI pg_signal_dispatch_thread(LPVOID param) {
330+
HANDLE pipe = (HANDLE)param;
331+
BYTE sigNum;
332+
DWORD bytes;
333+
334+
if (!ReadFile(pipe,&sigNum,1,&bytes,NULL)) {
335+
/* Client died before sending */
336+
CloseHandle(pipe);
337+
return 0;
338+
}
339+
if (bytes != 1) {
340+
/* Received <bytes> bytes over signal pipe (should be 1) */
341+
CloseHandle(pipe);
342+
return 0;
343+
}
344+
WriteFile(pipe,&sigNum,1,&bytes,NULL); /* Don't care if it works or not.. */
345+
FlushFileBuffers(pipe);
346+
DisconnectNamedPipe(pipe);
347+
CloseHandle(pipe);
348+
349+
pg_queue_signal(sigNum);
350+
return 0;
351+
}
352+
353+
/* Signal handling thread */
354+
static DWORD WINAPI pg_signal_thread(LPVOID param) {
355+
char pipename[128];
356+
HANDLE pipe = INVALID_HANDLE_VALUE;
357+
358+
wsprintf(pipename,"\\\\.\\pipe\\pgsignal_%i",GetCurrentProcessId());
359+
360+
for (;;) {
361+
BOOL fConnected;
362+
HANDLE hThread;
363+
364+
pipe = CreateNamedPipe(pipename,PIPE_ACCESS_DUPLEX,
365+
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
366+
PIPE_UNLIMITED_INSTANCES,16,16,1000,NULL);
367+
if (pipe == INVALID_HANDLE_VALUE) {
368+
fprintf(stderr,gettext("Failed to create signal listener pipe: %i. Retrying.\n"),(int)GetLastError());
369+
SleepEx(500,TRUE);
370+
continue;
371+
}
372+
373+
fConnected = ConnectNamedPipe(pipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
374+
if (fConnected) {
375+
hThread = CreateThread(NULL, 0,
376+
(LPTHREAD_START_ROUTINE)pg_signal_dispatch_thread,
377+
(LPVOID)pipe,0,NULL);
378+
if (hThread == INVALID_HANDLE_VALUE) {
379+
fprintf(stderr,gettext("Failed to create signal dispatch thread: %i\n"),(int)GetLastError());
380+
}
381+
else
382+
CloseHandle(hThread);
383+
}
384+
else
385+
/* Connection failed. Cleanup and try again */
386+
CloseHandle(pipe);
387+
}
388+
return 0;
389+
}
390+
391+
392+
#endif

src/backend/main/main.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*
1414
*
1515
* IDENTIFICATION
16-
* $PostgreSQL: pgsql/src/backend/main/main.c,v 1.71 2004/01/11 03:49:31 momjian Exp $
16+
* $PostgreSQL: pgsql/src/backend/main/main.c,v 1.72 2004/01/27 00:45:26 momjian Exp $
1717
*
1818
*-------------------------------------------------------------------------
1919
*/
@@ -40,6 +40,9 @@
4040
#include "utils/help_config.h"
4141
#include "utils/ps_status.h"
4242
#include "pgstat.h"
43+
#ifdef WIN32
44+
#include "libpq/pqsignal.h"
45+
#endif
4346

4447

4548

@@ -97,6 +100,8 @@ main(int argc, char *argv[])
97100
argv[0], err);
98101
exit(1);
99102
}
103+
104+
pgwin32_signal_initialize();
100105
}
101106
#endif
102107

src/backend/port/sysv_sema.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/port/sysv_sema.c,v 1.12 2003/12/01 22:15:37 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/port/sysv_sema.c,v 1.13 2004/01/27 00:45:26 momjian Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -31,6 +31,7 @@
3131
#include "miscadmin.h"
3232
#include "storage/ipc.h"
3333
#include "storage/pg_sema.h"
34+
#include "libpq/pqsignal.h"
3435

3536

3637
#ifndef HAVE_UNION_SEMUN
@@ -232,7 +233,7 @@ IpcSemaphoreCreate(int numSems)
232233
continue; /* oops, GETPID failed */
233234
if (creatorPID != getpid())
234235
{
235-
if (kill(creatorPID, 0) == 0 ||
236+
if (pqkill(creatorPID, 0) == 0 ||
236237
errno != ESRCH)
237238
continue; /* sema belongs to a live process */
238239
}

src/backend/port/sysv_shmem.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* Portions Copyright (c) 1994, Regents of the University of California
1111
*
1212
* IDENTIFICATION
13-
* $PostgreSQL: pgsql/src/backend/port/sysv_shmem.c,v 1.28 2004/01/07 18:56:27 neilc Exp $
13+
* $PostgreSQL: pgsql/src/backend/port/sysv_shmem.c,v 1.29 2004/01/27 00:45:26 momjian Exp $
1414
*
1515
*-------------------------------------------------------------------------
1616
*/
@@ -33,6 +33,7 @@
3333
#include "miscadmin.h"
3434
#include "storage/ipc.h"
3535
#include "storage/pg_shmem.h"
36+
#include "libpq/pqsignal.h"
3637

3738

3839
typedef key_t IpcMemoryKey; /* shared memory key passed to shmget(2) */
@@ -284,7 +285,7 @@ PGSharedMemoryCreate(uint32 size, bool makePrivate, int port)
284285
hdr = (PGShmemHeader *) memAddress;
285286
if (hdr->creatorPID != getpid())
286287
{
287-
if (kill(hdr->creatorPID, 0) == 0 || errno != ESRCH)
288+
if (pqkill(hdr->creatorPID, 0) == 0 || errno != ESRCH)
288289
{
289290
shmdt(memAddress);
290291
continue; /* segment belongs to a live process */

0 commit comments

Comments
 (0)