00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "postgres.h"
00015
00016 #include "libpq/pqsignal.h"
00017
00018
00019
00020
00021
00022
00023
00024 volatile int pg_signal_queue;
00025 int pg_signal_mask;
00026
00027 HANDLE pgwin32_signal_event;
00028 HANDLE pgwin32_initial_signal_pipe = INVALID_HANDLE_VALUE;
00029
00030
00031
00032
00033
00034 static CRITICAL_SECTION pg_signal_crit_sec;
00035
00036 static pqsigfunc pg_signal_array[PG_SIGNAL_COUNT];
00037 static pqsigfunc pg_signal_defaults[PG_SIGNAL_COUNT];
00038
00039
00040
00041 static DWORD WINAPI pg_signal_thread(LPVOID param);
00042 static BOOL WINAPI pg_console_handler(DWORD dwCtrlType);
00043
00044
00045
00046
00047
00048
00049
00050
00051 void
00052 pg_usleep(long microsec)
00053 {
00054 if (WaitForSingleObject(pgwin32_signal_event,
00055 (microsec < 500 ? 1 : (microsec + 500) / 1000))
00056 == WAIT_OBJECT_0)
00057 {
00058 pgwin32_dispatch_queued_signals();
00059 errno = EINTR;
00060 return;
00061 }
00062 }
00063
00064
00065
00066 void
00067 pgwin32_signal_initialize(void)
00068 {
00069 int i;
00070 HANDLE signal_thread_handle;
00071
00072 InitializeCriticalSection(&pg_signal_crit_sec);
00073
00074 for (i = 0; i < PG_SIGNAL_COUNT; i++)
00075 {
00076 pg_signal_array[i] = SIG_DFL;
00077 pg_signal_defaults[i] = SIG_IGN;
00078 }
00079 pg_signal_mask = 0;
00080 pg_signal_queue = 0;
00081
00082
00083 pgwin32_signal_event = CreateEvent(NULL, TRUE, FALSE, NULL);
00084 if (pgwin32_signal_event == NULL)
00085 ereport(FATAL,
00086 (errmsg_internal("could not create signal event: error code %lu", GetLastError())));
00087
00088
00089 signal_thread_handle = CreateThread(NULL, 0, pg_signal_thread, NULL, 0, NULL);
00090 if (signal_thread_handle == NULL)
00091 ereport(FATAL,
00092 (errmsg_internal("could not create signal handler thread")));
00093
00094
00095 if (!SetConsoleCtrlHandler(pg_console_handler, TRUE))
00096 ereport(FATAL,
00097 (errmsg_internal("could not set console control handler")));
00098 }
00099
00100
00101
00102
00103
00104
00105 void
00106 pgwin32_dispatch_queued_signals(void)
00107 {
00108 int i;
00109
00110 EnterCriticalSection(&pg_signal_crit_sec);
00111 while (UNBLOCKED_SIGNAL_QUEUE())
00112 {
00113
00114 int exec_mask = UNBLOCKED_SIGNAL_QUEUE();
00115
00116 for (i = 0; i < PG_SIGNAL_COUNT; i++)
00117 {
00118 if (exec_mask & sigmask(i))
00119 {
00120
00121 pqsigfunc sig = pg_signal_array[i];
00122
00123 if (sig == SIG_DFL)
00124 sig = pg_signal_defaults[i];
00125 pg_signal_queue &= ~sigmask(i);
00126 if (sig != SIG_ERR && sig != SIG_IGN && sig != SIG_DFL)
00127 {
00128 LeaveCriticalSection(&pg_signal_crit_sec);
00129 sig(i);
00130 EnterCriticalSection(&pg_signal_crit_sec);
00131 break;
00132
00133
00134 }
00135 }
00136 }
00137 }
00138 ResetEvent(pgwin32_signal_event);
00139 LeaveCriticalSection(&pg_signal_crit_sec);
00140 }
00141
00142
00143 int
00144 pqsigsetmask(int mask)
00145 {
00146 int prevmask;
00147
00148 prevmask = pg_signal_mask;
00149 pg_signal_mask = mask;
00150
00151
00152
00153
00154
00155 pgwin32_dispatch_queued_signals();
00156
00157 return prevmask;
00158 }
00159
00160
00161
00162
00163
00164
00165
00166 pqsigfunc
00167 pqsignal(int signum, pqsigfunc handler)
00168 {
00169 pqsigfunc prevfunc;
00170
00171 if (signum >= PG_SIGNAL_COUNT || signum < 0)
00172 return SIG_ERR;
00173 prevfunc = pg_signal_array[signum];
00174 pg_signal_array[signum] = handler;
00175 return prevfunc;
00176 }
00177
00178
00179 HANDLE
00180 pgwin32_create_signal_listener(pid_t pid)
00181 {
00182 char pipename[128];
00183 HANDLE pipe;
00184
00185 snprintf(pipename, sizeof(pipename), "\\\\.\\pipe\\pgsignal_%u", (int) pid);
00186
00187 pipe = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX,
00188 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
00189 PIPE_UNLIMITED_INSTANCES, 16, 16, 1000, NULL);
00190
00191 if (pipe == INVALID_HANDLE_VALUE)
00192 ereport(ERROR,
00193 (errmsg("could not create signal listener pipe for PID %d: error code %lu",
00194 (int) pid, GetLastError())));
00195
00196 return pipe;
00197 }
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208 void
00209 pg_queue_signal(int signum)
00210 {
00211 if (signum >= PG_SIGNAL_COUNT || signum <= 0)
00212 return;
00213
00214 EnterCriticalSection(&pg_signal_crit_sec);
00215 pg_signal_queue |= sigmask(signum);
00216 LeaveCriticalSection(&pg_signal_crit_sec);
00217
00218 SetEvent(pgwin32_signal_event);
00219 }
00220
00221
00222 static DWORD WINAPI
00223 pg_signal_dispatch_thread(LPVOID param)
00224 {
00225 HANDLE pipe = (HANDLE) param;
00226 BYTE sigNum;
00227 DWORD bytes;
00228
00229 if (!ReadFile(pipe, &sigNum, 1, &bytes, NULL))
00230 {
00231
00232 CloseHandle(pipe);
00233 return 0;
00234 }
00235 if (bytes != 1)
00236 {
00237
00238 CloseHandle(pipe);
00239 return 0;
00240 }
00241 WriteFile(pipe, &sigNum, 1, &bytes, NULL);
00242
00243 FlushFileBuffers(pipe);
00244 DisconnectNamedPipe(pipe);
00245 CloseHandle(pipe);
00246
00247 pg_queue_signal(sigNum);
00248 return 0;
00249 }
00250
00251
00252 static DWORD WINAPI
00253 pg_signal_thread(LPVOID param)
00254 {
00255 char pipename[128];
00256 HANDLE pipe = pgwin32_initial_signal_pipe;
00257
00258 snprintf(pipename, sizeof(pipename), "\\\\.\\pipe\\pgsignal_%lu", GetCurrentProcessId());
00259
00260 for (;;)
00261 {
00262 BOOL fConnected;
00263 HANDLE hThread;
00264
00265 if (pipe == INVALID_HANDLE_VALUE)
00266 {
00267 pipe = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX,
00268 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
00269 PIPE_UNLIMITED_INSTANCES, 16, 16, 1000, NULL);
00270
00271 if (pipe == INVALID_HANDLE_VALUE)
00272 {
00273 write_stderr("could not create signal listener pipe: error code %lu; retrying\n", GetLastError());
00274 SleepEx(500, FALSE);
00275 continue;
00276 }
00277 }
00278
00279 fConnected = ConnectNamedPipe(pipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
00280 if (fConnected)
00281 {
00282 HANDLE newpipe;
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294 newpipe = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX,
00295 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
00296 PIPE_UNLIMITED_INSTANCES, 16, 16, 1000, NULL);
00297 if (newpipe == INVALID_HANDLE_VALUE)
00298 {
00299
00300
00301
00302
00303
00304
00305 write_stderr("could not create signal listener pipe: error code %lu; retrying\n", GetLastError());
00306
00307
00308
00309
00310
00311 }
00312 hThread = CreateThread(NULL, 0,
00313 (LPTHREAD_START_ROUTINE) pg_signal_dispatch_thread,
00314 (LPVOID) pipe, 0, NULL);
00315 if (hThread == INVALID_HANDLE_VALUE)
00316 write_stderr("could not create signal dispatch thread: error code %lu\n",
00317 GetLastError());
00318 else
00319 CloseHandle(hThread);
00320
00321
00322
00323
00324
00325
00326 pipe = newpipe;
00327 }
00328 else
00329 {
00330
00331
00332
00333
00334
00335
00336 CloseHandle(pipe);
00337 pipe = INVALID_HANDLE_VALUE;
00338 }
00339 }
00340 return 0;
00341 }
00342
00343
00344
00345
00346 static BOOL WINAPI
00347 pg_console_handler(DWORD dwCtrlType)
00348 {
00349 if (dwCtrlType == CTRL_C_EVENT ||
00350 dwCtrlType == CTRL_BREAK_EVENT ||
00351 dwCtrlType == CTRL_CLOSE_EVENT ||
00352 dwCtrlType == CTRL_SHUTDOWN_EVENT)
00353 {
00354 pg_queue_signal(SIGINT);
00355 return TRUE;
00356 }
00357 return FALSE;
00358 }