CVS User Account cvsuser
Wed Jul 20 14:59:56 PDT 2005
Log Message:
-----------
Initial Win32 port, from Magnus Hagander, with minor tweaks by Dave Page. Needs service and eventlog code yet, but works nicely from the command line :-)

Changes:
* Added "override" to LDFLAGS in the Makefile. I am no makefile guru, so
I don't really know why :-) But it was there for CFLAGS, and without it,
the pthreads library simply wasn't added to the build command...

* For win32 only, added mandatory link to "wsock32" winsock functions,
required so we can access TCP/IP functions at all.

* #ifdef out the whole "watchdog process" for win32. Win32 does not have
signals, so we don't need a special process to catch and channel those.
And we expect the service control manager to deal with restarts as
required (when it comes).

* As a consequence of win32 not having signals, change exits to just do
exit() instead of sigterm:ing the own process. This includes modifying
slon_abort() and slon_restart() (_restart seems never to be used?)

* Import pgpipe implementation from postgresql backend, and change all
read/write to piperead/pipewrite - same as in the pg backend. This is
rquired because on win32 you can't "select()" on a pipe. The pgpipe
implementation uses TCP sockets instead.

* Remove the sched_shutdown() code per my previous mail. Not strictly a
part of the win32 work...

* Start and stop winsock as appropriate.

Modified Files:
--------------
    slony1-engine/src/slon:
        Makefile (r1.33 -> r1.34)
        cleanup_thread.c (r1.26 -> r1.27)
        local_listen.c (r1.31 -> r1.32)
        misc.c (r1.18 -> r1.19)
        misc.h (r1.6 -> r1.7)
        runtime_config.c (r1.24 -> r1.25)
        scheduler.c (r1.20 -> r1.21)
        slon.c (r1.52 -> r1.53)
        slon.h (r1.48 -> r1.49)

Added Files:
-----------
    slony1-engine/src/slon/port:
        pipe.c (r1.1)

-------------- next part --------------
Index: misc.h
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/slon/misc.h,v
retrieving revision 1.6
retrieving revision 1.7
diff -Lsrc/slon/misc.h -Lsrc/slon/misc.h -u -w -r1.6 -r1.7
--- src/slon/misc.h
+++ src/slon/misc.h
@@ -25,6 +25,17 @@
 extern int	slon_scanint64(char *str, int64 * result);
 #endif
 
+#ifdef WIN32
+/* Remove some defines that are imported from the postgresql headers, but
+ * that refer to backend porting functions. */
+#undef select
+#undef accept
+#undef connect
+#undef socket
+#undef recv
+#undef send
+#endif
+
 /*
  * Local Variables:
  *	tab-width: 4
Index: scheduler.c
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/slon/scheduler.c,v
retrieving revision 1.20
retrieving revision 1.21
diff -Lsrc/slon/scheduler.c -Lsrc/slon/scheduler.c -u -w -r1.20 -r1.21
--- src/slon/scheduler.c
+++ src/slon/scheduler.c
@@ -192,7 +192,7 @@
 	 * Give the scheduler thread a heads up, release the master lock and wait
 	 * for it to tell us that the event we're waiting for happened.
 	 */
