Index: backend/main/main.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/main/main.c,v
retrieving revision 1.92
diff -c -r1.92 main.c
*** backend/main/main.c	5 Nov 2004 17:11:17 -0000	1.92
--- backend/main/main.c	11 Nov 2004 20:33:11 -0000
***************
*** 118,126 ****
  						 argv[0], err);
  			exit(1);
  		}
-
- 		/* Start our win32 signal implementation */
- 		pgwin32_signal_initialize();
  	}
  #endif

--- 118,123 ----
***************
*** 281,286 ****
--- 278,291 ----
  		exit(SubPostmasterMain(argc, argv));
  #endif

+ #ifdef WIN32
+ 	/* Start our win32 signal implementation
+ 	 * SubPostmasterMain() will do this when it's called, but all other
+ 	 * 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.)
Index: backend/port/win32/signal.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/port/win32/signal.c,v
retrieving revision 1.9
diff -c -r1.9 signal.c
*** backend/port/win32/signal.c	9 Nov 2004 13:01:25 -0000	1.9
--- backend/port/win32/signal.c	12 Nov 2004 19:54:32 -0000
***************
*** 26,31 ****
--- 26,32 ----
  static int	pg_signal_mask;

  DLLIMPORT HANDLE pgwin32_signal_event;
+ HANDLE pgwin32_initial_signal_pipe = INVALID_HANDLE_VALUE;


  /* Signal handling thread function */
***************
*** 154,159 ****
--- 155,183 ----
  	return prevfunc;
  }

+ /* Create the signal listener pipe for specified pid */
+ HANDLE pgwin32_create_signal_listener(pid_t pid)
+ {
+ 	char		pipename[128];
+ 	HANDLE		pipe = INVALID_HANDLE_VALUE;
+ 
+ 	wsprintf(pipename, "\\\\.\\pipe\\pgsignal_%d", 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 %i: error code %i",
+ 						pid, (int) GetLastError())));
+ 	}
+ 
+ 	return pipe;
+ }
+ 
+ 
  /*
   * All functions below execute on the signal handler thread
   * and must be synchronized as such!
***************
*** 210,232 ****
  pg_signal_thread(LPVOID param)
  {
  	char		pipename[128];
! 	HANDLE		pipe = INVALID_HANDLE_VALUE;
  
  	wsprintf(pipename, "\\\\.\\pipe\\pgsignal_%d", GetCurrentProcessId());
  
! 	for (;;)
  	{
  		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;
  		}
  
  		fConnected = ConnectNamedPipe(pipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
--- 234,260 ----
  pg_signal_thread(LPVOID param)
  {
  	char		pipename[128];
! 	HANDLE      pipe = pgwin32_initial_signal_pipe;
  
  	wsprintf(pipename, "\\\\.\\pipe\\pgsignal_%d", GetCurrentProcessId());
  
!   	for (;;)
  	{
  		BOOL		fConnected;
  		HANDLE		hThread;
  
  		if (pipe == INVALID_HANDLE_VALUE)
  		{
! 			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,249 ****
--- 272,280 ----
  		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;
  }
Index: backend/postmaster/pgstat.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/postmaster/pgstat.c,v
retrieving revision 1.84
diff -c -r1.84 pgstat.c
*** backend/postmaster/pgstat.c	28 Oct 2004 01:38:41 -0000	1.84
--- backend/postmaster/pgstat.c	12 Nov 2004 19:55:04 -0000
***************
*** 110,117 ****
   * ----------
   */
  NON_EXEC_STATIC int pgStatSock = -1;
! static int	pgStatPipe[2];
  static struct sockaddr_storage pgStatAddr;
  
  static time_t last_pgstat_start_time;
  
--- 110,118 ----
   * ----------
   */
  NON_EXEC_STATIC int pgStatSock = -1;
! 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,501 ****
  	/* 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++)
--- 493,498 ----
***************
*** 517,528 ****
  static void
  pgstat_parseArgs(int argc, char *argv[])
  {
! 	Assert(argc == 6);
  
  	argc = 3;
  	StrNCpy(postgres_exec_path, argv[argc++], MAXPGPATH);
- 	pgStatPipe[0] = atoi(argv[argc++]);
- 	pgStatPipe[1] = atoi(argv[argc++]);
  }
  #endif   /* EXEC_BACKEND */
  
