Index: backend/main/main.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/main/main.c,v retrieving revision 1.92 diff -c -r1.92 main.c *** backend/main/main.c 5 Nov 2004 17:11:17 -0000 1.92 --- backend/main/main.c 11 Nov 2004 20:33:11 -0000 *************** *** 118,126 **** argv[0], err); exit(1); } - - /* Start our win32 signal implementation */ - pgwin32_signal_initialize(); } #endif --- 118,123 ---- *************** *** 281,286 **** --- 278,291 ---- exit(SubPostmasterMain(argc, argv)); #endif + #ifdef WIN32 + /* Start our win32 signal implementation + * SubPostmasterMain() will do this when it's called, but all other + * modes need it here */ + pgwin32_signal_initialize(); + #endif + + /* * If the first argument is "-boot", then invoke bootstrap mode. (This * path is taken only for a standalone bootstrap process.) Index: backend/port/win32/signal.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/port/win32/signal.c,v retrieving revision 1.9 diff -c -r1.9 signal.c *** backend/port/win32/signal.c 9 Nov 2004 13:01:25 -0000 1.9 --- backend/port/win32/signal.c 12 Nov 2004 19:54:32 -0000 *************** *** 26,31 **** --- 26,32 ---- static int pg_signal_mask; DLLIMPORT HANDLE pgwin32_signal_event; + HANDLE pgwin32_initial_signal_pipe = INVALID_HANDLE_VALUE; /* Signal handling thread function */ *************** *** 154,159 **** --- 155,183 ---- return prevfunc; } + /* Create the signal listener pipe for specified pid */ + HANDLE pgwin32_create_signal_listener(pid_t pid) + { + char pipename[128]; + HANDLE pipe = INVALID_HANDLE_VALUE; + + wsprintf(pipename, "\\\\.\\pipe\\pgsignal_%d", pid); + + 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) + { + ereport(ERROR, + (errmsg("could not create signal listener pipe for pid %i: error code %i", + pid, (int) GetLastError()))); + } + + return pipe; + } + + /* * All functions below execute on the signal handler thread * and must be synchronized as such! *************** *** 210,232 **** pg_signal_thread(LPVOID param) { char pipename[128]; ! HANDLE pipe = INVALID_HANDLE_VALUE; wsprintf(pipename, "\\\\.\\pipe\\pgsignal_%d", 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) { ! write_stderr("could not create signal listener pipe: error code %d; retrying\n", (int) GetLastError()); ! SleepEx(500, FALSE); ! continue; } fConnected = ConnectNamedPipe(pipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); --- 234,260 ---- pg_signal_thread(LPVOID param) { char pipename[128]; ! HANDLE pipe = pgwin32_initial_signal_pipe; wsprintf(pipename, "\\\\.\\pipe\\pgsignal_%d", GetCurrentProcessId()); ! for (;;) { BOOL fConnected; HANDLE hThread; if (pipe == INVALID_HANDLE_VALUE) { ! 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) ! { ! write_stderr("could not create signal listener pipe: error code %d; retrying\n", (int) GetLastError()); ! SleepEx(500, FALSE); ! continue; ! } } fConnected = ConnectNamedPipe(pipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); *************** *** 244,249 **** --- 272,280 ---- else /* Connection failed. Cleanup and try again */ CloseHandle(pipe); + + /* Set up so we create a new pipe on next loop */ + pipe = INVALID_HANDLE_VALUE; } return 0; } Index: backend/postmaster/pgstat.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/postmaster/pgstat.c,v retrieving revision 1.84 diff -c -r1.84 pgstat.c *** backend/postmaster/pgstat.c 28 Oct 2004 01:38:41 -0000 1.84 --- backend/postmaster/pgstat.c 12 Nov 2004 19:55:04 -0000 *************** *** 110,117 **** * ---------- */ NON_EXEC_STATIC int pgStatSock = -1; ! static int pgStatPipe[2]; static struct sockaddr_storage pgStatAddr; static time_t last_pgstat_start_time; --- 110,118 ---- * ---------- */ NON_EXEC_STATIC int pgStatSock = -1; ! NON_EXEC_STATIC int pgStatPipe[2] = {-1,-1}; static struct sockaddr_storage pgStatAddr; + static pid_t pgStatCollectorPid = 0; static time_t last_pgstat_start_time; *************** *** 492,501 **** /* postgres_exec_path is not passed by write_backend_variables */ av[ac++] = postgres_exec_path; - /* Pipe file ids (those not passed by write_backend_variables) */ - snprintf(pgstatBuf[bufc++], 32, "%d", pgStatPipe[0]); - snprintf(pgstatBuf[bufc++], 32, "%d", pgStatPipe[1]); - /* Add to the arg list */ Assert(bufc <= lengthof(pgstatBuf)); for (i = 0; i < bufc; i++) --- 493,498 ---- *************** *** 517,528 **** static void pgstat_parseArgs(int argc, char *argv[]) { ! Assert(argc == 6); argc = 3; StrNCpy(postgres_exec_path, argv[argc++], MAXPGPATH); - pgStatPipe[0] = atoi(argv[argc++]); - pgStatPipe[1] = atoi(argv[argc++]); } #endif /* EXEC_BACKEND */ --- 514,523 ---- static void pgstat_parseArgs(int argc, char *argv[]) { ! Assert(argc == 4); argc = 3; StrNCpy(postgres_exec_path, argv[argc++], MAXPGPATH); } #endif /* EXEC_BACKEND */ *************** *** 1387,1396 **** #ifdef EXEC_BACKEND /* child becomes collector process */ ! switch (pgstat_forkexec(STAT_PROC_COLLECTOR)) #else ! switch (fork()) #endif { case -1: ereport(ERROR, --- 1382,1392 ---- #ifdef EXEC_BACKEND /* child becomes collector process */ ! pgStatCollectorPid = pgstat_forkexec(STAT_PROC_COLLECTOR); #else ! pgStatCollectorPid = fork(); #endif + switch (pgStatCollectorPid) { case -1: ereport(ERROR, *************** *** 1445,1451 **** pqsignal(SIGHUP, SIG_IGN); pqsignal(SIGINT, SIG_IGN); pqsignal(SIGTERM, SIG_IGN); ! pqsignal(SIGQUIT, SIG_IGN); pqsignal(SIGALRM, SIG_IGN); pqsignal(SIGPIPE, SIG_IGN); pqsignal(SIGUSR1, SIG_IGN); --- 1441,1447 ---- pqsignal(SIGHUP, SIG_IGN); pqsignal(SIGINT, SIG_IGN); pqsignal(SIGTERM, SIG_IGN); ! pqsignal(SIGQUIT, pgstat_exit); pqsignal(SIGALRM, SIG_IGN); pqsignal(SIGPIPE, SIG_IGN); pqsignal(SIGUSR1, SIG_IGN); *************** *** 1943,1948 **** --- 1939,1954 ---- * be cleaner to allow any pending messages to be sent, but that * creates a tradeoff against speed of exit. */ + + /* + * If running in bufferer, kill our collector as well. On some broken + * win32 systems, it does not shut down automatically because of issues + * with socket inheritance + */ + #ifdef WIN32 + if (pgStatCollectorPid > 0) + kill(pgStatCollectorPid, SIGQUIT); + #endif exit(0); } Index: backend/postmaster/postmaster.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/postmaster/postmaster.c,v retrieving revision 1.437 diff -c -r1.437 postmaster.c *** backend/postmaster/postmaster.c 9 Nov 2004 13:01:26 -0000 1.437 --- backend/postmaster/postmaster.c 12 Nov 2004 20:46:36 -0000 *************** *** 275,281 **** #ifdef EXEC_BACKEND #ifdef WIN32 - static pid_t win32_forkexec(const char *path, char *argv[]); static void win32_AddChild(pid_t pid, HANDLE handle); static void win32_RemoveChild(pid_t pid); static pid_t win32_waitpid(int *exitstatus); --- 275,280 ---- *************** *** 292,298 **** --- 291,302 ---- static pid_t internal_forkexec(int argc, char *argv[], Port *port); static void read_backend_variables(char *filename, Port *port); + #ifndef WIN32 static bool write_backend_variables(char *filename, Port *port); + #else + static bool write_backend_variables(char *filename, Port *port, HANDLE childProcess, pid_t childPid); + #endif + static void get_backend_variable_filename(char *filename); static void ShmemBackendArrayAdd(Backend *bn); static void ShmemBackendArrayRemove(pid_t pid); *************** *** 338,343 **** --- 341,351 ---- } } + #ifdef WIN32 + /* Start our win32 signal implementation */ + pgwin32_signal_initialize(); + #endif + /* * for security, no dir or file created can be group or other * accessible *************** *** 2820,2830 **** --- 2828,2848 ---- return internal_forkexec(ac, av, port); } + #ifndef WIN32 + /* + * internal_forkexec non-win32 implementation + * + * - writes out backend variables to the parameter file + * - fork():s, and then exec():s the child process + * + */ static pid_t internal_forkexec(int argc, char *argv[], Port *port) { pid_t pid; char tmpfilename[MAXPGPATH]; + + get_backend_variable_filename(tmpfilename); if (!write_backend_variables(tmpfilename, port)) return -1; /* log made by write_backend_variables */ *************** *** 2838,2846 **** /* Insert temp file name after -fork argument */ argv[2] = tmpfilename; - #ifdef WIN32 - pid = win32_forkexec(postgres_exec_path, argv); - #else /* Fire off execv in child */ if ((pid = fork()) == 0) { --- 2856,2861 ---- *************** *** 2853,2864 **** exit(1); } } - #endif return pid; /* Parent returns pid, or -1 on fork * failure */ } /* * SubPostmasterMain -- Get the fork/exec'd process into a state equivalent * to what it would be if we'd simply forked on Unix, and then --- 2868,3013 ---- exit(1); } } return pid; /* Parent returns pid, or -1 on fork * failure */ } + #else + /* + * internal_forkexec win32 implementation + * + * - starts backend using CreateProcess(), in suspended state + * - writes out backend variables to the parameter file + * - during this, duplicates handles and sockets required for + * inheritance into the new process + * - resumes execution of the new process once the backend parameter + * file is complete. + */ + static pid_t + internal_forkexec(int argc, char *argv[], Port *port) + { + STARTUPINFO si; + PROCESS_INFORMATION pi; + int i; + int j; + char cmdLine[MAXPGPATH * 2]; + HANDLE childHandleCopy; + HANDLE waiterThread; + char tmpfilename[MAXPGPATH]; + + /* Make sure caller set up argv properly */ + Assert(argc >= 3); + Assert(argv[argc] == NULL); + Assert(strncmp(argv[1], "-fork", 5) == 0); + Assert(argv[2] == NULL); + + /* Get the name of the parameter file, to put on the commandline */ + get_backend_variable_filename(tmpfilename); + + /* Insert temp file name after -fork argument */ + argv[2] = tmpfilename; + + /* Format the cmd line */ + cmdLine[sizeof(cmdLine) - 1] = '\0'; + cmdLine[sizeof(cmdLine) - 2] = '\0'; + snprintf(cmdLine, sizeof(cmdLine) - 1, "\"%s\"", postgres_exec_path); + i = 0; + while (argv[++i] != NULL) + { + j = strlen(cmdLine); + snprintf(cmdLine + j, sizeof(cmdLine) - 1 - j, " \"%s\"", argv[i]); + } + if (cmdLine[sizeof(cmdLine) - 2] != '\0') + { + elog(LOG, "subprocess command line too long"); + return -1; + } + + memset(&pi, 0, sizeof(pi)); + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + /* + * Create the subprocess in a suspended state. This will be resumed + * later, once we have written out the parameter file. + */ + if (!CreateProcess(NULL, cmdLine, NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) + { + elog(LOG, "CreateProcess call failed (%d): %m", (int) GetLastError()); + return -1; + } + + if (!write_backend_variables(tmpfilename, port, pi.hProcess, pi.dwProcessId)) + { + /* log made by write_backend_variables, but we have to clean + * up the mess with the half-started process */ + if (!TerminateProcess(pi.hProcess, 255)) + ereport(ERROR, + (errmsg_internal("could not terminate unstarted process: %i", + (int) GetLastError()))); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return -1; /* log made by write_backend_variables */ + } + + /* Now that the backend variables are written out, we start the + * child thread so it can start initializing while we set up + * the rest of the parent state. */ + if (ResumeThread(pi.hThread) == -1) + { + if (!TerminateProcess(pi.hProcess, 255)) + { + ereport(ERROR, + (errmsg_internal("could not terminate unstartable process: %i", + (int) GetLastError()))); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return -1; + } + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + ereport(ERROR, + (errmsg_internal("could not resume thread of unstarted process: %i", + (int) GetLastError()))); + return -1; + } + + if (!IsUnderPostmaster) + { + /* We are the Postmaster creating a child... */ + win32_AddChild(pi.dwProcessId, pi.hProcess); + } + + /* Set up the thread to handle the SIGCHLD for this process */ + if (DuplicateHandle(GetCurrentProcess(), + pi.hProcess, + GetCurrentProcess(), + &childHandleCopy, + 0, + FALSE, + DUPLICATE_SAME_ACCESS) == 0) + ereport(FATAL, + (errmsg_internal("could not duplicate child handle: %d", + (int) GetLastError()))); + + waiterThread = CreateThread(NULL, 64 * 1024, win32_sigchld_waiter, + (LPVOID) childHandleCopy, 0, NULL); + if (!waiterThread) + ereport(FATAL, + (errmsg_internal("could not create sigchld waiter thread: %d", + (int) GetLastError()))); + CloseHandle(waiterThread); + + if (IsUnderPostmaster) + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + + return pi.dwProcessId; + } + + #endif /* win32 implementation of internal_forkexec */ + + /* * SubPostmasterMain -- Get the fork/exec'd process into a state equivalent * to what it would be if we'd simply forked on Unix, and then *************** *** 2880,2885 **** --- 3029,3046 ---- MyProcPid = getpid(); /* reset MyProcPid */ + /* Read in file-based context */ + memset(&port, 0, sizeof(Port)); + read_backend_variables(argv[2], &port); + + /* Start our win32 signal implementation. This has to be done + * after we read the backend variables, because we need to pick + * up the signal pipe from the parent process. + */ + #ifdef WIN32 + pgwin32_signal_initialize(); + #endif + /* In EXEC_BACKEND case we will not have inherited these settings */ IsPostmasterEnvironment = true; whereToSendOutput = None; *************** *** 2894,2902 **** if (argc < 3) elog(FATAL, "invalid subpostmaster invocation"); ! /* Read in file-based context */ ! memset(&port, 0, sizeof(Port)); ! read_backend_variables(argv[2], &port); read_nondefault_variables(); /* Run backend or appropriate child */ --- 3055,3061 ---- if (argc < 3) elog(FATAL, "invalid subpostmaster invocation"); ! /* Read in remaining GUC variables */ read_nondefault_variables(); /* Run backend or appropriate child */ *************** *** 3330,3353 **** extern LWLock *LWLockArray; extern slock_t *ProcStructLock; extern int pgStatSock; - #define write_var(var,fp) fwrite((void*)&(var),sizeof(var),1,fp) - #define read_var(var,fp) fread((void*)&(var),sizeof(var),1,fp) - #define write_array_var(var,fp) fwrite((void*)(var),sizeof(var),1,fp) - #define read_array_var(var,fp) fread((void*)(var),sizeof(var),1,fp) ! static bool ! write_backend_variables(char *filename, Port *port) { static unsigned long tmpBackendFileNum = 0; - FILE *fp; - char str_buf[MAXPGPATH]; - /* Calculate name for temp file in caller's buffer */ Assert(DataDir); snprintf(filename, MAXPGPATH, "%s/%s/%s.backend_var.%d.%lu", DataDir, PG_TEMP_FILES_DIR, PG_TEMP_FILE_PREFIX, MyProcPid, ++tmpBackendFileNum); /* Open file */ fp = AllocateFile(filename, PG_BINARY_W); --- 3489,3575 ---- extern LWLock *LWLockArray; extern slock_t *ProcStructLock; extern int pgStatSock; + extern int pgStatPipe[2]; ! /* Type for a socket that can be inherited to a client process */ ! #ifdef WIN32 ! typedef struct ! { ! SOCKET origsocket; /* Original socket value, or -1 if not a socket */ ! WSAPROTOCOL_INFO wsainfo; ! } InheritableSocket; ! #else ! typedef int InheritableSocket; ! #endif ! ! /* ! * Structure contains all variables passed to exec:ed backends ! */ ! typedef struct ! { ! Port port; ! InheritableSocket portsocket; ! char DataDir[MAXPGPATH]; ! int ListenSocket[MAXLISTEN]; ! long MyCancelKey; ! unsigned long UsedShmemSegID; ! void *UsedShmemSegAddr; ! slock_t *ShmemLock; ! slock_t *ShmemIndexLock; ! VariableCache ShmemVariableCache; ! void *ShmemIndexAlloc; ! Backend *ShmemBackendArray; ! LWLock *LWLockArray; ! slock_t *ProcStructLock; ! InheritableSocket pgStatSock; ! InheritableSocket pgStatPipe0; ! InheritableSocket pgStatPipe1; ! int debug_flag; ! pid_t PostmasterPid; ! #ifdef WIN32 ! HANDLE PostmasterHandle; ! HANDLE initial_signal_pipe; ! HANDLE syslogPipe[2]; ! #else ! int syslogPipe[2]; ! #endif ! char my_exec_path[MAXPGPATH]; ! char ExtraOptions[MAXPGPATH]; ! char lc_collate[MAXPGPATH]; ! char lc_ctype[MAXPGPATH]; ! } BackendParameters; ! ! #ifndef WIN32 ! #define write_inheritable_socket(dest, src, childpid) (*dest)=src ! #define read_inheritable_socket(dest, src) *dest=*src; ! #else ! static void write_duplicated_handle(HANDLE *dest, HANDLE src, HANDLE child); ! static void write_inheritable_socket(InheritableSocket *dest, SOCKET src, pid_t childPid); ! static void read_inheritable_socket(SOCKET *dest, InheritableSocket *src); ! #endif ! ! /* Calculate name for temp file in caller's buffer */ ! static void get_backend_variable_filename(char *filename) { static unsigned long tmpBackendFileNum = 0; Assert(DataDir); snprintf(filename, MAXPGPATH, "%s/%s/%s.backend_var.%d.%lu", DataDir, PG_TEMP_FILES_DIR, PG_TEMP_FILE_PREFIX, MyProcPid, ++tmpBackendFileNum); + } + + #ifndef WIN32 + static bool + write_backend_variables(char *filename, Port *port) + #else + static bool + write_backend_variables(char *filename, Port *port, HANDLE childProcess, pid_t childPid) + #endif + { + FILE *fp; + BackendParameters param; /* Open file */ fp = AllocateFile(filename, PG_BINARY_W); *************** *** 3371,3427 **** } /* Write vars */ ! write_var(port->sock, fp); ! write_var(port->proto, fp); ! write_var(port->laddr, fp); ! write_var(port->raddr, fp); ! write_var(port->canAcceptConnections, fp); ! write_var(port->cryptSalt, fp); ! write_var(port->md5Salt, fp); ! /* ! * XXX FIXME later: writing these strings as MAXPGPATH bytes always is ! * probably a waste of resources ! */ ! ! StrNCpy(str_buf, DataDir, MAXPGPATH); ! write_array_var(str_buf, fp); ! ! write_array_var(ListenSocket, fp); ! ! write_var(MyCancelKey, fp); - write_var(UsedShmemSegID, fp); - write_var(UsedShmemSegAddr, fp); - - write_var(ShmemLock, fp); - write_var(ShmemIndexLock, fp); - write_var(ShmemVariableCache, fp); - write_var(ShmemIndexAlloc, fp); - write_var(ShmemBackendArray, fp); - - write_var(LWLockArray, fp); - write_var(ProcStructLock, fp); - write_var(pgStatSock, fp); - - write_var(debug_flag, fp); - write_var(PostmasterPid, fp); #ifdef WIN32 ! write_var(PostmasterHandle, fp); #endif ! write_var(syslogPipe[0], fp); ! write_var(syslogPipe[1], fp); ! StrNCpy(str_buf, my_exec_path, MAXPGPATH); ! write_array_var(str_buf, fp); ! write_array_var(ExtraOptions, fp); ! StrNCpy(str_buf, setlocale(LC_COLLATE, NULL), MAXPGPATH); ! write_array_var(str_buf, fp); ! StrNCpy(str_buf, setlocale(LC_CTYPE, NULL), MAXPGPATH); ! write_array_var(str_buf, fp); /* Release file */ if (FreeFile(fp)) --- 3593,3643 ---- } /* Write vars */ ! memcpy(¶m.port, port, sizeof(Port)); ! write_inheritable_socket(¶m.portsocket, port->sock, childPid); ! ! StrNCpy(param.DataDir, DataDir, MAXPGPATH); ! ! memcpy(¶m.ListenSocket, &ListenSocket, sizeof(ListenSocket)); ! ! param.MyCancelKey = MyCancelKey; ! ! param.UsedShmemSegID = UsedShmemSegID; ! param.UsedShmemSegAddr = UsedShmemSegAddr; ! ! param.ShmemLock = ShmemLock; ! param.ShmemIndexLock = ShmemIndexLock; ! param.ShmemVariableCache = ShmemVariableCache; ! param.ShmemIndexAlloc = ShmemIndexAlloc; ! param.ShmemBackendArray = ShmemBackendArray; ! ! param.LWLockArray = LWLockArray; ! param.ProcStructLock = ProcStructLock; ! write_inheritable_socket(¶m.pgStatSock, pgStatSock, childPid); ! write_inheritable_socket(¶m.pgStatPipe0, pgStatPipe[0], childPid); ! write_inheritable_socket(¶m.pgStatPipe1, pgStatPipe[1], childPid); ! param.debug_flag = debug_flag; ! param.PostmasterPid = PostmasterPid; #ifdef WIN32 ! param.PostmasterHandle = PostmasterHandle; ! write_duplicated_handle(¶m.initial_signal_pipe, pgwin32_create_signal_listener(childPid), childProcess); #endif ! memcpy(¶m.syslogPipe, &syslogPipe, sizeof(syslogPipe)); ! ! StrNCpy(param.my_exec_path, my_exec_path, MAXPGPATH); ! StrNCpy(param.ExtraOptions, ExtraOptions, MAXPGPATH); ! StrNCpy(param.lc_collate, setlocale(LC_COLLATE, NULL), MAXPGPATH); ! StrNCpy(param.lc_ctype, setlocale(LC_CTYPE, NULL), MAXPGPATH); ! if (fwrite(¶m, sizeof(param), 1, fp) != 1) ! ereport(ERROR, ! (errcode_for_file_access(), ! errmsg("could not write to file \"%s\": %m", filename))); /* Release file */ if (FreeFile(fp)) *************** *** 3435,3508 **** return true; } static void read_backend_variables(char *filename, Port *port) { FILE *fp; ! char str_buf[MAXPGPATH]; /* Open file */ fp = AllocateFile(filename, PG_BINARY_R); if (!fp) ! ereport(FATAL, ! (errcode_for_file_access(), ! errmsg("could not read from backend variables file \"%s\": %m", ! filename))); /* Read vars */ ! read_var(port->sock, fp); ! read_var(port->proto, fp); ! read_var(port->laddr, fp); ! read_var(port->raddr, fp); ! read_var(port->canAcceptConnections, fp); ! read_var(port->cryptSalt, fp); ! read_var(port->md5Salt, fp); ! ! read_array_var(str_buf, fp); ! SetDataDir(str_buf); ! ! read_array_var(ListenSocket, fp); ! ! read_var(MyCancelKey, fp); ! ! read_var(UsedShmemSegID, fp); ! read_var(UsedShmemSegAddr, fp); ! ! read_var(ShmemLock, fp); ! read_var(ShmemIndexLock, fp); ! read_var(ShmemVariableCache, fp); ! read_var(ShmemIndexAlloc, fp); ! read_var(ShmemBackendArray, fp); ! ! read_var(LWLockArray, fp); ! read_var(ProcStructLock, fp); ! read_var(pgStatSock, fp); - read_var(debug_flag, fp); - read_var(PostmasterPid, fp); #ifdef WIN32 ! read_var(PostmasterHandle, fp); #endif ! read_var(syslogPipe[0], fp); ! read_var(syslogPipe[1], fp); ! read_array_var(str_buf, fp); ! StrNCpy(my_exec_path, str_buf, MAXPGPATH); ! read_array_var(ExtraOptions, fp); ! read_array_var(str_buf, fp); ! setlocale(LC_COLLATE, str_buf); ! read_array_var(str_buf, fp); ! setlocale(LC_CTYPE, str_buf); /* Release file */ FreeFile(fp); if (unlink(filename) != 0) ! ereport(WARNING, ! (errcode_for_file_access(), ! errmsg("could not remove file \"%s\": %m", filename))); } --- 3651,3811 ---- return true; } + + #ifdef WIN32 + /* + * Duplicate a handle for usage in a child process, and write the child + * process instance of the handle to the parameter file. + */ + static void + write_duplicated_handle(HANDLE *dest, HANDLE src, HANDLE childProcess) + { + HANDLE hChild = INVALID_HANDLE_VALUE; + + if (!DuplicateHandle(GetCurrentProcess(), + src, + childProcess, + &hChild, + 0, + TRUE, + DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) + ereport(ERROR, + (errmsg_internal("could not duplicate handle to be written to backend parameter file: %i", + (int) GetLastError()))); + + *dest = hChild; + } + + /* + * Duplicate a socket for usage in a child process, and write the resulting + * structure to the parameter file. + * This is required because a number of LSPs (Layered Service Providers) very + * common on Windows (antivirus, firewalls, download managers etc) break + * straight socket inheritance. + */ + static void + write_inheritable_socket(InheritableSocket *dest, SOCKET src, pid_t childpid) + { + dest->origsocket = src; + if (src != 0 && src != -1) + { + /* Actual socket */ + if (WSADuplicateSocket(src, childpid, &dest->wsainfo) != 0) + ereport(ERROR, + (errmsg("could not duplicate socket %i for use in backend: %i\n", + src, WSAGetLastError()))); + } + } + + /* + * Read a duplicate socket structure back, and get the socket descriptor. + */ + static void + read_inheritable_socket(SOCKET *dest, InheritableSocket *src) + { + SOCKET s; + + if (src->origsocket == -1 || src->origsocket == 0) + { + /* Not a real socket! */ + *dest = src->origsocket; + } + else + { + /* Actual socket, so create from structure */ + s = WSASocket(FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + &src->wsainfo, + 0, + 0); + if (s == INVALID_SOCKET) + { + write_stderr("could not create inherited socket: %i\n", + WSAGetLastError()); + exit(1); + } + *dest = s; + /* To make sure we don't get two references to the same socket, + * close the original one. (This would happen when inheritance + * actually works.. + */ + closesocket(src->origsocket); + } + } + #endif + static void read_backend_variables(char *filename, Port *port) { FILE *fp; ! BackendParameters param; /* Open file */ fp = AllocateFile(filename, PG_BINARY_R); if (!fp) ! { ! write_stderr("could not read from backend variables file \"%s\": %i", ! filename, errno); ! exit(1); ! } ! ! if (fread(¶m, sizeof(param), 1, fp) != 1) ! { ! write_stderr("could not read from backend variables file \"%s\": %i", ! filename, errno); ! exit(1); ! } /* Read vars */ ! memcpy(port, ¶m.port, sizeof(Port)); ! read_inheritable_socket(&port->sock, ¶m.portsocket); ! ! SetDataDir(param.DataDir); ! ! memcpy(&ListenSocket, ¶m.ListenSocket, sizeof(ListenSocket)); ! ! MyCancelKey = param.MyCancelKey; ! ! UsedShmemSegID = param.UsedShmemSegID; ! UsedShmemSegAddr = param.UsedShmemSegAddr; ! ! ShmemLock = param.ShmemLock; ! ShmemIndexLock = param.ShmemIndexLock; ! ShmemVariableCache = param.ShmemVariableCache; ! ShmemIndexAlloc = param.ShmemIndexAlloc; ! ShmemBackendArray = param.ShmemBackendArray; ! ! LWLockArray = param.LWLockArray; ! ProcStructLock = param.ProcStructLock; ! read_inheritable_socket(&pgStatSock, ¶m.pgStatSock); ! read_inheritable_socket(&pgStatPipe[0], ¶m.pgStatPipe0); ! read_inheritable_socket(&pgStatPipe[1], ¶m.pgStatPipe1); ! ! debug_flag = param.debug_flag; ! PostmasterPid = param.PostmasterPid; #ifdef WIN32 ! PostmasterHandle = param.PostmasterHandle; ! pgwin32_initial_signal_pipe = param.initial_signal_pipe; #endif ! memcpy(&syslogPipe, ¶m.syslogPipe, sizeof(syslogPipe)); ! StrNCpy(my_exec_path, param.my_exec_path, MAXPGPATH); ! StrNCpy(ExtraOptions, param.ExtraOptions, MAXPGPATH); ! setlocale(LC_COLLATE, param.lc_collate); ! setlocale(LC_CTYPE, param.lc_ctype); /* Release file */ FreeFile(fp); if (unlink(filename) != 0) ! { ! write_stderr("could not remove file \"%s\": %i", filename, errno); ! exit(1); ! } } *************** *** 3565,3638 **** #ifdef WIN32 - static pid_t - win32_forkexec(const char *path, char *argv[]) - { - STARTUPINFO si; - PROCESS_INFORMATION pi; - int i; - int j; - char cmdLine[MAXPGPATH * 2]; - HANDLE childHandleCopy; - HANDLE waiterThread; - - /* Format the cmd line */ - cmdLine[sizeof(cmdLine) - 1] = '\0'; - cmdLine[sizeof(cmdLine) - 2] = '\0'; - snprintf(cmdLine, sizeof(cmdLine) - 1, "\"%s\"", path); - i = 0; - while (argv[++i] != NULL) - { - j = strlen(cmdLine); - snprintf(cmdLine + j, sizeof(cmdLine) - 1 - j, " \"%s\"", argv[i]); - } - if (cmdLine[sizeof(cmdLine) - 2] != '\0') - { - elog(LOG, "subprocess command line too long"); - return -1; - } - - memset(&pi, 0, sizeof(pi)); - memset(&si, 0, sizeof(si)); - si.cb = sizeof(si); - if (!CreateProcess(NULL, cmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) - { - elog(LOG, "CreateProcess call failed (%d): %m", (int) GetLastError()); - return -1; - } - - if (!IsUnderPostmaster) - { - /* We are the Postmaster creating a child... */ - win32_AddChild(pi.dwProcessId, pi.hProcess); - } - - if (DuplicateHandle(GetCurrentProcess(), - pi.hProcess, - GetCurrentProcess(), - &childHandleCopy, - 0, - FALSE, - DUPLICATE_SAME_ACCESS) == 0) - ereport(FATAL, - (errmsg_internal("could not duplicate child handle: %d", - (int) GetLastError()))); - - waiterThread = CreateThread(NULL, 64 * 1024, win32_sigchld_waiter, - (LPVOID) childHandleCopy, 0, NULL); - if (!waiterThread) - ereport(FATAL, - (errmsg_internal("could not create sigchld waiter thread: %d", - (int) GetLastError()))); - CloseHandle(waiterThread); - - if (IsUnderPostmaster) - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - - return pi.dwProcessId; - } - /* * Note: The following three functions must not be interrupted (eg. by * signals). As the Postgres Win32 signalling architecture (currently) --- 3868,3873 ---- *************** *** 3735,3741 **** */ ereport(FATAL, (errmsg_internal("failed to get exit code for child %lu", ! win32_childPIDArray[index]))); } *exitstatus = (int) exitCode; return win32_childPIDArray[index]; --- 3970,3976 ---- */ ereport(FATAL, (errmsg_internal("failed to get exit code for child %lu", ! (DWORD)win32_childPIDArray[index]))); } *exitstatus = (int) exitCode; return win32_childPIDArray[index]; Index: include/port/win32.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/port/win32.h,v retrieving revision 1.39 diff -c -r1.39 win32.h *** include/port/win32.h 6 Oct 2004 17:47:53 -0000 1.39 --- include/port/win32.h 2 Nov 2004 18:53:52 -0000 *************** *** 106,111 **** --- 106,113 ---- /* In backend/port/win32/signal.c */ void pgwin32_signal_initialize(void); extern DLLIMPORT HANDLE pgwin32_signal_event; + extern HANDLE pgwin32_initial_signal_pipe; + HANDLE pgwin32_create_signal_listener(pid_t pid); void pgwin32_dispatch_queued_signals(void); void pg_queue_signal(int signum);