-	if (write(sched_wakeuppipe[1], "x", 1) < 0)
+	if (pipewrite(sched_wakeuppipe[1], "x", 1) < 0)
 	{
 		perror("sched_wait_conn: write()");
 		exit(-1);
@@ -326,7 +326,7 @@
 	 */
 	if (num_wakeup > 0)
 	{
-		if (write(sched_wakeuppipe[1], "x", 1) < 0)
+		if (pipewrite(sched_wakeuppipe[1], "x", 1) < 0)
 		{
 			perror("sched_wait_conn: write()");
 			slon_abort();
@@ -517,7 +517,7 @@
 			char		buf    [1];
 
 			rc--;
-			if (read(sched_wakeuppipe[0], buf, 1) != 1)
+			if (piperead(sched_wakeuppipe[0], buf, 1) != 1)
 			{
 				perror("sched_mainloop: read()");
 				sched_status = SCHED_STATUS_ERROR;
@@ -638,60 +638,6 @@
 
 
 /*
- * ---------- sched_sighandler
- *
- * After starting up the sole purpose of the main thread (the original process)
- * is to respond to signals while waiting for the scheduler to finish. The
- * signal handler is here because it is actually sched_start_mainloop() that
- * arranges for the signal handling and sched_wait_mainloop() that enables
- * them. And the only one really interested in the signals is the scheduler
- * thread ... but that's doing select(2) mainly and we have to avoid race
- * conditions with signals. ----------
- */
-static void
-sched_shutdown()
-{
-	/*
-	 * Lock the master mutex and make sure that we are the main thread
-	 */
-	pthread_mutex_lock(&sched_master_lock);
-	if (!pthread_equal(pthread_self(), sched_main_thread))
-	{
-		slon_log(SLON_FATAL, "sched_sighandler: called in non-main thread\n");
-		slon_abort();
-	}
-
-	/*
-	 * Set the scheduling status to shutdown
-	 */
-	if (sched_status == SCHED_STATUS_OK)
-		sched_status = SCHED_STATUS_SHUTDOWN;
-
-	/*
-	 * Try to wakeup the scheduler thread by throwing a bait
-	 */
-	if (sched_wakeuppipe[1] < 0)
-	{
-		slon_log(SLON_ERROR, "sched_sighandler: sockpair already closed\n");
-		pthread_mutex_unlock(&sched_master_lock);
-		return;
-	}
-	if (write(sched_wakeuppipe[1], "x", 1) < 0)
-	{
-		perror("sched_sighandler: write()");
-		pthread_mutex_unlock(&sched_master_lock);
-		exit(-1);
-	}
-
-	/*
-	 * Unlock the master mutex
-	 */
-	pthread_mutex_unlock(&sched_master_lock);
-}
-
-
-
-/*
  * ---------- sched_add_fdset
  *
  * Add a file descriptor to one of the global scheduler sets and adjust
Index: slon.h
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/slon/slon.h,v
retrieving revision 1.48
retrieving revision 1.49
diff -Lsrc/slon/slon.h -Lsrc/slon/slon.h -u -w -r1.48 -r1.49
--- src/slon/slon.h
+++ src/slon/slon.h
@@ -324,8 +324,10 @@
  * ----------
  */
 extern pid_t slon_pid;
+#ifndef WIN32
 extern pid_t slon_ppid;
 extern pid_t slon_cpid;
+#endif
 extern char *rtcfg_cluster_name;
 extern char *rtcfg_namespace;
 extern char *rtcfg_conninfo;
@@ -344,6 +346,7 @@
  * Functions in slon.c
  * ----------
  */
+#ifndef WIN32
 #define slon_abort() \
 do { \
 	kill((slon_ppid == 0 ? slon_pid : slon_ppid), SIGTERM); \
@@ -353,6 +356,17 @@
 do { \
 	kill((slon_ppid == 0 ? slon_pid : slon_ppid), SIGHUP); \
 } while (0)
+#else /* WIN32 */
+/* On win32, we currently just bail out and let the service control manager
+ * deal with possible restarts */
+#define slon_abort() \
+WSACleanup(); \
+exit(1);
+#define slon_restart() \
+WSACleanup(); \
+exit(1);
+#endif
+
 extern void slon_exit(int code);
 
 extern int	slon_restart_request;
Index: runtime_config.c
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/slon/runtime_config.c,v
retrieving revision 1.24
retrieving revision 1.25
diff -Lsrc/slon/runtime_config.c -Lsrc/slon/runtime_config.c -u -w -r1.24 -r1.25
--- src/slon/runtime_config.c
+++ src/slon/runtime_config.c
@@ -33,8 +33,10 @@
  * ---------- Global data ----------
  */
 pid_t		slon_pid;
+#ifndef WIN32
 pid_t		slon_cpid;
 pid_t		slon_ppid;
+#endif
 char	   *rtcfg_cluster_name = NULL;
 char	   *rtcfg_namespace = NULL;
 char	   *rtcfg_conninfo = NULL;
Index: misc.c
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/slon/misc.c,v
retrieving revision 1.18
retrieving revision 1.19
diff -Lsrc/slon/misc.c -Lsrc/slon/misc.c -u -w -r1.18 -r1.19
--- src/slon/misc.c
+++ src/slon/misc.c
@@ -24,7 +24,9 @@
 #include <sys/time.h>
 #include <sys/types.h>
 
+#ifndef WIN32
 #include <syslog.h>
+#endif
 #include <stdarg.h>
 
 #include "libpq-fe.h"
Index: local_listen.c
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/slon/local_listen.c,v
retrieving revision 1.31
retrieving revision 1.32
diff -Lsrc/slon/local_listen.c -Lsrc/slon/local_listen.c -u -w -r1.31 -r1.32
--- src/slon/local_listen.c
+++ src/slon/local_listen.c
@@ -160,7 +160,13 @@
 			slon_log(SLON_INFO,
 					 "localListenThread: got restart notification - "
 					 "signal scheduler\n");
+#ifndef WIN32
 			kill(getppid(), SIGHUP);
+#else
+			/* XXX */
+			/* Win32 defer to service manager to restart for now */
+			slon_abort();
+#endif
 		}
 
 		/*
Index: cleanup_thread.c
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/slon/cleanup_thread.c,v
retrieving revision 1.26
retrieving revision 1.27
diff -Lsrc/slon/cleanup_thread.c -Lsrc/slon/cleanup_thread.c -u -w -r1.26 -r1.27
--- src/slon/cleanup_thread.c
+++ src/slon/cleanup_thread.c
@@ -91,8 +91,12 @@
 	 */
 	if ((conn = slon_connectdb(rtcfg_conninfo, "local_cleanup")) == NULL)
 	{
+#ifndef WIN32
 		kill(getpid(), SIGTERM);
 		pthread_exit(NULL);
+#else
+		exit(0);
+#endif
 		/* slon_abort(); */
 	}
 	dbconn = conn->dbconn;
Index: slon.c
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/slon/slon.c,v
retrieving revision 1.52
retrieving revision 1.53
diff -Lsrc/slon/slon.c -Lsrc/slon/slon.c -u -w -r1.52 -r1.53
--- src/slon/slon.c
+++ src/slon/slon.c
@@ -24,16 +24,23 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 
+#ifdef WIN32
+#include <winsock.h>
+#endif
+
 #include "libpq-fe.h"
 #include "c.h"
 
 #include "slon.h"
 #include "confoptions.h"
 
+
 /*
  * ---------- Global data ----------
  */
+#ifndef WIN32
 int			watchdog_pipe[2];
+#endif
 int			sched_wakeuppipe[2];
 
 pthread_mutex_t slon_wait_listen_lock = PTHREAD_MUTEX_INITIALIZER;
@@ -53,9 +60,11 @@
 static pthread_t main_thread;
 static char *const *main_argv;
 
+#ifndef WIN32
 static void sighandler(int signo);
 static void main_sigalrmhandler(int signo);
 static void slon_kill_child(void);
+#endif
 
 int			slon_log_level;
 char	   *pid_file;
@@ -83,7 +92,12 @@
 	extern int	optind;
 	extern char *optarg;
 
-#ifndef CYGWIN
+#ifdef WIN32
+    WSADATA wsaData;
+    int err;
+#endif
+
+#if !defined(CYGWIN) && !defined(WIN32)
 	struct sigaction act;
 #endif
 	InitializeConfOptions();
@@ -155,8 +169,10 @@
 	 * identifier
 	 */
 	slon_pid = getpid();
+#ifndef WIN32
 	slon_cpid = 0;
 	slon_ppid = 0;
+#endif
 	main_argv = argv;
 
 	if ((char *)argv[optind])
@@ -212,6 +228,16 @@
 		return 1;
 	}
 
+#ifdef WIN32
+    /* 
+     * Startup the network subsystem, in case our libpq doesn't
+     */
+    err = WSAStartup(MAKEWORD(1, 1), &wsaData);
+    if (err != 0) {
+		slon_log(SLON_FATAL, "main: Cannot start the network subsystem - %d\n", err);
+		slon_exit(-1);
+    }
+#endif
 
 	/*
 	 * Connect to the local database to read the initial configuration
@@ -268,17 +294,23 @@
 	 * Pipes to be used as communication devices between the parent (watchdog)
 	 * and child (worker) processes.
 	 */
-	if (pipe(watchdog_pipe) < 0)
+#ifndef WIN32
+	if (pgpipe(watchdog_pipe) < 0)
 	{
 		slon_log(SLON_FATAL, "slon: parent pipe create failed -(%d) %s\n", errno,strerror(errno));
 		slon_exit(-1);
 	}
-	if (pipe(sched_wakeuppipe) < 0)
+#endif
+	if (pgpipe(sched_wakeuppipe) < 0)
 	{
 		slon_log(SLON_FATAL, "slon: sched_wakeuppipe create failed -(%d) %s\n", errno,strerror(errno));
 		slon_exit(-1);
 	}
 
+	/* There is no watchdog process on win32. We delegate restarting and
+	 * other such tasks to the Service Control Manager. And win32 doesn't
+	 * support signals, so we don't need to catch them... */
+#ifndef WIN32
 	/*
 	 * Fork here to allow parent process to trap signals and child process to 
 	 * handle real processing work creating a watchdog and worker process
@@ -290,11 +322,15 @@
 		slon_exit(-1);
 	}
 	else if (slon_cpid == 0) /* child */
+#endif /* WIN32 */
 	{
 		slon_pid = getpid();
+#ifndef WIN32
 		slon_ppid = getppid();
+#endif
 
 		slon_log(SLON_DEBUG2, "main: main process started\n");
+#ifndef WIN32
 		/*
 		 * Wait for the parent process to initialize
 		 */
@@ -339,6 +375,7 @@
 		}
 
 		slon_log(SLON_DEBUG2, "main: end signal handler setup\n");
+#endif
 
 		/*
 		 * Start the event scheduling system
@@ -619,13 +656,17 @@
 		 * Wait for all remote threads to finish
 		 */
 		main_thread = pthread_self();
+#ifndef WIN32 /* XXX WIN32 no sigalarm, how fix? XXX */
 		signal(SIGALRM, main_sigalrmhandler);
 		alarm(20);
+#endif
 
 		slon_log(SLON_DEBUG2, "main: wait for remote threads\n");
 		rtcfg_joinAllRemoteThreads();
 
+#ifndef WIN32 /* XXX WIN32 XXX */
 		alarm(0);
+#endif
 
 		/*
 		 * Wait for the local threads to finish
@@ -651,6 +692,7 @@
 		/*
 		 * Tell parent that worker is done
 		 */
+#ifndef WIN32
 		slon_log(SLON_DEBUG2, "main: notify parent that worker is done\n");
 
 		if (write(watchdog_pipe[1], "c", 1) != 1)
@@ -658,11 +700,13 @@
 			slon_log(SLON_FATAL, "main: write to watchdog pipe failed -(%d) %s\n", errno,strerror(errno));
 			slon_exit(-1);
 		}
+#endif
 
 		slon_log(SLON_DEBUG1, "main: done\n");
 
 		exit(0);
 	}
+#ifndef WIN32 /* Again, no watchdog process on WIN32 */
 	else /* parent */
 	{
 		slon_log(SLON_DEBUG2, "slon: watchdog process started\n");
@@ -733,9 +777,11 @@
 		 */
 		slon_exit(0);
 	}
+#endif /* WIN32 */
 }
 
 