--- 514,523 ----
  static void
  pgstat_parseArgs(int argc, char *argv[])
  {
! 	Assert(argc == 4);
  
  	argc = 3;
  	StrNCpy(postgres_exec_path, argv[argc++], MAXPGPATH);
  }
  #endif   /* EXEC_BACKEND */
  
***************
*** 1387,1396 ****
  
  #ifdef EXEC_BACKEND
  	/* child becomes collector process */
! 	switch (pgstat_forkexec(STAT_PROC_COLLECTOR))
  #else
! 	switch (fork())
  #endif
  	{
  		case -1:
  			ereport(ERROR,
--- 1382,1392 ----
  
  #ifdef EXEC_BACKEND
  	/* child becomes collector process */
! 	pgStatCollectorPid = pgstat_forkexec(STAT_PROC_COLLECTOR);
  #else
! 	pgStatCollectorPid = fork();
  #endif
+ 	switch (pgStatCollectorPid)
  	{
  		case -1:
  			ereport(ERROR,
***************
*** 1445,1451 ****
  	pqsignal(SIGHUP, SIG_IGN);
  	pqsignal(SIGINT, SIG_IGN);
  	pqsignal(SIGTERM, SIG_IGN);
! 	pqsignal(SIGQUIT, SIG_IGN);
  	pqsignal(SIGALRM, SIG_IGN);
  	pqsignal(SIGPIPE, SIG_IGN);
  	pqsignal(SIGUSR1, SIG_IGN);
--- 1441,1447 ----
  	pqsignal(SIGHUP, SIG_IGN);
  	pqsignal(SIGINT, SIG_IGN);
  	pqsignal(SIGTERM, SIG_IGN);
! 	pqsignal(SIGQUIT, pgstat_exit);
  	pqsignal(SIGALRM, SIG_IGN);
  	pqsignal(SIGPIPE, SIG_IGN);
  	pqsignal(SIGUSR1, SIG_IGN);
***************
*** 1943,1948 ****
--- 1939,1954 ----
  	 * 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
+ 	 */
+ #ifdef WIN32
+ 	if (pgStatCollectorPid > 0)
+ 		kill(pgStatCollectorPid, SIGQUIT);
+ #endif
  	exit(0);
  }
  
Index: backend/postmaster/postmaster.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/postmaster/postmaster.c,v
retrieving revision 1.437
diff -c -r1.437 postmaster.c
*** backend/postmaster/postmaster.c	9 Nov 2004 13:01:26 -0000	1.437
--- backend/postmaster/postmaster.c	12 Nov 2004 20:46:36 -0000
***************
*** 275,281 ****
  #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);
--- 275,280 ----
***************
*** 292,298 ****
--- 291,302 ----
  static pid_t internal_forkexec(int argc, char *argv[], Port *port);
  
  static void read_backend_variables(char *filename, Port *port);
+ #ifndef WIN32
  static bool write_backend_variables(char *filename, Port *port);
+ #else
+ static bool write_backend_variables(char *filename, Port *port, HANDLE childProcess, pid_t childPid);
+ #endif
+ static void get_backend_variable_filename(char *filename);
  
  static void ShmemBackendArrayAdd(Backend *bn);
  static void ShmemBackendArrayRemove(pid_t pid);
***************
*** 338,343 ****
--- 341,351 ----
  		}
  	}

+ #ifdef WIN32
+ 		/* Start our win32 signal implementation */
+ 		pgwin32_signal_initialize();
+ #endif
+
  	/*
  	 * for security, no dir or file created can be group or other
  	 * accessible
***************
*** 2820,2830 ****
--- 2828,2848 ----
  	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)
  {
  	pid_t		pid;
  	char		tmpfilename[MAXPGPATH];
+
+ 	get_backend_variable_filename(tmpfilename);

  	if (!write_backend_variables(tmpfilename, port))
  		return -1;				/* log made by write_backend_variables */
***************
*** 2838,2846 ****
  	/* 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)
  	{
--- 2856,2861 ----
***************
*** 2853,2864 ****
  			exit(1);
  		}
  	}
- #endif

  	return pid;					/* Parent returns pid, or -1 on fork
  								 * failure */
  }

  /*
   * 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
--- 2868,3013 ----
  			exit(1);
  		}
  	}

  	return pid;					/* Parent returns pid, or -1 on fork
  								 * failure */
  }

