diff options
Diffstat (limited to 'src/backend/postmaster/postmaster.c')
-rw-r--r-- | src/backend/postmaster/postmaster.c | 255 |
1 files changed, 233 insertions, 22 deletions
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index dd5f55c5adb..aff21186a0e 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -37,7 +37,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.359 2004/01/26 22:35:32 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.360 2004/01/26 22:51:55 momjian Exp $ * * NOTES * @@ -141,6 +141,11 @@ typedef struct bkend static Dllist *BackendList; +#ifdef EXEC_BACKEND +#define NUM_BACKENDARRAY_ELEMS (2*MaxBackends) +static Backend *ShmemBackendArray; +#endif + /* The socket number we are listening for connections on */ int PostPortNumber; char *UnixSocketDir; @@ -299,6 +304,14 @@ __attribute__((format(printf, 1, 2))); #ifdef EXEC_BACKEND #ifdef WIN32 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); + +static pid_t *win32_childPIDArray; +static HANDLE *win32_childHNDArray; +static unsigned long win32_numChildren = 0; #endif static pid_t Backend_forkexec(Port *port); @@ -306,6 +319,11 @@ static pid_t Backend_forkexec(Port *port); static unsigned long tmpBackendFileNum = 0; void read_backend_variables(unsigned long id, Port *port); static bool write_backend_variables(Port *port); + +size_t ShmemBackendArraySize(void); +void ShmemBackendArrayAllocation(void); +static void ShmemBackendArrayAdd(Backend *bn); +static void ShmemBackendArrayRemove(pid_t pid); #endif #define StartupDataBase() SSDataBase(BS_XLOG_STARTUP) @@ -430,7 +448,7 @@ PostmasterMain(int argc, char *argv[]) */ umask((mode_t) 0077); - MyProcPid = getpid(); + MyProcPid = PostmasterPid = getpid(); /* * Fire up essential subsystems: memory management @@ -825,6 +843,21 @@ PostmasterMain(int argc, char *argv[]) */ BackendList = DLNewList(); +#ifdef WIN32 + /* + * Initialize the child pid/HANDLE arrays + */ + /* FIXME: [fork/exec] Ideally, we would resize these arrays with changes + * in MaxBackends, but this'll do as a first order solution. + */ + win32_childPIDArray = (HANDLE*)malloc(NUM_BACKENDARRAY_ELEMS*sizeof(pid_t)); + win32_childHNDArray = (HANDLE*)malloc(NUM_BACKENDARRAY_ELEMS*sizeof(HANDLE)); + if (!win32_childPIDArray || !win32_childHNDArray) + ereport(LOG, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); +#endif + /* * Record postmaster options. We delay this till now to avoid * recording bogus options (eg, NBuffers too high for available @@ -1257,11 +1290,7 @@ ProcessStartupPacket(Port *port, bool SSLdone) if (proto == CANCEL_REQUEST_CODE) { -#ifdef EXEC_BACKEND - abort(); /* FIXME: [fork/exec] Whoops. Not handled... yet */ -#else processCancelRequest(port, buf); -#endif return 127; /* XXX */ } @@ -1494,8 +1523,12 @@ processCancelRequest(Port *port, void *pkt) CancelRequestPacket *canc = (CancelRequestPacket *) pkt; int backendPID; long cancelAuthCode; - Dlelem *curr; Backend *bp; +#ifndef EXEC_BACKEND + Dlelem *curr; +#else + int i; +#endif backendPID = (int) ntohl(canc->backendPID); cancelAuthCode = (long) ntohl(canc->cancelAuthCode); @@ -1514,16 +1547,17 @@ processCancelRequest(Port *port, void *pkt) backendPID))); return; } -#ifdef EXEC_BACKEND - else - AttachSharedMemoryAndSemaphores(); -#endif /* See if we have a matching backend */ - +#ifndef EXEC_BACKEND for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr)) { bp = (Backend *) DLE_VAL(curr); +#else + for (i = 0; i < NUM_BACKENDARRAY_ELEMS; i++) + { + bp = (Backend*) &ShmemBackendArray[i]; +#endif if (bp->pid == backendPID) { if (bp->cancel_key == cancelAuthCode) @@ -1846,15 +1880,13 @@ reaper(SIGNAL_ARGS) { int save_errno = errno; -#ifdef WIN32 -#warning fix waidpid for Win32 -#else #ifdef HAVE_WAITPID int status; /* backend exit status */ - #else +#ifndef WIN32 union wait status; /* backend exit status */ #endif +#endif int exitstatus; int pid; /* process id of dead backend */ @@ -1867,9 +1899,21 @@ reaper(SIGNAL_ARGS) { exitstatus = status; #else +#ifndef WIN32 while ((pid = wait3(&status, WNOHANG, NULL)) > 0) { exitstatus = status.w_status; +#else + while ((pid = win32_waitpid(&exitstatus)) > 0) + { + /* + * We need to do this here, and not in CleanupProc, since this + * is to be called on all children when we are done with them. + * Could move to LogChildExit, but that seems like asking for + * future trouble... + */ + win32_RemoveChild(pid); +#endif #endif /* @@ -1957,7 +2001,6 @@ reaper(SIGNAL_ARGS) CleanupProc(pid, exitstatus); } /* loop over pending child-death reports */ -#endif if (FatalError) { @@ -2022,6 +2065,9 @@ CleanupProc(int pid, bp = (Backend *) DLE_VAL(curr); if (bp->pid == pid) { +#ifdef EXEC_BACKEND + ShmemBackendArrayRemove(bp->pid); +#endif DLRemove(curr); free(bp); DLFreeElem(curr); @@ -2092,6 +2138,9 @@ CleanupProc(int pid, /* * Found entry for freshly-dead backend, so remove it. */ +#ifdef EXEC_BACKEND + ShmemBackendArrayRemove(bp->pid); +#endif DLRemove(curr); free(bp); DLFreeElem(curr); @@ -2296,6 +2345,9 @@ BackendStartup(Port *port) */ bn->pid = pid; bn->cancel_key = MyCancelKey; +#ifdef EXEC_BACKEND + ShmemBackendArrayAdd(bn); +#endif DLAddHead(BackendList, DLNewElem(bn)); return STATUS_OK; @@ -2642,6 +2694,9 @@ SubPostmasterMain(int argc, char* argv[]) memset((void*)&port, 0, sizeof(Port)); Assert(argc == 2); + /* Do this sooner rather than later... */ + IsUnderPostmaster = true; /* we are a postmaster subprocess now */ + /* Setup global context */ MemoryContextInit(); InitializeGUCOptions(); @@ -2661,6 +2716,9 @@ SubPostmasterMain(int argc, char* argv[]) load_user(); load_group(); + /* Attach process to shared segments */ + AttachSharedMemoryAndSemaphores(); + /* Run backend */ proc_exit(BackendRun(&port)); } @@ -3129,6 +3187,9 @@ SSDataBase(int xlop) bn->pid = pid; bn->cancel_key = PostmasterRandom(); +#ifdef EXEC_BACKEND + ShmemBackendArrayAdd(bn); +#endif DLAddHead(BackendList, DLNewElem(bn)); /* @@ -3278,6 +3339,7 @@ write_backend_variables(Port *port) write_var(ShmemIndexLock,fp); write_var(ShmemVariableCache,fp); write_var(ShmemIndexAlloc,fp); + write_var(ShmemBackendArray,fp); write_var(LWLockArray,fp); write_var(ProcStructLock,fp); @@ -3285,6 +3347,7 @@ write_backend_variables(Port *port) write_var(PreAuthDelay,fp); write_var(debug_flag,fp); + write_var(PostmasterPid,fp); /* Release file */ if (FreeFile(fp)) @@ -3338,6 +3401,7 @@ read_backend_variables(unsigned long id, Port *port) read_var(ShmemIndexLock,fp); read_var(ShmemVariableCache,fp); read_var(ShmemIndexAlloc,fp); + read_var(ShmemBackendArray,fp); read_var(LWLockArray,fp); read_var(ProcStructLock,fp); @@ -3345,6 +3409,7 @@ read_backend_variables(unsigned long id, Port *port) read_var(PreAuthDelay,fp); read_var(debug_flag,fp); + read_var(PostmasterPid,fp); /* Release file */ FreeFile(fp); @@ -3354,6 +3419,55 @@ read_backend_variables(unsigned long id, Port *port) errmsg("could not remove file \"%s\": %m", filename))); } + +size_t ShmemBackendArraySize(void) +{ + return (NUM_BACKENDARRAY_ELEMS*sizeof(Backend)); +} + +void ShmemBackendArrayAllocation(void) +{ + size_t size = ShmemBackendArraySize(); + ShmemBackendArray = (Backend*)ShmemAlloc(size); + memset(ShmemBackendArray, 0, size); +} + +static void ShmemBackendArrayAdd(Backend *bn) +{ + int i; + for (i = 0; i < NUM_BACKENDARRAY_ELEMS; i++) + { + /* Find an empty slot */ + if (ShmemBackendArray[i].pid == 0) + { + ShmemBackendArray[i] = *bn; + return; + } + } + + /* FIXME: [fork/exec] some sort of error */ + abort(); +} + +static void ShmemBackendArrayRemove(pid_t pid) +{ + int i; + for (i = 0; i < NUM_BACKENDARRAY_ELEMS; i++) + { + if (ShmemBackendArray[i].pid == pid) + { + /* Mark the slot as empty */ + ShmemBackendArray[i].pid = 0; + return; + } + } + + /* Something stronger than WARNING here? */ + ereport(WARNING, + (errmsg_internal("unable to find backend entry with pid %d", + pid))); +} + #endif #ifdef WIN32 @@ -3393,14 +3507,111 @@ pid_t win32_forkexec(const char* path, char *argv[]) return -1; } - /* - FIXME: [fork/exec] we might need to keep the following handle/s, - depending on how we implement signalling. - */ - CloseHandle(pi.hProcess); + if (!IsUnderPostmaster) + /* We are the Postmaster creating a child... */ + win32_AddChild(pi.dwProcessId,pi.hProcess); + else + 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) requires polling, + * or APC checking functions which aren't used here, this is not an issue. + * + * We keep two separate arrays, instead of a single array of pid/HANDLE structs, + * to avoid having to re-create a handle array for WaitForMultipleObjects on + * each call to win32_waitpid. + */ + +static void win32_AddChild(pid_t pid, HANDLE handle) +{ + Assert(win32_childPIDArray && win32_childHNDArray); + if (win32_numChildren < NUM_BACKENDARRAY_ELEMS) + { + win32_childPIDArray[win32_numChildren] = pid; + win32_childHNDArray[win32_numChildren] = handle; + ++win32_numChildren; + } + else + /* FIXME: [fork/exec] some sort of error */ + abort(); +} + +static void win32_RemoveChild(pid_t pid) +{ + int i; + Assert(win32_childPIDArray && win32_childHNDArray); + + for (i = 0; i < win32_numChildren; i++) + { + if (win32_childPIDArray[i] == pid) + { + CloseHandle(win32_childHNDArray[i]); + + /* Swap last entry into the "removed" one */ + --win32_numChildren; + win32_childPIDArray[win32_numChildren] = win32_childPIDArray[i]; + win32_childHNDArray[win32_numChildren] = win32_childHNDArray[i]; + return; + } + } + + /* Something stronger than WARNING here? */ + ereport(WARNING, + (errmsg_internal("unable to find child entry with pid %d", + pid))); +} + +static pid_t win32_waitpid(int *exitstatus) +{ + Assert(win32_childPIDArray && win32_childHNDArray); + elog(DEBUG3,"waiting on %d children",win32_numChildren); + + if (win32_numChildren > 0) + { + /* + * Note: Do NOT use WaitForMultipleObjectsEx, as we don't + * want to run queued APCs here. + */ + int index; + DWORD exitCode; + DWORD ret = WaitForMultipleObjects(win32_numChildren,win32_childHNDArray,FALSE,0); + + switch (ret) + { + case WAIT_FAILED: + ereport(ERROR, + (errmsg_internal("failed to wait on %d children", + win32_numChildren))); + /* Fall through to WAIT_TIMEOUTs return */ + + case WAIT_TIMEOUT: + /* No children have finished */ + return -1; + + default: + /* Get the exit code, and return the PID of, the respective process */ + index = ret-WAIT_OBJECT_0; + Assert(index >= 0 && index < win32_numChildren); + if (!GetExitCodeProcess(win32_childHNDArray[index],&exitCode)) + /* + * If we get this far, this should never happen, but, then again... + * No choice other than to assume a catastrophic failure. + */ + ereport(FATAL, + (errmsg_internal("failed to get exit code for child %d", + win32_childPIDArray[index]))); + *exitstatus = (int)exitCode; + return win32_childPIDArray[index]; + } + } + + /* No children */ + return -1; +} + #endif |