@ -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