+ #else
+ /*
+  * 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;
+ 	char		tmpfilename[MAXPGPATH];
+
+ 	/* 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);
+
+ 	/* Get the name of the parameter file, to put on the commandline */
+ 	get_backend_variable_filename(tmpfilename);
+
+ 	/* Insert temp file name after -fork argument */
+ 	argv[2] = tmpfilename;
+ 
+ 	/* 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 (%d): %m", (int) GetLastError());
+ 		return -1;
+ 	}
+ 
+ 	if (!write_backend_variables(tmpfilename, port, pi.hProcess, pi.dwProcessId))
+ 	{
+ 		/* log made by write_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: %i",
+ 									 (int) GetLastError())));
+ 		CloseHandle(pi.hProcess);
+ 		CloseHandle(pi.hThread);
+ 		return -1;				/* log made by write_backend_variables */
+ 	}
+ 	
+ 	/* 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: %i",
+ 									 (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: %i",
+ 								 (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: %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;
+ }
+ 
+ #endif /* win32 implementation of internal_forkexec */
+ 
+ 
  /*
   * 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
***************
*** 2880,2885 ****
--- 3029,3046 ----
  
  	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;
***************
*** 2894,2902 ****
  	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_nondefault_variables();
  
  	/* Run backend or appropriate child */
--- 3055,3061 ----
  	if (argc < 3)
  		elog(FATAL, "invalid subpostmaster invocation");
  
! 	/* Read in remaining GUC variables */
  	read_nondefault_variables();
  
  	/* Run backend or appropriate child */
***************
*** 3330,3353 ****
  extern LWLock *LWLockArray;
  extern slock_t *ProcStructLock;
  extern int	pgStatSock;

- #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)

! static bool
! write_backend_variables(char *filename, Port *port)
  {
  	static unsigned long tmpBackendFileNum = 0;
- 	FILE	   *fp;
- 	char		str_buf[MAXPGPATH];

- 	/* 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);

  	/* Open file */
  	fp = AllocateFile(filename, PG_BINARY_W);
--- 3489,3575 ----
  extern LWLock *LWLockArray;
  extern slock_t *ProcStructLock;
  extern int	pgStatSock;
+ extern int pgStatPipe[2];
  
  
! /* 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
! 
! /*
!  * 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;
! 	int debug_flag;
! 	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;
!
! #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
!
! /* Calculate name for temp file in caller's buffer */
! static void get_backend_variable_filename(char *filename)
  {
  	static unsigned long tmpBackendFileNum = 0;

  	Assert(DataDir);
  	snprintf(filename, MAXPGPATH, "%s/%s/%s.backend_var.%d.%lu",
  			 DataDir, PG_TEMP_FILES_DIR, PG_TEMP_FILE_PREFIX,
  			 MyProcPid, ++tmpBackendFileNum);
+ }
+
+ #ifndef WIN32
+ static bool
+ write_backend_variables(char *filename, Port *port)
+ #else
+ static bool
+ write_backend_variables(char *filename, Port *port, HANDLE childProcess, pid_t childPid)
+ #endif
+ {
+ 	FILE	   *fp;
+ 	BackendParameters param;

  	/* Open file */
  	fp = AllocateFile(filename, PG_BINARY_W);
***************
*** 3371,3427 ****
  	}

  	/* 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);
  
! 	/*
! 	 * XXX FIXME later: writing these strings as MAXPGPATH bytes always is
! 	 * probably a waste of resources
! 	 */
! 
! 	StrNCpy(str_buf, DataDir, MAXPGPATH);
! 	write_array_var(str_buf, fp);
! 
! 	write_array_var(ListenSocket, fp);
! 
! 	write_var(MyCancelKey, fp);
  
- 	write_var(UsedShmemSegID, fp);
- 	write_var(UsedShmemSegAddr, fp);
- 
- 	write_var(ShmemLock, fp);
- 	write_var(ShmemIndexLock, fp);
- 	write_var(ShmemVariableCache, fp);
- 	write_var(ShmemIndexAlloc, fp);
- 	write_var(ShmemBackendArray, fp);
- 
- 	write_var(LWLockArray, fp);
- 	write_var(ProcStructLock, fp);
- 	write_var(pgStatSock, fp);
- 
- 	write_var(debug_flag, fp);
- 	write_var(PostmasterPid, fp);
  #ifdef WIN32
! 	write_var(PostmasterHandle, fp);
  #endif
  
! 	write_var(syslogPipe[0], fp);
! 	write_var(syslogPipe[1], fp);
  
! 	StrNCpy(str_buf, my_exec_path, MAXPGPATH);
! 	write_array_var(str_buf, fp);
  
! 	write_array_var(ExtraOptions, fp);
  
! 	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);
  
  	/* Release file */
  	if (FreeFile(fp))
