diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index c2b97704cc..b684f01c11 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -13,7 +13,7 @@ * * Copyright (c) 2001-2003, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.55 2004/01/26 22:54:56 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.56 2004/01/26 22:59:53 momjian Exp $ * ---------- */ #include "postgres.h" @@ -147,7 +147,7 @@ static void pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len); #define piperead(a,b,c) read(a,b,c) #define pipewrite(a,b,c) write(a,b,c) #else -/* pgpipe() is in /src/port */ +extern int pgpipe(int handles[2]); /* pgpipe() is in /src/port */ #define piperead(a,b,c) recv(a,b,c,0) #define pipewrite(a,b,c) send(a,b,c,0) #endif @@ -322,7 +322,7 @@ pgstat_init(void) /* * Create the pipe that controls the statistics collector shutdown */ - if (pipe(pgStatPmPipe) < 0) + if (pgpipe(pgStatPmPipe) < 0) { ereport(LOG, (errcode_for_socket_access(), diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 5fa9590a62..ccbffab561 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.361 2004/01/26 22:54:56 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.362 2004/01/26 22:59:53 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 diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c index 15692684e3..7de7d85e74 100644 --- a/src/backend/storage/ipc/ipci.c +++ b/src/backend/storage/ipc/ipci.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/ipc/ipci.c,v 1.62 2004/01/26 22:54:57 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/storage/ipc/ipci.c,v 1.63 2004/01/26 22:59:53 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -63,6 +63,9 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, size += LWLockShmemSize(); size += SInvalShmemSize(maxBackends); size += FreeSpaceShmemSize(); +#ifdef EXEC_BACKEND + size += ShmemBackendArraySize(); +#endif #ifdef STABLE_MEMORY_STORAGE size += MMShmemSize(); #endif @@ -132,6 +135,13 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, * Set up child-to-postmaster signaling mechanism */ PMSignalInit(); + +#ifdef EXEC_BACKEND + /* + * Alloc the win32 shared backend array + */ + ShmemBackendArrayAllocation(); +#endif } diff --git a/src/backend/storage/ipc/pmsignal.c b/src/backend/storage/ipc/pmsignal.c index 2b15f8d444..2d6252b66c 100644 --- a/src/backend/storage/ipc/pmsignal.c +++ b/src/backend/storage/ipc/pmsignal.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/ipc/pmsignal.c,v 1.10 2004/01/26 22:54:57 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/storage/ipc/pmsignal.c,v 1.11 2004/01/26 22:59:53 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -63,8 +63,8 @@ SendPostmasterSignal(PMSignalReason reason) return; /* Atomically set the proper flag */ PMSignalFlags[reason] = true; - /* Send signal to postmaster (assume it is our direct parent) */ - kill(getppid(), SIGUSR1); + /* Send signal to postmaster */ + kill(PostmasterPid, SIGUSR1); } /* diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index f8a3bfd3bd..2a40b34261 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.385 2004/01/26 22:54:57 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.386 2004/01/26 22:59:53 momjian Exp $ * * NOTES * this is the "main" module of the postgres backend and @@ -2535,9 +2535,7 @@ PostgresMain(int argc, char *argv[], const char *username) errmsg("invalid command-line arguments for server process"), errhint("Try \"%s --help\" for more information.", argv[0]))); } -#ifdef EXEC_BACKEND - AttachSharedMemoryAndSemaphores(); -#endif + XLOGPathInit(); BaseInit(); diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c index 29d1ebc0c7..56058fa05c 100644 --- a/src/backend/utils/init/globals.c +++ b/src/backend/utils/init/globals.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/init/globals.c,v 1.79 2004/01/26 22:54:57 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/init/globals.c,v 1.80 2004/01/26 22:59:53 momjian Exp $ * * NOTES * Globals used all over the place should be declared here and not @@ -53,6 +53,8 @@ BackendId MyBackendId; char *DatabasePath = NULL; Oid MyDatabaseId = InvalidOid; +pid_t PostmasterPid = 0; + /* these are initialized for the bootstrap/standalone case: */ bool IsPostmasterEnvironment = false; bool IsUnderPostmaster = false; diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index b48345858a..b44d160c27 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -12,7 +12,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.147 2004/01/26 22:54:57 momjian Exp $ + * $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.148 2004/01/26 22:59:53 momjian Exp $ * * NOTES * some of the information in this file should be moved to @@ -109,10 +109,14 @@ do { \ #else #define PG_USLEEP(_usec) \ do { \ - Sleep(_usec < 500) ? 1 : (_usec+500)/ 1000); \ + Sleep((_usec) < 500 ? 1 : ((_usec)+500)/ 1000); \ } while(0) #endif +#ifdef WIN32 +#define ftruncate(a,b) chsize(a,b) +#endif + /***************************************************************************** * globals.h -- * *****************************************************************************/ @@ -132,6 +136,7 @@ extern void ClosePostmasterPorts(bool pgstat_too); /* * from utils/init/globals.c */ +extern pid_t PostmasterPid; extern bool IsPostmasterEnvironment; extern bool IsUnderPostmaster; diff --git a/src/include/port/win32.h b/src/include/port/win32.h index 6562aa93e8..69cccb2b7a 100644 --- a/src/include/port/win32.h +++ b/src/include/port/win32.h @@ -1,4 +1,4 @@ -/* $PostgreSQL: pgsql/src/include/port/win32.h,v 1.15 2004/01/26 22:54:58 momjian Exp $ */ +/* $PostgreSQL: pgsql/src/include/port/win32.h,v 1.16 2004/01/26 22:59:54 momjian Exp $ */ /* undefine and redefine after #include */ #undef mkdir @@ -15,7 +15,7 @@ #define NOFILE 100 /* defines for dynamic linking on Win32 platform */ -#ifdef __CYGWIN__ +#if defined(__CYGWIN__) || defined(__MINGW32__) #if __GNUC__ && ! defined (__declspec) #error You need egcs 1.1 or newer for compiling! @@ -27,7 +27,7 @@ #define DLLIMPORT __declspec (dllimport) #endif -#elif defined(WIN32) && defined(_MSC_VER) /* not CYGWIN */ +#elif defined(WIN32) && defined(_MSC_VER) /* not CYGWIN or MingW */ #if defined(_DLL) #define DLLIMPORT __declspec (dllexport) @@ -35,7 +35,7 @@ #define DLLIMPORT __declspec (dllimport) #endif -#else /* not CYGWIN, not MSVC */ +#else /* not CYGWIN, not MSVC, not MingW */ #define DLLIMPORT #endif