Index: src/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 *** src/backend/main/main.c 5 Nov 2004 17:11:17 -0000 1.92 --- src/backend/main/main.c 14 Nov 2004 13:49:31 -0000 *************** *** 119,126 **** exit(1); } - /* Start our win32 signal implementation */ - pgwin32_signal_initialize(); } #endif --- 119,124 ---- *************** *** 281,286 **** --- 279,292 ---- 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: src/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 *** src/backend/port/win32/signal.c 9 Nov 2004 13:01:25 -0000 1.9 --- src/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: src/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 *** src/backend/postmaster/pgstat.c 28 Oct 2004 01:38:41 -0000 1.84 --- src/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: src/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 *** src/backend/postmaster/postmaster.c 9 Nov 2004 13:01:26 -0000 1.437 --- src/backend/postmaster/postmaster.c 15 Nov 2004 18:52:16 -0000 *************** *** 120,125 **** --- 120,128 ---- #include "bootstrap/bootstrap.h" #include "pgstat.h" + #ifdef EXEC_BACKEND + #include "storage/spin.h" + #endif /* * List of active backends (or child processes anyway; we don't actually *************** *** 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); --- 278,283 ---- *************** *** 291,298 **** static pid_t backend_forkexec(Port *port); static pid_t internal_forkexec(int argc, char *argv[], Port *port); ! static void read_backend_variables(char *filename, Port *port); ! static bool write_backend_variables(char *filename, Port *port); static void ShmemBackendArrayAdd(Backend *bn); static void ShmemBackendArrayRemove(pid_t pid); --- 293,355 ---- static pid_t backend_forkexec(Port *port); static pid_t internal_forkexec(int argc, char *argv[], Port *port); ! /* 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 ! ! typedef struct LWLock LWLock; ! ! /* ! * 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; ! ! static void read_backend_variables(char *id, Port *port); ! static void get_backend_variables(BackendParameters *param, Port *port); ! #ifndef WIN32 ! static bool set_backend_variables(BackendParameters *param, Port *port); ! #else ! static bool set_backend_variables(BackendParameters *param, Port *port, HANDLE childProcess, pid_t childPid); ! #endif static void ShmemBackendArrayAdd(Backend *bn); static void ShmemBackendArrayRemove(pid_t pid); *************** *** 338,343 **** --- 394,404 ---- } } + #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,2833 **** return internal_forkexec(ac, av, port); } static pid_t internal_forkexec(int argc, char *argv[], Port *port) { pid_t pid; char tmpfilename[MAXPGPATH]; ! if (!write_backend_variables(tmpfilename, port)) ! return -1; /* log made by write_backend_variables */ /* Make sure caller set up argv properly */ Assert(argc >= 3); --- 2881,2947 ---- 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]; + BackendParameters param; + FILE *fp; + + /* Calculate name for temp file */ + Assert(DataDir); + snprintf(tmpfilename, MAXPGPATH, "%s/%s/%s.backend_var.%d.%lu", + DataDir, PG_TEMP_FILES_DIR, PG_TEMP_FILE_PREFIX, + MyProcPid, ++tmpBackendFileNum); + + if (!set_backend_variables(¶m, port)) + return -1; /* log made by set_backend_variables */ + + /* Open file */ + fp = AllocateFile(tmpfilename, PG_BINARY_W); + if (!fp) + { + /* As per OpenTemporaryFile... */ + char dirname[MAXPGPATH]; ! snprintf(dirname, MAXPGPATH, "%s/%s", DataDir, PG_TEMP_FILES_DIR); ! mkdir(dirname, S_IRWXU); ! ! fp = AllocateFile(tmpfilename, PG_BINARY_W); ! if (!fp) ! ereport(LOG, ! (errcode_for_file_access(), ! errmsg("could not create file \"%s\": %m", ! tmpfilename))); ! return -1; ! } ! } ! ! if (fwrite(¶m, sizeof(param), 1, fp) != 1) ! { ! ereport(LOG, ! (errcode_for_file_access(), ! errmsg("could not write to file \"%s\": %m", tmpfilename))); ! return -1; ! } ! ! /* Release file */ ! if (FreeFile(fp)) ! { ! ereport(LOG, ! (errcode_for_file_access(), ! errmsg("could not write to file \"%s\": %m", tmpfilename))); ! return -1; ! } /* Make sure caller set up argv properly */ Assert(argc >= 3); *************** *** 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) { --- 2952,2957 ---- *************** *** 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 --- 2964,3144 ---- 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; + HANDLE paramHandle; + BackendParameters *param; + SECURITY_ATTRIBUTES sa; + char paramHandleStr[32]; + + /* 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); + + /* Set up shared memory for parameter passing */ + ZeroMemory(&sa,sizeof(sa)); + sa.nLength = sizeof(sa); + sa.bInheritHandle = TRUE; + paramHandle = CreateFileMapping(INVALID_HANDLE_VALUE, + &sa, + PAGE_READWRITE, + 0, + sizeof(BackendParameters), + NULL); + if (paramHandle == INVALID_HANDLE_VALUE) + { + elog(LOG, "could not create backend parameter file mapping: %i", + (int) GetLastError()); + return -1; + } + + param = MapViewOfFile(paramHandle, FILE_MAP_WRITE, 0, 0, sizeof(BackendParameters)); + if (!param) + { + elog(LOG, "could not map backend parameter memory: %i", + (int) GetLastError()); + CloseHandle(paramHandle); + return -1; + } + + /* Insert temp file name after -fork argument */ + sprintf(paramHandleStr, "%lu", (DWORD)paramHandle); + argv[2] = paramHandleStr; + + /* 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 (!set_backend_variables(param, port, pi.hProcess, pi.dwProcessId)) + { + /* log made by set_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 set_backend_variables */ + } + + /* Drop the shared memory that is now inherited to the backend */ + if (!UnmapViewOfFile(param)) + elog(LOG, "could not unmap view of backend parameter file: %i", + (int) GetLastError()); + if (!CloseHandle(paramHandle)) + elog(LOG, "could not close handle to backend parameter file: %i", + (int) GetLastError()); + + /* 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 **** --- 3160,3177 ---- 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 */ --- 3186,3192 ---- if (argc < 3) elog(FATAL, "invalid subpostmaster invocation"); ! /* Read in remaining GUC variables */ read_nondefault_variables(); /* Run backend or appropriate child */ *************** *** 3318,3508 **** #ifdef EXEC_BACKEND /* ! * The following need to be available to the read/write_backend_variables * functions */ - #include "storage/spin.h" extern slock_t *ShmemLock; extern slock_t *ShmemIndexLock; extern void *ShmemIndexAlloc; - typedef struct LWLock LWLock; 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); ! if (!fp) ! { ! /* As per OpenTemporaryFile... */ ! char dirname[MAXPGPATH]; ! snprintf(dirname, MAXPGPATH, "%s/%s", DataDir, PG_TEMP_FILES_DIR); ! mkdir(dirname, S_IRWXU); ! fp = AllocateFile(filename, PG_BINARY_W); ! if (!fp) ! { ! ereport(LOG, ! (errcode_for_file_access(), ! errmsg("could not create file \"%s\": %m", ! filename))); ! return false; ! } ! } ! /* 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)) { ! ereport(ERROR, ! (errcode_for_file_access(), ! errmsg("could not write to file \"%s\": %m", filename))); ! return false; } ! 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))); } --- 3608,3881 ---- #ifdef EXEC_BACKEND /* ! * The following need to be available to the get/set_backend_variables * functions */ extern slock_t *ShmemLock; extern slock_t *ShmemIndexLock; extern void *ShmemIndexAlloc; extern LWLock *LWLockArray; extern slock_t *ProcStructLock; extern int pgStatSock; + extern int pgStatPipe[2]; + ! #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 + #ifndef WIN32 static bool ! set_backend_variables(BackendParameters *param, Port *port) ! #else ! static bool ! set_backend_variables(BackendParameters *param, Port *port, HANDLE childProcess, pid_t childPid) ! #endif { ! /* 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); ! 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 *id, Port *port) ! { ! #ifndef WIN32 ! /* Non-win32 implementation reads from file */ ! FILE *fp; ! BackendParameters param; ! /* Open file */ ! fp = AllocateFile(id, PG_BINARY_R); ! if (!fp) ! { ! write_stderr("could not read from backend variables file \"%s\": %i", ! id, errno); ! exit(1); ! } ! if (fread(¶m, sizeof(param), 1, fp) != 1) ! { ! write_stderr("could not read from backend variables file \"%s\": %i", ! id, errno); ! exit(1); ! } /* Release file */ ! FreeFile(fp); ! if (unlink(filename) != 0) { ! write_stderr("could not remove file \"%s\": %i", id, errno); ! exit(1); } ! get_backend_variables(¶m, port); ! #else ! /* Win32 version uses mapped file */ ! HANDLE paramHandle; ! BackendParameters *param; ! ! paramHandle = (HANDLE)atol(id); ! param = MapViewOfFile(paramHandle, FILE_MAP_READ, 0, 0, 0); ! if (!param) ! { ! write_stderr("could not map view of backend variables: %i", ! (int) GetLastError()); ! exit(1); ! } ! ! get_backend_variables(param, port); ! ! if (!UnmapViewOfFile(param)) ! { ! write_stderr("could not unmap view of backend variables: %i", ! (int) GetLastError()); ! exit(1); ! } ! ! if (!CloseHandle(paramHandle)) ! { ! write_stderr("could not close handle to backend parameter variabels: %i", ! (int) GetLastError()); ! exit(1); ! } ! #endif } static void ! get_backend_variables(BackendParameters *param, Port *port) { ! /* 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); } *************** *** 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) --- 3938,3943 ---- *************** *** 3735,3741 **** */ ereport(FATAL, (errmsg_internal("failed to get exit code for child %lu", ! win32_childPIDArray[index]))); } *exitstatus = (int) exitCode; return win32_childPIDArray[index]; --- 4040,4046 ---- */ ereport(FATAL, (errmsg_internal("failed to get exit code for child %lu", ! (DWORD)win32_childPIDArray[index]))); } *exitstatus = (int) exitCode; return win32_childPIDArray[index]; Index: src/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 *** src/include/port/win32.h 6 Oct 2004 17:47:53 -0000 1.39 --- src/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);