aboutsummaryrefslogtreecommitdiff
path: root/src/backend/postmaster/postmaster.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/postmaster/postmaster.c')
-rw-r--r--src/backend/postmaster/postmaster.c255
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