Skip to content
Snippets Groups Projects
Commit 0021ae06 authored by Tom Lane's avatar Tom Lane
Browse files

Fix Win32 problems with signals and sockets, by making the forkexec code

even uglier than it was already :-(.  Also, on Windows only, use temporary
shared memory segments instead of ordinary files to pass over critical
variable values from postmaster to child processes.  Magnus Hagander
parent e1bf6527
No related branches found
No related tags found
No related merge requests found
......@@ -13,7 +13,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/main/main.c,v 1.92 2004/11/05 17:11:17 petere Exp $
* $PostgreSQL: pgsql/src/backend/main/main.c,v 1.93 2004/11/17 00:14:09 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -118,9 +118,6 @@ main(int argc, char *argv[])
argv[0], err);
exit(1);
}
/* Start our win32 signal implementation */
pgwin32_signal_initialize();
}
#endif
......@@ -281,6 +278,16 @@ main(int argc, char *argv[])
exit(SubPostmasterMain(argc, argv));
#endif
#ifdef WIN32
/*
* Start our win32 signal implementation
*
* SubPostmasterMain() will do this for itself, but the remaining
* modes need it here
*/
pgwin32_signal_initialize();
#endif
/*
* If the first argument is "-boot", then invoke bootstrap mode. (This
* path is taken only for a standalone bootstrap process.)
......
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/port/win32/signal.c,v 1.9 2004/11/09 13:01:25 petere Exp $
* $PostgreSQL: pgsql/src/backend/port/win32/signal.c,v 1.10 2004/11/17 00:14:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -26,6 +26,7 @@ static pqsigfunc pg_signal_defaults[PG_SIGNAL_COUNT];
static int pg_signal_mask;
DLLIMPORT HANDLE pgwin32_signal_event;
HANDLE pgwin32_initial_signal_pipe = INVALID_HANDLE_VALUE;
/* Signal handling thread function */
......@@ -154,6 +155,28 @@ pqsignal(int signum, pqsigfunc handler)
return prevfunc;
}
/* Create the signal listener pipe for specified pid */
HANDLE
pgwin32_create_signal_listener(pid_t pid)
{
char pipename[128];
HANDLE pipe;
wsprintf(pipename, "\\\\.\\pipe\\pgsignal_%d", (int) pid);
pipe = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, 16, 16, 1000, NULL);
if (pipe == INVALID_HANDLE_VALUE)
ereport(ERROR,
(errmsg("could not create signal listener pipe for pid %d: error code %d",
(int) pid, (int) GetLastError())));
return pipe;
}
/*
* All functions below execute on the signal handler thread
* and must be synchronized as such!
......@@ -210,7 +233,7 @@ static DWORD WINAPI
pg_signal_thread(LPVOID param)
{
char pipename[128];
HANDLE pipe = INVALID_HANDLE_VALUE;
HANDLE pipe = pgwin32_initial_signal_pipe;
wsprintf(pipename, "\\\\.\\pipe\\pgsignal_%d", GetCurrentProcessId());
......@@ -219,14 +242,18 @@ pg_signal_thread(LPVOID param)
BOOL fConnected;
HANDLE hThread;
pipe = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, 16, 16, 1000, NULL);
if (pipe == INVALID_HANDLE_VALUE)
{
write_stderr("could not create signal listener pipe: error code %d; retrying\n", (int) GetLastError());
SleepEx(500, FALSE);
continue;
pipe = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, 16, 16, 1000, NULL);
if (pipe == INVALID_HANDLE_VALUE)
{
write_stderr("could not create signal listener pipe: error code %d; retrying\n", (int) GetLastError());
SleepEx(500, FALSE);
continue;
}
}
fConnected = ConnectNamedPipe(pipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
......@@ -244,6 +271,9 @@ pg_signal_thread(LPVOID param)
else
/* Connection failed. Cleanup and try again */
CloseHandle(pipe);
/* Set up so we create a new pipe on next loop */
pipe = INVALID_HANDLE_VALUE;
}
return 0;
}
......
......@@ -13,7 +13,7 @@
*
* Copyright (c) 2001-2004, PostgreSQL Global Development Group
*
* $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.84 2004/10/28 01:38:41 neilc Exp $
* $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.85 2004/11/17 00:14:12 tgl Exp $
* ----------
*/
#include "postgres.h"
......@@ -110,8 +110,9 @@ bool pgstat_collect_blocklevel = false;
* ----------
*/
NON_EXEC_STATIC int pgStatSock = -1;
static int pgStatPipe[2];
NON_EXEC_STATIC int pgStatPipe[2] = {-1,-1};
static struct sockaddr_storage pgStatAddr;
static pid_t pgStatCollectorPid = 0;
static time_t last_pgstat_start_time;
......@@ -492,10 +493,6 @@ pgstat_forkexec(STATS_PROCESS_TYPE procType)
/* postgres_exec_path is not passed by write_backend_variables */
av[ac++] = postgres_exec_path;
/* Pipe file ids (those not passed by write_backend_variables) */
snprintf(pgstatBuf[bufc++], 32, "%d", pgStatPipe[0]);
snprintf(pgstatBuf[bufc++], 32, "%d", pgStatPipe[1]);
/* Add to the arg list */
Assert(bufc <= lengthof(pgstatBuf));
for (i = 0; i < bufc; i++)
......@@ -517,12 +514,10 @@ pgstat_forkexec(STATS_PROCESS_TYPE procType)
static void
pgstat_parseArgs(int argc, char *argv[])
{
Assert(argc == 6);
Assert(argc == 4);
argc = 3;
StrNCpy(postgres_exec_path, argv[argc++], MAXPGPATH);
pgStatPipe[0] = atoi(argv[argc++]);
pgStatPipe[1] = atoi(argv[argc++]);
}
#endif /* EXEC_BACKEND */
......@@ -1385,12 +1380,13 @@ PgstatBufferMain(int argc, char *argv[])
(errcode_for_socket_access(),
errmsg("could not create pipe for statistics buffer: %m")));
#ifdef EXEC_BACKEND
/* child becomes collector process */
switch (pgstat_forkexec(STAT_PROC_COLLECTOR))
#ifdef EXEC_BACKEND
pgStatCollectorPid = pgstat_forkexec(STAT_PROC_COLLECTOR);
#else
switch (fork())
pgStatCollectorPid = fork();
#endif
switch (pgStatCollectorPid)
{
case -1:
ereport(ERROR,
......@@ -1445,7 +1441,12 @@ PgstatCollectorMain(int argc, char *argv[])
pqsignal(SIGHUP, SIG_IGN);
pqsignal(SIGINT, SIG_IGN);
pqsignal(SIGTERM, SIG_IGN);
#ifndef WIN32
pqsignal(SIGQUIT, SIG_IGN);
#else
/* kluge to allow buffer process to kill collector; FIXME */
pqsignal(SIGQUIT, pgstat_exit);
#endif
pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN);
pqsignal(SIGUSR1, SIG_IGN);
......@@ -1943,6 +1944,16 @@ pgstat_exit(SIGNAL_ARGS)
* be cleaner to allow any pending messages to be sent, but that
* creates a tradeoff against speed of exit.
*/
/*
* If running in bufferer, kill our collector as well. On some broken
* win32 systems, it does not shut down automatically because of issues
* with socket inheritance. XXX so why not fix the socket inheritance...
*/
#ifdef WIN32
if (pgStatCollectorPid > 0)
kill(pgStatCollectorPid, SIGQUIT);
#endif
exit(0);
}
......
......@@ -37,7 +37,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.438 2004/11/14 19:35:30 tgl Exp $
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.439 2004/11/17 00:14:12 tgl Exp $
*
* NOTES
*
......@@ -120,6 +120,10 @@
#include "bootstrap/bootstrap.h"
#include "pgstat.h"
#ifdef EXEC_BACKEND
#include "storage/spin.h"
#endif
/*
* List of active backends (or child processes anyway; we don't actually
......@@ -273,7 +277,6 @@ static pid_t StartChildProcess(int xlop);
#ifdef EXEC_BACKEND
#ifdef WIN32
static 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);
......@@ -289,11 +292,67 @@ HANDLE PostmasterHandle;
static pid_t backend_forkexec(Port *port);
static pid_t internal_forkexec(int argc, char *argv[], Port *port);
static void read_backend_variables(char *filename, Port *port);
static bool write_backend_variables(char *filename, Port *port);
/* Type for a socket that can be inherited to a client process */
#ifdef WIN32
typedef struct
{
SOCKET origsocket; /* Original socket value, or -1 if not a socket */
WSAPROTOCOL_INFO wsainfo;
} InheritableSocket;
#else
typedef int InheritableSocket;
#endif
typedef struct LWLock LWLock; /* ugly kluge */
/*
* Structure contains all variables passed to exec:ed backends
*/
typedef struct
{
Port port;
InheritableSocket portsocket;
char DataDir[MAXPGPATH];
int ListenSocket[MAXLISTEN];
long MyCancelKey;
unsigned long UsedShmemSegID;
void *UsedShmemSegAddr;
slock_t *ShmemLock;
slock_t *ShmemIndexLock;
VariableCache ShmemVariableCache;
void *ShmemIndexAlloc;
Backend *ShmemBackendArray;
LWLock *LWLockArray;
slock_t *ProcStructLock;
InheritableSocket pgStatSock;
InheritableSocket pgStatPipe0;
InheritableSocket pgStatPipe1;
pid_t PostmasterPid;
#ifdef WIN32
HANDLE PostmasterHandle;
HANDLE initial_signal_pipe;
HANDLE syslogPipe[2];
#else
int syslogPipe[2];
#endif
char my_exec_path[MAXPGPATH];
char ExtraOptions[MAXPGPATH];
char lc_collate[MAXPGPATH];
char lc_ctype[MAXPGPATH];
} BackendParameters;
static void read_backend_variables(char *id, Port *port);
static void restore_backend_variables(BackendParameters *param, Port *port);
#ifndef WIN32
static bool save_backend_variables(BackendParameters *param, Port *port);
#else
static bool save_backend_variables(BackendParameters *param, Port *port,
HANDLE childProcess, pid_t childPid);
#endif
static void ShmemBackendArrayAdd(Backend *bn);
static void ShmemBackendArrayRemove(pid_t pid);
#endif /* EXEC_BACKEND */
#define StartupDataBase() StartChildProcess(BS_XLOG_STARTUP)
......@@ -336,6 +395,11 @@ PostmasterMain(int argc, char *argv[])
}
}
#ifdef WIN32
/* Start our win32 signal implementation */
pgwin32_signal_initialize();
#endif
/*
* for security, no dir or file created can be group or other
* accessible
......@@ -756,7 +820,7 @@ PostmasterMain(int argc, char *argv[])
TRUE,
DUPLICATE_SAME_ACCESS) == 0)
ereport(FATAL,
(errmsg_internal("could not duplicate postmaster handle: %d",
(errmsg_internal("could not duplicate postmaster handle: error code %d",
(int) GetLastError())));
#endif
......@@ -2799,14 +2863,70 @@ backend_forkexec(Port *port)
return internal_forkexec(ac, av, port);
}
#ifndef WIN32
/*
* internal_forkexec non-win32 implementation
*
* - writes out backend variables to the parameter file
* - fork():s, and then exec():s the child process
*/
static pid_t
internal_forkexec(int argc, char *argv[], Port *port)
{
static unsigned long tmpBackendFileNum = 0;
pid_t pid;
char tmpfilename[MAXPGPATH];
BackendParameters param;
FILE *fp;
if (!save_backend_variables(&param, port))
return -1; /* log made by save_backend_variables */
/* Calculate name for temp file */
Assert(DataDir);
snprintf(tmpfilename, MAXPGPATH, "%s/%s/%s.backend_var.%d.%lu",
DataDir, PG_TEMP_FILES_DIR, PG_TEMP_FILE_PREFIX,
MyProcPid, ++tmpBackendFileNum);
if (!write_backend_variables(tmpfilename, port))
return -1; /* log made by write_backend_variables */
/* Open file */
fp = AllocateFile(tmpfilename, PG_BINARY_W);
if (!fp)
{
/* As per OpenTemporaryFile... */
char dirname[MAXPGPATH];
snprintf(dirname, MAXPGPATH, "%s/%s", DataDir, PG_TEMP_FILES_DIR);
mkdir(dirname, S_IRWXU);
fp = AllocateFile(tmpfilename, PG_BINARY_W);
if (!fp)
{
ereport(LOG,
(errcode_for_file_access(),
errmsg("could not create file \"%s\": %m",
tmpfilename)));
return -1;
}
}
if (fwrite(&param, sizeof(param), 1, fp) != 1)
{
ereport(LOG,
(errcode_for_file_access(),
errmsg("could not write to file \"%s\": %m", tmpfilename)));
FreeFile(fp);
return -1;
}
/* Release file */
if (FreeFile(fp))
{
ereport(LOG,
(errcode_for_file_access(),
errmsg("could not write to file \"%s\": %m", tmpfilename)));
return -1;
}
/* Make sure caller set up argv properly */
Assert(argc >= 3);
......@@ -2817,9 +2937,6 @@ internal_forkexec(int argc, char *argv[], Port *port)
/* Insert temp file name after -fork argument */
argv[2] = tmpfilename;
#ifdef WIN32
pid = win32_forkexec(postgres_exec_path, argv);
#else
/* Fire off execv in child */
if ((pid = fork()) == 0)
{
......@@ -2832,12 +2949,188 @@ internal_forkexec(int argc, char *argv[], Port *port)
exit(1);
}
}
#endif
return pid; /* Parent returns pid, or -1 on fork
* failure */
}
#else /* WIN32 */
/*
* internal_forkexec win32 implementation
*
* - starts backend using CreateProcess(), in suspended state
* - writes out backend variables to the parameter file
* - during this, duplicates handles and sockets required for
* inheritance into the new process
* - resumes execution of the new process once the backend parameter
* file is complete.
*/
static pid_t
internal_forkexec(int argc, char *argv[], Port *port)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
int i;
int j;
char cmdLine[MAXPGPATH * 2];
HANDLE childHandleCopy;
HANDLE waiterThread;
HANDLE paramHandle;
BackendParameters *param;
SECURITY_ATTRIBUTES sa;
char paramHandleStr[32];
/* Make sure caller set up argv properly */
Assert(argc >= 3);
Assert(argv[argc] == NULL);
Assert(strncmp(argv[1], "-fork", 5) == 0);
Assert(argv[2] == NULL);
/* Set up shared memory for parameter passing */
ZeroMemory(&sa,sizeof(sa));
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
paramHandle = CreateFileMapping(INVALID_HANDLE_VALUE,
&sa,
PAGE_READWRITE,
0,
sizeof(BackendParameters),
NULL);
if (paramHandle == INVALID_HANDLE_VALUE)
{
elog(LOG, "could not create backend parameter file mapping: error code %d",
(int) GetLastError());
return -1;
}
param = MapViewOfFile(paramHandle, FILE_MAP_WRITE, 0, 0, sizeof(BackendParameters));
if (!param)
{
elog(LOG, "could not map backend parameter memory: error code %d",
(int) GetLastError());
CloseHandle(paramHandle);
return -1;
}
/* Insert temp file name after -fork argument */
sprintf(paramHandleStr, "%lu", (DWORD)paramHandle);
argv[2] = paramHandleStr;
/* Format the cmd line */
cmdLine[sizeof(cmdLine) - 1] = '\0';
cmdLine[sizeof(cmdLine) - 2] = '\0';
snprintf(cmdLine, sizeof(cmdLine) - 1, "\"%s\"", postgres_exec_path);
i = 0;
while (argv[++i] != NULL)
{
j = strlen(cmdLine);
snprintf(cmdLine + j, sizeof(cmdLine) - 1 - j, " \"%s\"", argv[i]);
}
if (cmdLine[sizeof(cmdLine) - 2] != '\0')
{
elog(LOG, "subprocess command line too long");
return -1;
}
memset(&pi, 0, sizeof(pi));
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
/*
* Create the subprocess in a suspended state. This will be resumed
* later, once we have written out the parameter file.
*/
if (!CreateProcess(NULL, cmdLine, NULL, NULL, TRUE, CREATE_SUSPENDED,
NULL, NULL, &si, &pi))
{
elog(LOG, "CreateProcess call failed: %m (error code %d)",
(int) GetLastError());
return -1;
}
if (!save_backend_variables(param, port, pi.hProcess, pi.dwProcessId))
{
/*
* log made by save_backend_variables, but we have to clean
* up the mess with the half-started process
*/
if (!TerminateProcess(pi.hProcess, 255))
ereport(ERROR,
(errmsg_internal("could not terminate unstarted process: error code %d",
(int) GetLastError())));
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return -1; /* log made by save_backend_variables */
}
/* Drop the shared memory that is now inherited to the backend */
if (!UnmapViewOfFile(param))
elog(LOG, "could not unmap view of backend parameter file: error code %d",
(int) GetLastError());
if (!CloseHandle(paramHandle))
elog(LOG, "could not close handle to backend parameter file: error code %d",
(int) GetLastError());
/*
* Now that the backend variables are written out, we start the
* child thread so it can start initializing while we set up
* the rest of the parent state.
*/
if (ResumeThread(pi.hThread) == -1)
{
if (!TerminateProcess(pi.hProcess, 255))
{
ereport(ERROR,
(errmsg_internal("could not terminate unstartable process: error code %d",
(int) GetLastError())));
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return -1;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
ereport(ERROR,
(errmsg_internal("could not resume thread of unstarted process: error code %d",
(int) GetLastError())));
return -1;
}
if (!IsUnderPostmaster)
{
/* We are the Postmaster creating a child... */
win32_AddChild(pi.dwProcessId, pi.hProcess);
}
/* Set up the thread to handle the SIGCHLD for this process */
if (DuplicateHandle(GetCurrentProcess(),
pi.hProcess,
GetCurrentProcess(),
&childHandleCopy,
0,
FALSE,
DUPLICATE_SAME_ACCESS) == 0)
ereport(FATAL,
(errmsg_internal("could not duplicate child handle: error code %d",
(int) GetLastError())));
waiterThread = CreateThread(NULL, 64 * 1024, win32_sigchld_waiter,
(LPVOID) childHandleCopy, 0, NULL);
if (!waiterThread)
ereport(FATAL,
(errmsg_internal("could not create sigchld waiter thread: error code %d",
(int) GetLastError())));
CloseHandle(waiterThread);
if (IsUnderPostmaster)
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return pi.dwProcessId;
}
#endif /* WIN32 */
/*
* SubPostmasterMain -- Get the fork/exec'd process into a state equivalent
* to what it would be if we'd simply forked on Unix, and then
......@@ -2859,6 +3152,19 @@ SubPostmasterMain(int argc, char *argv[])
MyProcPid = getpid(); /* reset MyProcPid */
/* Read in file-based context */
memset(&port, 0, sizeof(Port));
read_backend_variables(argv[2], &port);
/*
* Start our win32 signal implementation. This has to be done
* after we read the backend variables, because we need to pick
* up the signal pipe from the parent process.
*/
#ifdef WIN32
pgwin32_signal_initialize();
#endif
/* In EXEC_BACKEND case we will not have inherited these settings */
IsPostmasterEnvironment = true;
whereToSendOutput = None;
......@@ -2873,9 +3179,7 @@ SubPostmasterMain(int argc, char *argv[])
if (argc < 3)
elog(FATAL, "invalid subpostmaster invocation");
/* Read in file-based context */
memset(&port, 0, sizeof(Port));
read_backend_variables(argv[2], &port);
/* Read in remaining GUC variables */
read_nondefault_variables();
/* Run backend or appropriate child */
......@@ -3297,189 +3601,278 @@ CreateOptsFile(int argc, char *argv[], char *fullprogname)
#ifdef EXEC_BACKEND
/*
* The following need to be available to the read/write_backend_variables
* The following need to be available to the save/restore_backend_variables
* functions
*/
#include "storage/spin.h"
extern slock_t *ShmemLock;
extern slock_t *ShmemIndexLock;
extern void *ShmemIndexAlloc;
typedef struct LWLock LWLock;
extern LWLock *LWLockArray;
extern slock_t *ProcStructLock;
extern int pgStatSock;
extern int pgStatPipe[2];
#ifndef WIN32
#define write_inheritable_socket(dest, src, childpid) (*(dest) = (src))
#define read_inheritable_socket(dest, src) (*(dest) = *(src))
#else
static void write_duplicated_handle(HANDLE *dest, HANDLE src, HANDLE child);
static void write_inheritable_socket(InheritableSocket *dest, SOCKET src,
pid_t childPid);
static void read_inheritable_socket(SOCKET *dest, InheritableSocket *src);
#endif
#define write_var(var,fp) fwrite((void*)&(var),sizeof(var),1,fp)
#define read_var(var,fp) fread((void*)&(var),sizeof(var),1,fp)
#define write_array_var(var,fp) fwrite((void*)(var),sizeof(var),1,fp)
#define read_array_var(var,fp) fread((void*)(var),sizeof(var),1,fp)
/* Save critical backend variables into the BackendParameters struct */
#ifndef WIN32
static bool
write_backend_variables(char *filename, Port *port)
save_backend_variables(BackendParameters *param, Port *port)
#else
static bool
save_backend_variables(BackendParameters *param, Port *port,
HANDLE childProcess, pid_t childPid)
#endif
{
static unsigned long tmpBackendFileNum = 0;
FILE *fp;
char str_buf[MAXPGPATH];
memcpy(&param->port, port, sizeof(Port));
write_inheritable_socket(&param->portsocket, port->sock, childPid);
/* Calculate name for temp file in caller's buffer */
Assert(DataDir);
snprintf(filename, MAXPGPATH, "%s/%s/%s.backend_var.%d.%lu",
DataDir, PG_TEMP_FILES_DIR, PG_TEMP_FILE_PREFIX,
MyProcPid, ++tmpBackendFileNum);
StrNCpy(param->DataDir, DataDir, MAXPGPATH);
/* Open file */
fp = AllocateFile(filename, PG_BINARY_W);
if (!fp)
{
/* As per OpenTemporaryFile... */
char dirname[MAXPGPATH];
memcpy(&param->ListenSocket, &ListenSocket, sizeof(ListenSocket));
snprintf(dirname, MAXPGPATH, "%s/%s", DataDir, PG_TEMP_FILES_DIR);
mkdir(dirname, S_IRWXU);
param->MyCancelKey = MyCancelKey;
fp = AllocateFile(filename, PG_BINARY_W);
if (!fp)
{
ereport(LOG,
(errcode_for_file_access(),
errmsg("could not create file \"%s\": %m",
filename)));
return false;
}
}
param->UsedShmemSegID = UsedShmemSegID;
param->UsedShmemSegAddr = UsedShmemSegAddr;
/* Write vars */
write_var(port->sock, fp);
write_var(port->proto, fp);
write_var(port->laddr, fp);
write_var(port->raddr, fp);
write_var(port->canAcceptConnections, fp);
write_var(port->cryptSalt, fp);
write_var(port->md5Salt, fp);
param->ShmemLock = ShmemLock;
param->ShmemIndexLock = ShmemIndexLock;
param->ShmemVariableCache = ShmemVariableCache;
param->ShmemIndexAlloc = ShmemIndexAlloc;
param->ShmemBackendArray = ShmemBackendArray;
/*
* XXX FIXME later: writing these strings as MAXPGPATH bytes always is
* probably a waste of resources
*/
param->LWLockArray = LWLockArray;
param->ProcStructLock = ProcStructLock;
write_inheritable_socket(&param->pgStatSock, pgStatSock, childPid);
write_inheritable_socket(&param->pgStatPipe0, pgStatPipe[0], childPid);
write_inheritable_socket(&param->pgStatPipe1, pgStatPipe[1], childPid);
StrNCpy(str_buf, DataDir, MAXPGPATH);
write_array_var(str_buf, fp);
param->PostmasterPid = PostmasterPid;
write_array_var(ListenSocket, fp);
#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
write_duplicated_handle(&param->initial_signal_pipe,
pgwin32_create_signal_listener(childPid),
childProcess);
#endif
write_var(MyCancelKey, fp);
memcpy(&param->syslogPipe, &syslogPipe, sizeof(syslogPipe));
write_var(UsedShmemSegID, fp);
write_var(UsedShmemSegAddr, fp);
StrNCpy(param->my_exec_path, my_exec_path, MAXPGPATH);
write_var(ShmemLock, fp);
write_var(ShmemIndexLock, fp);
write_var(ShmemVariableCache, fp);
write_var(ShmemIndexAlloc, fp);
write_var(ShmemBackendArray, fp);
StrNCpy(param->ExtraOptions, ExtraOptions, MAXPGPATH);
write_var(LWLockArray, fp);
write_var(ProcStructLock, fp);
write_var(pgStatSock, fp);
StrNCpy(param->lc_collate, setlocale(LC_COLLATE, NULL), MAXPGPATH);
StrNCpy(param->lc_ctype, setlocale(LC_CTYPE, NULL), MAXPGPATH);
write_var(PostmasterPid, fp);
#ifdef WIN32
write_var(PostmasterHandle, fp);
#endif
return true;
}
write_var(syslogPipe[0], fp);
write_var(syslogPipe[1], fp);
StrNCpy(str_buf, my_exec_path, MAXPGPATH);
write_array_var(str_buf, fp);
#ifdef WIN32
/*
* Duplicate a handle for usage in a child process, and write the child
* process instance of the handle to the parameter file.
*/
static void
write_duplicated_handle(HANDLE *dest, HANDLE src, HANDLE childProcess)
{
HANDLE hChild = INVALID_HANDLE_VALUE;
if (!DuplicateHandle(GetCurrentProcess(),
src,
childProcess,
&hChild,
0,
TRUE,
DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS))
ereport(ERROR,
(errmsg_internal("could not duplicate handle to be written to backend parameter file: error code %d",
(int) GetLastError())));
*dest = hChild;
}
write_array_var(ExtraOptions, fp);
/*
* Duplicate a socket for usage in a child process, and write the resulting
* structure to the parameter file.
* This is required because a number of LSPs (Layered Service Providers) very
* common on Windows (antivirus, firewalls, download managers etc) break
* straight socket inheritance.
*/
static void
write_inheritable_socket(InheritableSocket *dest, SOCKET src, pid_t childpid)
{
dest->origsocket = src;
if (src != 0 && src != -1)
{
/* Actual socket */
if (WSADuplicateSocket(src, childpid, &dest->wsainfo) != 0)
ereport(ERROR,
(errmsg("could not duplicate socket %d for use in backend: error code %d",
src, WSAGetLastError())));
}
}
StrNCpy(str_buf, setlocale(LC_COLLATE, NULL), MAXPGPATH);
write_array_var(str_buf, fp);
StrNCpy(str_buf, setlocale(LC_CTYPE, NULL), MAXPGPATH);
write_array_var(str_buf, fp);
/*
* Read a duplicate socket structure back, and get the socket descriptor.
*/
static void
read_inheritable_socket(SOCKET *dest, InheritableSocket *src)
{
SOCKET s;
/* Release file */
if (FreeFile(fp))
if (src->origsocket == -1 || src->origsocket == 0)
{
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not write to file \"%s\": %m", filename)));
return false;
/* Not a real socket! */
*dest = src->origsocket;
}
else
{
/* Actual socket, so create from structure */
s = WSASocket(FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,
&src->wsainfo,
0,
0);
if (s == INVALID_SOCKET)
{
write_stderr("could not create inherited socket: error code %d\n",
WSAGetLastError());
exit(1);
}
*dest = s;
return true;
/*
* To make sure we don't get two references to the same socket,
* close the original one. (This would happen when inheritance
* actually works..
*/
closesocket(src->origsocket);
}
}
#endif
static void
read_backend_variables(char *filename, Port *port)
read_backend_variables(char *id, Port *port)
{
FILE *fp;
char str_buf[MAXPGPATH];
#ifndef WIN32
/* Non-win32 implementation reads from file */
FILE *fp;
BackendParameters param;
/* Open file */
fp = AllocateFile(filename, PG_BINARY_R);
fp = AllocateFile(id, PG_BINARY_R);
if (!fp)
ereport(FATAL,
(errcode_for_file_access(),
errmsg("could not read from backend variables file \"%s\": %m",
filename)));
{
write_stderr("could not read from backend variables file \"%s\": %s\n",
id, strerror(errno));
exit(1);
}
if (fread(&param, sizeof(param), 1, fp) != 1)
{
write_stderr("could not read from backend variables file \"%s\": %s\n",
id, strerror(errno));
exit(1);
}
/* Release file */
FreeFile(fp);
if (unlink(id) != 0)
{
write_stderr("could not remove file \"%s\": %s\n",
id, strerror(errno));
exit(1);
}
/* Read vars */
read_var(port->sock, fp);
read_var(port->proto, fp);
read_var(port->laddr, fp);
read_var(port->raddr, fp);
read_var(port->canAcceptConnections, fp);
read_var(port->cryptSalt, fp);
read_var(port->md5Salt, fp);
restore_backend_variables(&param, port);
#else
/* Win32 version uses mapped file */
HANDLE paramHandle;
BackendParameters *param;
read_array_var(str_buf, fp);
SetDataDir(str_buf);
paramHandle = (HANDLE)atol(id);
param = MapViewOfFile(paramHandle, FILE_MAP_READ, 0, 0, 0);
if (!param)
{
write_stderr("could not map view of backend variables: error code %d\n",
(int) GetLastError());
exit(1);
}
read_array_var(ListenSocket, fp);
restore_backend_variables(param, port);
read_var(MyCancelKey, fp);
if (!UnmapViewOfFile(param))
{
write_stderr("could not unmap view of backend variables: error code %d\n",
(int) GetLastError());
exit(1);
}
read_var(UsedShmemSegID, fp);
read_var(UsedShmemSegAddr, fp);
if (!CloseHandle(paramHandle))
{
write_stderr("could not close handle to backend parameter variables: error code %d\n",
(int) GetLastError());
exit(1);
}
#endif
}
/* Restore critical backend variables from the BackendParameters struct */
static void
restore_backend_variables(BackendParameters *param, Port *port)
{
memcpy(port, &param->port, sizeof(Port));
read_inheritable_socket(&port->sock, &param->portsocket);
SetDataDir(param->DataDir);
read_var(ShmemLock, fp);
read_var(ShmemIndexLock, fp);
read_var(ShmemVariableCache, fp);
read_var(ShmemIndexAlloc, fp);
read_var(ShmemBackendArray, fp);
memcpy(&ListenSocket, &param->ListenSocket, sizeof(ListenSocket));
read_var(LWLockArray, fp);
read_var(ProcStructLock, fp);
read_var(pgStatSock, fp);
MyCancelKey = param->MyCancelKey;
UsedShmemSegID = param->UsedShmemSegID;
UsedShmemSegAddr = param->UsedShmemSegAddr;
ShmemLock = param->ShmemLock;
ShmemIndexLock = param->ShmemIndexLock;
ShmemVariableCache = param->ShmemVariableCache;
ShmemIndexAlloc = param->ShmemIndexAlloc;
ShmemBackendArray = param->ShmemBackendArray;
LWLockArray = param->LWLockArray;
ProcStructLock = param->ProcStructLock;
read_inheritable_socket(&pgStatSock, &param->pgStatSock);
read_inheritable_socket(&pgStatPipe[0], &param->pgStatPipe0);
read_inheritable_socket(&pgStatPipe[1], &param->pgStatPipe1);
PostmasterPid = param->PostmasterPid;
read_var(PostmasterPid, fp);
#ifdef WIN32
read_var(PostmasterHandle, fp);
PostmasterHandle = param->PostmasterHandle;
pgwin32_initial_signal_pipe = param->initial_signal_pipe;
#endif
read_var(syslogPipe[0], fp);
read_var(syslogPipe[1], fp);
read_array_var(str_buf, fp);
StrNCpy(my_exec_path, str_buf, MAXPGPATH);
memcpy(&syslogPipe, &param->syslogPipe, sizeof(syslogPipe));
read_array_var(ExtraOptions, fp);
StrNCpy(my_exec_path, param->my_exec_path, MAXPGPATH);
read_array_var(str_buf, fp);
setlocale(LC_COLLATE, str_buf);
read_array_var(str_buf, fp);
setlocale(LC_CTYPE, str_buf);
StrNCpy(ExtraOptions, param->ExtraOptions, MAXPGPATH);
/* Release file */
FreeFile(fp);
if (unlink(filename) != 0)
ereport(WARNING,
(errcode_for_file_access(),
errmsg("could not remove file \"%s\": %m", filename)));
setlocale(LC_COLLATE, param->lc_collate);
setlocale(LC_CTYPE, param->lc_ctype);
}
......@@ -3542,74 +3935,6 @@ ShmemBackendArrayRemove(pid_t pid)
#ifdef WIN32
static pid_t
win32_forkexec(const char *path, char *argv[])
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
int i;
int j;
char cmdLine[MAXPGPATH * 2];
HANDLE childHandleCopy;
HANDLE waiterThread;
/* Format the cmd line */
cmdLine[sizeof(cmdLine) - 1] = '\0';
cmdLine[sizeof(cmdLine) - 2] = '\0';
snprintf(cmdLine, sizeof(cmdLine) - 1, "\"%s\"", path);
i = 0;
while (argv[++i] != NULL)
{
j = strlen(cmdLine);
snprintf(cmdLine + j, sizeof(cmdLine) - 1 - j, " \"%s\"", argv[i]);
}
if (cmdLine[sizeof(cmdLine) - 2] != '\0')
{
elog(LOG, "subprocess command line too long");
return -1;
}
memset(&pi, 0, sizeof(pi));
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
if (!CreateProcess(NULL, cmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
{
elog(LOG, "CreateProcess call failed (%d): %m", (int) GetLastError());
return -1;
}
if (!IsUnderPostmaster)
{
/* We are the Postmaster creating a child... */
win32_AddChild(pi.dwProcessId, pi.hProcess);
}
if (DuplicateHandle(GetCurrentProcess(),
pi.hProcess,
GetCurrentProcess(),
&childHandleCopy,
0,
FALSE,
DUPLICATE_SAME_ACCESS) == 0)
ereport(FATAL,
(errmsg_internal("could not duplicate child handle: %d",
(int) GetLastError())));
waiterThread = CreateThread(NULL, 64 * 1024, win32_sigchld_waiter,
(LPVOID) childHandleCopy, 0, NULL);
if (!waiterThread)
ereport(FATAL,
(errmsg_internal("could not create sigchld waiter thread: %d",
(int) GetLastError())));
CloseHandle(waiterThread);
if (IsUnderPostmaster)
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)
......@@ -3687,7 +4012,7 @@ win32_waitpid(int *exitstatus)
{
case WAIT_FAILED:
ereport(LOG,
(errmsg_internal("failed to wait on %lu of %lu children: %d",
(errmsg_internal("failed to wait on %lu of %lu children: error code %d",
num, win32_numChildren, (int) GetLastError())));
return -1;
......@@ -3712,7 +4037,7 @@ win32_waitpid(int *exitstatus)
*/
ereport(FATAL,
(errmsg_internal("failed to get exit code for child %lu",
win32_childPIDArray[index])));
(DWORD)win32_childPIDArray[index])));
}
*exitstatus = (int) exitCode;
return win32_childPIDArray[index];
......
/* $PostgreSQL: pgsql/src/include/port/win32.h,v 1.39 2004/10/06 17:47:53 momjian Exp $ */
/* $PostgreSQL: pgsql/src/include/port/win32.h,v 1.40 2004/11/17 00:14:14 tgl Exp $ */
/* undefine and redefine after #include */
#undef mkdir
......@@ -104,8 +104,11 @@ int semop(int semId, struct sembuf * sops, int flag);
/* In backend/port/win32/signal.c */
void pgwin32_signal_initialize(void);
extern DLLIMPORT HANDLE pgwin32_signal_event;
extern HANDLE pgwin32_initial_signal_pipe;
void pgwin32_signal_initialize(void);
HANDLE pgwin32_create_signal_listener(pid_t pid);
void pgwin32_dispatch_queued_signals(void);
void pg_queue_signal(int signum);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment