9
9
*
10
10
*
11
11
* 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 $
13
13
*
14
14
* NOTES
15
15
* This shouldn't be in libpq, but the monitor and some other
38
38
* is to do signal-handler reinstallation, which doesn't work well
39
39
* at all.
40
40
* ------------------------------------------------------------------------*/
41
+ #ifdef WIN32
42
+ #define WIN32_LEAN_AND_MEAN
43
+ #define _WIN32_WINNT 0x0400
44
+ #endif
45
+
41
46
#include "postgres.h"
42
47
48
+ #ifndef WIN32
43
49
#include <signal.h>
50
+ #else
51
+ #include <windows.h>
52
+ #endif
44
53
45
54
#include "libpq/pqsignal.h"
46
55
@@ -127,6 +136,7 @@ pqinitmask(void)
127
136
}
128
137
129
138
139
+ #ifndef WIN32
130
140
/*
131
141
* Set up a signal handler
132
142
*/
@@ -149,3 +159,234 @@ pqsignal(int signo, pqsigfunc func)
149
159
return oact .sa_handler ;
150
160
#endif /* !HAVE_POSIX_SIGNALS */
151
161
}
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
0 commit comments