--- 3593,3643 ----
  	}
  
  	/* Write vars */
! 	memcpy(&param.port, port, sizeof(Port));
! 	write_inheritable_socket(&param.portsocket, port->sock, childPid);
! 	
! 	StrNCpy(param.DataDir, DataDir, MAXPGPATH);
! 	
! 	memcpy(&param.ListenSocket, &ListenSocket, sizeof(ListenSocket));
! 	
! 	param.MyCancelKey = MyCancelKey;
! 
! 	param.UsedShmemSegID = UsedShmemSegID;
! 	param.UsedShmemSegAddr = UsedShmemSegAddr;
! 
! 	param.ShmemLock = ShmemLock;
! 	param.ShmemIndexLock = ShmemIndexLock;
! 	param.ShmemVariableCache = ShmemVariableCache;
! 	param.ShmemIndexAlloc = ShmemIndexAlloc;
! 	param.ShmemBackendArray = ShmemBackendArray;
! 
! 	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);
  
! 	param.debug_flag = debug_flag;
! 	param.PostmasterPid = PostmasterPid;
  
  #ifdef WIN32
! 	param.PostmasterHandle = PostmasterHandle;
! 	write_duplicated_handle(&param.initial_signal_pipe, pgwin32_create_signal_listener(childPid), childProcess);
  #endif
  
! 	memcpy(&param.syslogPipe, &syslogPipe, sizeof(syslogPipe));
! 	
! 	StrNCpy(param.my_exec_path, my_exec_path, MAXPGPATH);
  
! 	StrNCpy(param.ExtraOptions, ExtraOptions, MAXPGPATH);
  
! 	StrNCpy(param.lc_collate, setlocale(LC_COLLATE, NULL), MAXPGPATH);
! 	StrNCpy(param.lc_ctype, setlocale(LC_CTYPE, NULL), MAXPGPATH);
  
! 	if (fwrite(&param, sizeof(param), 1, fp) != 1)
! 		ereport(ERROR,
! 				(errcode_for_file_access(),
! 				 errmsg("could not write to file \"%s\": %m", filename)));
  
  	/* Release file */
  	if (FreeFile(fp))
***************
*** 3435,3508 ****
  	return true;
  }
  
  static void
  read_backend_variables(char *filename, Port *port)
  {
  	FILE	   *fp;
! 	char		str_buf[MAXPGPATH];
  
  	/* Open file */
  	fp = AllocateFile(filename, PG_BINARY_R);
  	if (!fp)
! 		ereport(FATAL,
! 				(errcode_for_file_access(),
! 		  errmsg("could not read from backend variables file \"%s\": %m",
! 				 filename)));
  
  	/* 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);
! 
! 	read_array_var(str_buf, fp);
! 	SetDataDir(str_buf);
! 
! 	read_array_var(ListenSocket, fp);
! 
! 	read_var(MyCancelKey, fp);
! 
! 	read_var(UsedShmemSegID, fp);
! 	read_var(UsedShmemSegAddr, fp);
! 
! 	read_var(ShmemLock, fp);
! 	read_var(ShmemIndexLock, fp);
! 	read_var(ShmemVariableCache, fp);
! 	read_var(ShmemIndexAlloc, fp);
! 	read_var(ShmemBackendArray, fp);
! 
! 	read_var(LWLockArray, fp);
! 	read_var(ProcStructLock, fp);
! 	read_var(pgStatSock, fp);
  
- 	read_var(debug_flag, fp);
- 	read_var(PostmasterPid, fp);
  #ifdef WIN32
! 	read_var(PostmasterHandle, fp);
  #endif
  
! 	read_var(syslogPipe[0], fp);
! 	read_var(syslogPipe[1], fp);
  
! 	read_array_var(str_buf, fp);
! 	StrNCpy(my_exec_path, str_buf, MAXPGPATH);
  
! 	read_array_var(ExtraOptions, fp);
  
! 	read_array_var(str_buf, fp);
! 	setlocale(LC_COLLATE, str_buf);
! 	read_array_var(str_buf, fp);
! 	setlocale(LC_CTYPE, str_buf);
  
  	/* Release file */
  	FreeFile(fp);
  	if (unlink(filename) != 0)
! 		ereport(WARNING,
! 				(errcode_for_file_access(),
! 				 errmsg("could not remove file \"%s\": %m", filename)));
  }
  
  