+#ifndef WIN32
 static void
 main_sigalrmhandler(int signo)
 {
@@ -814,7 +860,7 @@
 		slon_exit(-1);
 	}
 	
-	if (write(sched_wakeuppipe[1], "p", 1) != 1)
+	if (pipewrite(sched_wakeuppipe[1], "p", 1) != 1)
 	{
 		slon_log(SLON_FATAL, "main: write to worker pipe failed -(%d) %s\n", errno,strerror(errno));
 		kill(slon_cpid,SIGKILL);
@@ -852,11 +898,19 @@
 
 	slon_log(SLON_DEBUG2, "slon: worker process shutdown ok\n");
 }
+#endif
 
 void
 slon_exit(int code)
 {
+#ifdef WIN32
+    /* Cleanup winsock */
+    WSACleanup();
+    
+	if (pid_file)
+#else
 	if (slon_ppid == 0 && pid_file)
+#endif
 	{
 		slon_log(SLON_DEBUG2, "slon: remove pid file\n");
 		unlink(pid_file);
Index: Makefile
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/slon/Makefile,v
retrieving revision 1.33
retrieving revision 1.34
diff -Lsrc/slon/Makefile -Lsrc/slon/Makefile -u -w -r1.33 -r1.34
--- src/slon/Makefile
+++ src/slon/Makefile
@@ -13,8 +13,8 @@
 
 CC = $(PTHREAD_CC)
 
-override CFLAGS +=  $(PTHREAD_CFLAGS) -I$(slony_top_builddir) -I$(pgincludedir)
-LDFLAGS += $(rpath) $(PTHREAD_LIBS) -L$(pglibdir) -lpq
+override CFLAGS +=  $(PTHREAD_CFLAGS) -I$(slony_top_builddir) -I$(slony_top_builddir)/$(slony_subdir) -I$(pgincludedir)
+override LDFLAGS += $(rpath) $(PTHREAD_LIBS) -L$(pglibdir) -lpq
 
 
 PROG		= slon
@@ -45,8 +45,13 @@
 LDFLAGS+= ${NETSNMP_AGENTLIBS}
 endif
 
+ifeq ($(PORTNAME), win32)
+OBJS += port/pipe.o
+override LDFLAGS += -lwsock32
+endif
+
 
-DISTFILES = Makefile README $(wildcard *.c) $(wildcard *.h) $(wildcard *.l) $(wildcard *.y)
+DISTFILES = Makefile README $(wildcard *.c) $(wildcard port/*.c) $(wildcard *.h) $(wildcard *.l) $(wildcard *.y)
 
 ALL =				\
 	$(PROG)
--- /dev/null
+++ src/slon/port/pipe.c
@@ -0,0 +1,95 @@
+/*-------------------------------------------------------------------------
+ *
+ * pipe.c
+ *	  pipe()
+ *
+ * Copyright (c) 1996-2005, PostgreSQL Global Development Group
+ *
+ *	This is a replacement version of pipe for Win32 which allows
+ *	returned handles to be used in select(). Note that read/write calls
+ *	must be replaced with recv/send.
+ *
+ * $Id: pipe.c,v 1.1 2005/07/20 13:59:47 dpage Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+#include "misc.h"
+
+#ifdef WIN32
+int
+pgpipe(int handles[2])
+{
+	SOCKET		s;
+	struct sockaddr_in serv_addr;
+	int			len = sizeof(serv_addr);
+
+	handles[0] = handles[1] = INVALID_SOCKET;
+
+	if ((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
+	{
+		slon_log(SLON_ERROR, "pgpipe: failed to create socket: %ui", WSAGetLastError());
+		return -1;
+	}
+
+	memset((void *) &serv_addr, 0, sizeof(serv_addr));
+	serv_addr.sin_family = AF_INET;
+	serv_addr.sin_port = htons(0);
+	serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+	if (bind(s, (SOCKADDR *) & serv_addr, len) == SOCKET_ERROR)
+	{
+		slon_log(SLON_ERROR, "pgpipe: failed to bind: %ui", WSAGetLastError());
+		closesocket(s);
+		return -1;
+	}
+	if (listen(s, 1) == SOCKET_ERROR)
+	{
+		slon_log(SLON_ERROR, "pgpipe: failed to listen: %ui", WSAGetLastError());
+		closesocket(s);
+		return -1;
+	}
+	if (getsockname(s, (SOCKADDR *) & serv_addr, &len) == SOCKET_ERROR)
+	{
+		slon_log(SLON_ERROR, "pgpipe: failed to getsockname: %ui", WSAGetLastError());
+		closesocket(s);
+		return -1;
+	}
+	if ((handles[1] = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
+	{
+		slon_log(SLON_ERROR, "pgpipe: failed to create socket 2: %ui", WSAGetLastError());
+		closesocket(s);
+		return -1;
+	}
+
+	if (connect(handles[1], (SOCKADDR *) & serv_addr, len) == SOCKET_ERROR)
+	{
+		slon_log(SLON_ERROR, "pgpipe: filed to connect socket: %ui", WSAGetLastError());
+		closesocket(s);
+		return -1;
+	}
+	if ((handles[0] = accept(s, (SOCKADDR *) & serv_addr, &len)) == INVALID_SOCKET)
+	{
+		slon_log(SLON_ERROR, "pgpipe: failed to accept socket: %ui", WSAGetLastError());
+		closesocket(handles[1]);
+		handles[1] = INVALID_SOCKET;
+		closesocket(s);
+		return -1;
+	}
+	closesocket(s);
+	return 0;
+}
+
+
+int
+piperead(int s, char *buf, int len)
+{
+	int			ret = recv(s, buf, len, 0);
+
+	if (ret < 0 && WSAGetLastError() == WSAECONNRESET)
+		/* EOF on the pipe! (win32 socket based implementation) */
+		ret = 0;
+	return ret;
+}
+
+#endif


More information about the Slony1-commit mailing list