|
|
|
|
@ -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,14 +1880,12 @@ 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 |
|
|
|
|
|