From 272d7379224e7525ad6a16d9cc2963edda4bb05c Mon Sep 17 00:00:00 2001
From: Dan Egnor <egnor@ofb.net>
Date: Fri, 18 Jul 2003 14:46:22 +0000
Subject: [PATCH] More fixes from Cederqvist

---
 adns.c       |   8 ++
 configure.ac |   2 +-
 oop.h        |   4 +
 read.c       |   1 +
 sys.c        | 221 +++++++++++++++++++++++++++++----------------------
 test-oop.c   |   6 +-
 6 files changed, 145 insertions(+), 97 deletions(-)

diff --git a/adns.c b/adns.c
index 50d1c37..f3ae4b3 100644
--- a/adns.c
+++ b/adns.c
@@ -12,6 +12,14 @@
 
 #include <assert.h>
 
+#ifdef HAVE_STRING_H
+#include <string.h>   /* Needed on NetBSD1.1/SPARC due to bzero/FD_ZERO. */
+#endif
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>  /* Needed on AIX 4.2 due to bzero/FD_ZERO. */
+#endif
+
 struct oop_adapter_adns {
 	oop_source *source;
 	oop_adapter_select *select;
diff --git a/configure.ac b/configure.ac
index b993492..fe624f2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -25,7 +25,7 @@ case "$host" in
     ;;
 esac
 
-AC_CHECK_HEADERS(poll.h sys/select.h sys/socket.h)
+AC_CHECK_HEADERS(poll.h sys/select.h sys/socket.h string.h strings.h)
 
 AC_CHECK_LIB(adns,adns_init,[
   ADNS_LIBS="-ladns"
diff --git a/oop.h b/oop.h
index c940963..d5d82ac 100644
--- a/oop.h
+++ b/oop.h
@@ -75,6 +75,10 @@ oop_source_sys *oop_sys_new(void);
    3 -- an error occurs; will return OOP_ERROR (check errno). */
 void *oop_sys_run(oop_source_sys *); 
 
+/* Process all pending events and return immediately.
+   Return values are the same as for oop_sys_run(). */
+void *oop_sys_run_once(oop_source_sys *);
+
 /* Delete a system event source.  No callbacks may be registered. */
 void oop_sys_delete(oop_source_sys *);
 
diff --git a/read.c b/read.c
index d50fb5e..6a1cc29 100644
--- a/read.c
+++ b/read.c
@@ -12,6 +12,7 @@
 #include <assert.h>
 #include <limits.h>
 
+#undef MIN /* for systems that define it */
 #define MIN(a,b) ((a)<(b) ? (a) : (b))
 
 static void *on_time(oop_source*, struct timeval, void*);
diff --git a/sys.c b/sys.c
index b3cf6b1..65e4143 100644
--- a/sys.c
+++ b/sys.c
@@ -24,6 +24,14 @@
 #include <sys/socket.h>
 #endif
 
+#ifdef HAVE_STRING_H
+#include <string.h>   /* Needed on NetBSD1.1/SPARC due to bzero/FD_ZERO. */
+#endif
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>  /* Needed on AIX 4.2 due to bzero/FD_ZERO. */
+#endif
+
 #define MAGIC 0x9643
 
 struct sys_time {
@@ -118,6 +126,8 @@ static void sys_on_time(oop_source *source,struct timeval tv,
 	oop_source_sys *sys = verify_source(source);
 	struct sys_time **p = &sys->time_queue;
 	struct sys_time *time = oop_malloc(sizeof(struct sys_time));
+	assert(tv.tv_usec >= 0 && "tv_usec must be positive");
+	assert(tv.tv_usec < 1000000 && "tv_usec measures microseconds");
 	assert(NULL != f && "callback must be non-NULL");
 	if (NULL == time) return; /* ugh */
 	time->tv = tv;
@@ -283,121 +293,142 @@ static void *sys_time_run(oop_source_sys *sys) {
 }
 
 void *oop_sys_run(oop_source_sys *sys) {
-	void * volatile ret = OOP_CONTINUE;
+	void *ret = OOP_CONTINUE;
 	assert(!sys->in_run && "oop_sys_run is not reentrant");
-	sys->in_run = 1;
+	while (0 != sys->num_events && OOP_CONTINUE == ret)
+		ret = oop_sys_run_once(sys);
+	return ret;
+}
 
-	while (0 != sys->num_events && OOP_CONTINUE == ret) {
-		struct timeval * volatile ptv = NULL;
-		struct timeval tv;
-		fd_set rfd,wfd,xfd;
-		int i,rv;
+void *oop_sys_run_once(oop_source_sys *sys) {
+	void * volatile ret = OOP_CONTINUE;
+	struct timeval * volatile ptv = NULL;
+	struct timeval tv;
+	fd_set rfd,wfd,xfd;
+	int i,rv;
 
-		if (NULL != sys->time_run) {
-			/* interrupted, restart */
-			ptv = &tv;
-			tv.tv_sec = 0;
-			tv.tv_usec = 0;
-		} else if (NULL != sys->time_queue) {
-			ptv = &tv;
-			gettimeofday(ptv,NULL);
-			if (sys->time_queue->tv.tv_usec < tv.tv_usec) {
-				tv.tv_usec -= 1000000;
-				tv.tv_sec ++;
-			}
-			tv.tv_sec = sys->time_queue->tv.tv_sec - tv.tv_sec;
-			tv.tv_usec = sys->time_queue->tv.tv_usec - tv.tv_usec;
-			if (tv.tv_sec < 0) {
-				tv.tv_sec = 0;
-				tv.tv_usec = 0;
-			}
-		}
+	assert(!sys->in_run && "oop_sys_run_once is not reentrant");
+	sys->in_run = 1;
 
-		if (!sys->sig_active) sys->do_jmp = !sigsetjmp(sys->env,1);
-		if (sys->sig_active) {
-			/* Still perform select(), but don't block. */
-			ptv = &tv;
+	if (NULL != sys->time_run) {
+		/* interrupted, restart */
+		ptv = &tv;
+		tv.tv_sec = 0;
+		tv.tv_usec = 0;
+	} else if (NULL != sys->time_queue) {
+		ptv = &tv;
+		gettimeofday(ptv,NULL);
+		if (sys->time_queue->tv.tv_usec < tv.tv_usec) {
+			tv.tv_usec -= 1000000;
+			tv.tv_sec ++;
+		}
+		tv.tv_sec = sys->time_queue->tv.tv_sec - tv.tv_sec;
+		tv.tv_usec = sys->time_queue->tv.tv_usec - tv.tv_usec;
+		if (tv.tv_sec < 0) {
 			tv.tv_sec = 0;
 			tv.tv_usec = 0;
 		}
+	}
 
-		FD_ZERO(&rfd);
-		FD_ZERO(&wfd);
-		FD_ZERO(&xfd);
-		for (i = 0; i < sys->num_files; ++i) {
-			if (NULL != sys->files[i][OOP_READ].f) FD_SET(i,&rfd);
-			if (NULL != sys->files[i][OOP_WRITE].f) FD_SET(i,&wfd);
-			if (NULL != sys->files[i][OOP_EXCEPTION].f) FD_SET(i,&xfd);
-		}
+	if (!sys->sig_active) sys->do_jmp = !sigsetjmp(sys->env,1);
+	if (sys->sig_active) {
+		/* Still perform select(), but don't block. */
+		ptv = &tv;
+		tv.tv_sec = 0;
+		tv.tv_usec = 0;
+	}
 
-		do
-			rv = select(sys->num_files,&rfd,&wfd,&xfd,ptv);
-		while (0 > rv && EINTR == errno);
+	/* select() fails on FreeBSD with EINVAL if tv_sec > 1000000000.
+           The manual specifies the error code but not the limit.  We limit
+	   the select() timeout to one hour for portability. */
+	if (NULL != ptv && ptv->tv_sec >= 3600) ptv->tv_sec = 3599;
+	assert(NULL == ptv 
+	   || (ptv->tv_sec >= 0 && ptv->tv_sec < 3600
+           &&  ptv->tv_usec >= 0 && ptv->tv_usec < 1000000));
+
+	FD_ZERO(&rfd);
+	FD_ZERO(&wfd);
+	FD_ZERO(&xfd);
+	for (i = 0; i < sys->num_files; ++i) {
+		if (NULL != sys->files[i][OOP_READ].f) FD_SET(i,&rfd);
+		if (NULL != sys->files[i][OOP_WRITE].f) FD_SET(i,&wfd);
+		if (NULL != sys->files[i][OOP_EXCEPTION].f) FD_SET(i,&xfd);
+	}
 
-		sys->do_jmp = 0;
+	do
+		rv = select(sys->num_files,&rfd,&wfd,&xfd,ptv);
+	while (0 > rv && EINTR == errno);
 
-		if (0 > rv) { /* Error in select(). */
-			ret = OOP_ERROR;
-			break; 
-		}
+	sys->do_jmp = 0;
 
-		if (sys->sig_active) {
-			sys->sig_active = 0;
-			for (i = 0; OOP_CONTINUE == ret && i < OOP_NUM_SIGNALS; ++i) {
-				if (sys->sig[i].active) {
-					sys->sig[i].active = 0;
-					sys->sig[i].ptr = sys->sig[i].list;
-				}
-				while (OOP_CONTINUE == ret && NULL != sys->sig[i].ptr) {
-					struct sys_signal_handler *h;
-					h = sys->sig[i].ptr;
-					sys->sig[i].ptr = h->next;
-					ret = h->f(&sys->oop,i,h->v);
-				}
+	if (0 > rv) { /* Error in select(). */
+		ret = OOP_ERROR;
+		goto done; 
+	}
+
+	if (sys->sig_active) {
+		sys->sig_active = 0;
+		for (i = 0; OOP_CONTINUE == ret && i < OOP_NUM_SIGNALS; ++i) {
+			if (sys->sig[i].active) {
+				sys->sig[i].active = 0;
+				sys->sig[i].ptr = sys->sig[i].list;
 			}
-			if (OOP_CONTINUE != ret) {
-				sys->sig_active = 1; /* come back */
-				break;
+			while (OOP_CONTINUE == ret && NULL != sys->sig[i].ptr) {
+				struct sys_signal_handler *h;
+				h = sys->sig[i].ptr;
+				sys->sig[i].ptr = h->next;
+				ret = h->f(&sys->oop,i,h->v);
 			}
 		}
-
-		if (0 < rv) {
-			for (i = 0; OOP_CONTINUE == ret && i < sys->num_files; ++i)
-				if (FD_ISSET(i,&xfd) && NULL != sys->files[i][OOP_EXCEPTION].f)
-					ret = sys->files[i][OOP_EXCEPTION].f(&sys->oop,i,OOP_EXCEPTION,
-					                          sys->files[i][OOP_EXCEPTION].v);
-			for (i = 0; OOP_CONTINUE == ret && i < sys->num_files; ++i)
-				if (FD_ISSET(i,&wfd) && NULL != sys->files[i][OOP_WRITE].f)
-					ret = sys->files[i][OOP_WRITE].f(&sys->oop,i,OOP_WRITE,
-					                           sys->files[i][OOP_WRITE].v);
-			for (i = 0; OOP_CONTINUE == ret && i < sys->num_files; ++i)
-				if (FD_ISSET(i,&rfd) && NULL != sys->files[i][OOP_READ].f)
-					ret = sys->files[i][OOP_READ].f(&sys->oop,i,OOP_READ,
-					                          sys->files[i][OOP_READ].v);
-			if (OOP_CONTINUE != ret) break;
+		if (OOP_CONTINUE != ret) {
+			sys->sig_active = 1; /* come back */
+			goto done;
 		}
+	}
 
-		/* Catch any leftover timeout events. */
-		ret = sys_time_run(sys);
-		if (OOP_CONTINUE != ret) break;
-
-		if (NULL != sys->time_queue) {
-			struct sys_time *p,**pp = &sys->time_queue;
-			gettimeofday(&tv,NULL);
-			while (NULL != *pp 
-			   && (tv.tv_sec > (*pp)->tv.tv_sec
-			   || (tv.tv_sec == (*pp)->tv.tv_sec
-			   &&  tv.tv_usec >= (*pp)->tv.tv_usec)))
-				pp = &(*pp)->next;
-			p = *pp;
-			*pp = NULL;
-			sys->time_run = sys->time_queue;
-			sys->time_queue = p;
-		}
+	if (0 < rv) {
+		for (i = 0; OOP_CONTINUE == ret && i < sys->num_files; ++i)
+			if (FD_ISSET(i,&xfd) 
+			&&  NULL != sys->files[i][OOP_EXCEPTION].f)
+				ret = sys->files[i][OOP_EXCEPTION].f(
+					&sys->oop,i,OOP_EXCEPTION,
+					 sys->files[i][OOP_EXCEPTION].v);
+		for (i = 0; OOP_CONTINUE == ret && i < sys->num_files; ++i)
+			if (FD_ISSET(i,&wfd) 
+			&&  NULL != sys->files[i][OOP_WRITE].f)
+				ret = sys->files[i][OOP_WRITE].f(
+					&sys->oop,i,OOP_WRITE,
+					 sys->files[i][OOP_WRITE].v);
+		for (i = 0; OOP_CONTINUE == ret && i < sys->num_files; ++i)
+			if (FD_ISSET(i,&rfd) 
+			&&  NULL != sys->files[i][OOP_READ].f)
+				ret = sys->files[i][OOP_READ].f(
+					&sys->oop,i,OOP_READ,
+					 sys->files[i][OOP_READ].v);
+		if (OOP_CONTINUE != ret) goto done;
+	}
 
-		ret = sys_time_run(sys);
+	/* Catch any leftover timeout events. */
+	ret = sys_time_run(sys);
+	if (OOP_CONTINUE != ret) goto done;
+
+	if (NULL != sys->time_queue) {
+		struct sys_time *p,**pp = &sys->time_queue;
+		gettimeofday(&tv,NULL);
+		while (NULL != *pp 
+		   && (tv.tv_sec > (*pp)->tv.tv_sec
+		   || (tv.tv_sec == (*pp)->tv.tv_sec
+		   &&  tv.tv_usec >= (*pp)->tv.tv_usec)))
+			pp = &(*pp)->next;
+		p = *pp;
+		*pp = NULL;
+		sys->time_run = sys->time_queue;
+		sys->time_queue = p;
 	}
 
+	ret = sys_time_run(sys);
+
+done:
 	sys->in_run = 0;
 	return ret;
 }
diff --git a/test-oop.c b/test-oop.c
index f9b522e..c909a91 100644
--- a/test-oop.c
+++ b/test-oop.c
@@ -542,8 +542,12 @@ static oop_source *create_source(const char *name) {
 
 static void run_source(const char *name) {
 	if (!strcmp(name,"sys")
-	||  !strcmp(name,"signal"))
+	||  !strcmp(name,"signal")) {
+		oop_sys_run_once(source_sys);
+		oop_sys_run_once(source_sys);
+		oop_sys_run_once(source_sys);
 		oop_sys_run(source_sys);
+	}
 
 #ifdef HAVE_GLIB
 	if (!strcmp(name,"glib"))
-- 
GitLab