--- 3651,3811 ----
  	return true;
  }
  
+ 
+ #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: %i",
+ 								 (int) GetLastError())));
+ 
+ 	*dest = hChild;
+ }
+ 
+ /*
+  * 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 %i for use in backend: %i\n",
+ 							src, WSAGetLastError())));
+ 	}
+ }
+ 
+ /*
+  * Read a duplicate socket structure back, and get the socket descriptor.
+  */
+ static void
+ read_inheritable_socket(SOCKET *dest, InheritableSocket *src)
+ {
+ 	SOCKET s;
+ 
+ 	if (src->origsocket == -1  || src->origsocket == 0)
+ 	{
+ 		/* 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: %i\n",
+ 						 WSAGetLastError());
+ 			exit(1);
+ 		}
+ 		*dest = s;
+ 		/* 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)
  {
  	FILE	   *fp;
! 	BackendParameters param;
  
  	/* Open file */
  	fp = AllocateFile(filename, PG_BINARY_R);
  	if (!fp)
! 	{
! 		write_stderr("could not read from backend variables file \"%s\": %i",
! 					 filename, errno);
! 		exit(1);
! 	}
!
! 	if (fread(&param, sizeof(param), 1, fp) != 1)
! 	{
! 		write_stderr("could not read from backend variables file \"%s\": %i",
! 					 filename, errno);
! 		exit(1);
! 	}

  	/* Read vars */
! 	memcpy(port, &param.port, sizeof(Port));
! 	read_inheritable_socket(&port->sock, &param.portsocket);
!
! 	SetDataDir(param.DataDir);
!
! 	memcpy(&ListenSocket, &param.ListenSocket, sizeof(ListenSocket));
!
! 	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);
!
! 	debug_flag = param.debug_flag;
! 	PostmasterPid = param.PostmasterPid;

  #ifdef WIN32
! 	PostmasterHandle = param.PostmasterHandle;
! 	pgwin32_initial_signal_pipe = param.initial_signal_pipe;
  #endif

! 	memcpy(&syslogPipe, &param.syslogPipe, sizeof(syslogPipe));

! 	StrNCpy(my_exec_path, param.my_exec_path, MAXPGPATH);

! 	StrNCpy(ExtraOptions, param.ExtraOptions, MAXPGPATH);

! 	setlocale(LC_COLLATE, param.lc_collate);
! 	setlocale(LC_CTYPE, param.lc_ctype);

  	/* Release file */
  	FreeFile(fp);
  	if (unlink(filename) != 0)
! 	{
! 		write_stderr("could not remove file \"%s\": %i", filename, errno);
! 		exit(1);
! 	}
  }


***************
*** 3565,3638 ****

  #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)
--- 3868,3873 ----
***************
*** 3735,3741 ****
  					 */
  					ereport(FATAL,
  							(errmsg_internal("failed to get exit code for child %lu",
! 										   win32_childPIDArray[index])));
  				}
  				*exitstatus = (int) exitCode;
  				return win32_childPIDArray[index];
--- 3970,3976 ----
  					 */
  					ereport(FATAL,
  							(errmsg_internal("failed to get exit code for child %lu",
! 											 (DWORD)win32_childPIDArray[index])));
  				}
  				*exitstatus = (int) exitCode;
  				return win32_childPIDArray[index];
Index: include/port/win32.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/port/win32.h,v
retrieving revision 1.39
diff -c -r1.39 win32.h
*** include/port/win32.h	6 Oct 2004 17:47:53 -0000	1.39
--- include/port/win32.h	2 Nov 2004 18:53:52 -0000
***************
*** 106,111 ****
--- 106,113 ----
  /* In backend/port/win32/signal.c */
  void		pgwin32_signal_initialize(void);
  extern DLLIMPORT HANDLE pgwin32_signal_event;
+ extern HANDLE pgwin32_initial_signal_pipe;
+ HANDLE      pgwin32_create_signal_listener(pid_t pid);
  void		pgwin32_dispatch_queued_signals(void);
  void		pg_queue_signal(int signum);

