*** a/src/backend/postmaster/postmaster.c --- b/src/backend/postmaster/postmaster.c *************** *** 386,394 **** typedef struct --- 386,396 ---- HANDLE waitHandle; HANDLE procHandle; DWORD procId; + HANDLE startupCompletedEvent; } win32_deadchild_waitinfo; HANDLE PostmasterHandle; + static HANDLE StartupCompletedEvent; #endif static pid_t backend_forkexec(Port *port); *************** *** 440,445 **** typedef struct --- 442,448 ---- bool redirection_done; #ifdef WIN32 HANDLE PostmasterHandle; + HANDLE StartupCompletedEvent; HANDLE initial_signal_pipe; HANDLE syslogPipe[2]; #else *************** *** 3757,3762 **** internal_forkexec(int argc, char *argv[], Port *port) --- 3760,3777 ---- si.cb = sizeof(si); /* + * Create an event used to verify that the child started properly. + */ + StartupCompletedEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!StartupCompletedEvent) + { + ereport(LOG, + (errmsg_internal("could not create StartupCompletedEvent: error code %d", + (int) GetLastError()))); + return -1; + } + + /* * Create the subprocess in a suspended state. This will be resumed later, * once we have written out the parameter file. */ *************** *** 3765,3770 **** internal_forkexec(int argc, char *argv[], Port *port) --- 3780,3786 ---- { elog(LOG, "CreateProcess call failed: %m (error code %d)", (int) GetLastError()); + CloseHandle(StartupCompletedEvent); return -1; } *************** *** 3780,3785 **** internal_forkexec(int argc, char *argv[], Port *port) --- 3796,3802 ---- (int) GetLastError()))); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); + CloseHandle(StartupCompletedEvent); return -1; /* log made by save_backend_variables */ } *************** *** 3807,3812 **** internal_forkexec(int argc, char *argv[], Port *port) --- 3824,3830 ---- (int) GetLastError()))); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); + CloseHandle(StartupCompletedEvent); return -1; /* logging done made by * pgwin32_ReserveSharedMemoryRegion() */ } *************** *** 3825,3834 **** internal_forkexec(int argc, char *argv[], Port *port) --- 3843,3854 ---- (int) GetLastError()))); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); + CloseHandle(StartupCompletedEvent); return -1; } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); + CloseHandle(StartupCompletedEvent); ereport(LOG, (errmsg_internal("could not resume thread of unstarted process: error code %d", (int) GetLastError()))); *************** *** 3851,3856 **** internal_forkexec(int argc, char *argv[], Port *port) --- 3871,3877 ---- childinfo->procHandle = pi.hProcess; childinfo->procId = pi.dwProcessId; + childinfo->startupCompletedEvent = StartupCompletedEvent; if (!RegisterWaitForSingleObject(&childinfo->waitHandle, pi.hProcess, *************** *** 3920,3925 **** SubPostmasterMain(int argc, char *argv[]) --- 3941,3955 ---- read_backend_variables(argv[2], &port); /* + * Flag that we are running, as soon as possible, for detecting + * processes that die on startup before our code has a chance + * to do anything. + */ + #ifdef WIN32 + SetEvent(StartupCompletedEvent); + #endif + + /* * Set up memory area for GSS information. Mirrors the code in ConnCreate * for the non-exec case. */ *************** *** 4603,4609 **** extern pgsocket pgStatSock; #define write_inheritable_socket(dest, src, childpid) ((*(dest) = (src)), true) #define read_inheritable_socket(dest, src) (*(dest) = *(src)) #else ! static bool write_duplicated_handle(HANDLE *dest, HANDLE src, HANDLE child); static bool write_inheritable_socket(InheritableSocket * dest, SOCKET src, pid_t childPid); static void read_inheritable_socket(SOCKET * dest, InheritableSocket * src); --- 4633,4639 ---- #define write_inheritable_socket(dest, src, childpid) ((*(dest) = (src)), true) #define read_inheritable_socket(dest, src) (*(dest) = *(src)) #else ! static bool write_duplicated_handle(HANDLE *dest, HANDLE src, HANDLE child, bool close); static bool write_inheritable_socket(InheritableSocket * dest, SOCKET src, pid_t childPid); static void read_inheritable_socket(SOCKET * dest, InheritableSocket * src); *************** *** 4656,4662 **** save_backend_variables(BackendParameters * param, Port *port, param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, pgwin32_create_signal_listener(childPid), ! childProcess)) return false; #endif --- 4686,4696 ---- param->PostmasterHandle = PostmasterHandle; if (!write_duplicated_handle(¶m->initial_signal_pipe, pgwin32_create_signal_listener(childPid), ! childProcess, true)) ! return false; ! if (!write_duplicated_handle(¶m->StartupCompletedEvent, ! StartupCompletedEvent, ! childProcess, false)) return false; #endif *************** *** 4676,4686 **** save_backend_variables(BackendParameters * param, Port *port, /* * Duplicate a handle for usage in a child process, and write the child * process instance of the handle to the parameter file. */ static bool ! write_duplicated_handle(HANDLE *dest, HANDLE src, HANDLE childProcess) { HANDLE hChild = INVALID_HANDLE_VALUE; if (!DuplicateHandle(GetCurrentProcess(), src, --- 4710,4723 ---- /* * Duplicate a handle for usage in a child process, and write the child * process instance of the handle to the parameter file. + * If the close parameter is set to true, the handle will be set to be + * closed in the postmaster once it's duplicated. */ static bool ! write_duplicated_handle(HANDLE *dest, HANDLE src, HANDLE childProcess, bool close) { HANDLE hChild = INVALID_HANDLE_VALUE; + int closeflag = close ? DUPLICATE_CLOSE_SOURCE : 0; if (!DuplicateHandle(GetCurrentProcess(), src, *************** *** 4688,4694 **** write_duplicated_handle(HANDLE *dest, HANDLE src, HANDLE childProcess) &hChild, 0, TRUE, ! DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { ereport(LOG, (errmsg_internal("could not duplicate handle to be written to backend parameter file: error code %d", --- 4725,4731 ---- &hChild, 0, TRUE, ! closeflag | DUPLICATE_SAME_ACCESS)) { ereport(LOG, (errmsg_internal("could not duplicate handle to be written to backend parameter file: error code %d", *************** *** 4868,4873 **** restore_backend_variables(BackendParameters * param, Port *port) --- 4905,4911 ---- #ifdef WIN32 PostmasterHandle = param->PostmasterHandle; + StartupCompletedEvent = param->StartupCompletedEvent; pgwin32_initial_signal_pipe = param->initial_signal_pipe; #endif *************** *** 4944,4949 **** win32_waitpid(int *exitstatus) --- 4982,4990 ---- /* * Note! Code below executes on a thread pool! All operations must * be thread safe! Note that elog() and friends must *not* be used. + * Instead, use write_stderr() which will write the log to stderr + * when running on the console, or the eventlog when running as + * a service. */ static void WINAPI pgwin32_deadchild_callback(PVOID lpParameter, BOOLEAN TimerOrWaitFired) *************** *** 4970,4975 **** pgwin32_deadchild_callback(PVOID lpParameter, BOOLEAN TimerOrWaitFired) --- 5011,5038 ---- exitcode = 255; } + /* + * Did the process "fail before it started"? + * + * When the process has reached "runnable state", we will set the + * event in childinfo->startupCompletedEvent (using the duplicated + * handle that exists in the child process). If this event is + * not set, it means the process died before we got control of it, + * due to something like third party DLL failing to load or running + * out of desktop heap space. + * + * Don't treat this a fatal error requiring a restart. Instead, + * just log the fact and then post an exitcode indicating that + * the backend exited with a regular fatal error (exit code 1). + */ + if (WaitForSingleObject(childinfo->startupCompletedEvent, 0) != + WAIT_OBJECT_0) + { + /* Event not set, so we have an early death in the child */ + write_stderr("process %lu died early", childinfo->procId); + exitcode = 1; + } + if (!PostQueuedCompletionStatus(win32ChildQueue, childinfo->procId, (ULONG_PTR) exitcode, NULL)) write_stderr("could not post child completion status\n"); *************** *** 4978,4983 **** pgwin32_deadchild_callback(PVOID lpParameter, BOOLEAN TimerOrWaitFired) --- 5041,5047 ---- * originating thread */ CloseHandle(childinfo->procHandle); + CloseHandle(childinfo->startupCompletedEvent); /* * Free struct that was allocated before the call to