summaryrefslogtreecommitdiffstats
path: root/waitlib
diff options
context:
space:
mode:
Diffstat (limited to 'waitlib')
-rw-r--r--waitlib/.gitignore1
-rw-r--r--waitlib/Makefile.am18
-rw-r--r--waitlib/configure.in108
-rw-r--r--waitlib/confwait.c105
-rw-r--r--waitlib/testwait.c99
-rw-r--r--waitlib/testwait2.c9
-rw-r--r--waitlib/waitlib.c110
-rw-r--r--waitlib/waitlib.h90
-rw-r--r--waitlib/waitlib2.c114
9 files changed, 654 insertions, 0 deletions
diff --git a/waitlib/.gitignore b/waitlib/.gitignore
new file mode 100644
index 0000000..8d974d3
--- /dev/null
+++ b/waitlib/.gitignore
@@ -0,0 +1 @@
+/testwait
diff --git a/waitlib/Makefile.am b/waitlib/Makefile.am
new file mode 100644
index 0000000..c4871c1
--- /dev/null
+++ b/waitlib/Makefile.am
@@ -0,0 +1,18 @@
+#
+# Copyright 1998 - 1999 Double Precision, Inc. See COPYING for
+# distribution information.
+
+
+noinst_LIBRARIES=libwaitlib.a
+noinst_PROGRAMS=testwait
+
+EXTRA_DIST=confwait.c
+
+libwaitlib_a_SOURCES=waitlib.c waitlib.h waitlib2.c
+
+testwait_SOURCES=testwait.c testwait2.c
+testwait_DEPENDENCIES=libwaitlib.a
+testwait_LDADD=libwaitlib.a
+
+check-am:
+ ./testwait
diff --git a/waitlib/configure.in b/waitlib/configure.in
new file mode 100644
index 0000000..221696a
--- /dev/null
+++ b/waitlib/configure.in
@@ -0,0 +1,108 @@
+dnl Process this file with autoconf to produce a configure script.
+dnl
+dnl Copyright 1998 - 2002 Double Precision, Inc. See COPYING for
+dnl distribution information.
+
+AC_INIT(waitlib, 0.50, [courier-users@lists.sourceforge.net])
+
+>confdefs.h # Kill PACKAGE_ macros
+
+AC_CONFIG_SRCDIR(waitlib.c)
+AC_CONFIG_AUX_DIR(../..)
+AM_INIT_AUTOMAKE([foreign no-define])
+
+AM_CONFIG_HEADER(config.h)
+
+dnl Checks for programs.
+AC_PROG_AWK
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_RANLIB
+AC_PROG_CC
+
+dnl Checks for libraries.
+
+dnl Checks for header files.
+AC_HEADER_SYS_WAIT
+AC_CHECK_HEADERS(sys/wait.h unistd.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_TYPE_PID_T
+
+dnl Checks for library functions.
+AC_TYPE_SIGNAL
+AC_SYS_LARGEFILE
+
+AC_CHECK_FUNCS(wait wait3 sigblock sighold sigprocmask)
+
+AC_ARG_WITH(waitfunc, [--with-waitfunc=wait3 Use the wait3 system call
+--with-waitfunc-wait Use the wait system call],
+
+ waitfunc="$withval", waitfunc="")
+
+case $waitfunc in
+wait)
+ ;;
+wait3)
+ AC_DEFINE_UNQUOTED(USE_WAIT3, 1, [ Whether to use wait3() ])
+ ;;
+"")
+ AC_CACHE_CHECK([if wait function is broken],waitlib_cv_SYS_WAITBROKEN,
+
+ AC_TRY_RUN([
+#include "confdefs.h"
+#include "$srcdir/confwait.c"
+ ], waitlib_cv_SYS_WAITBROKEN=no,
+ waitlib_cv_SYS_WAITBROKEN=yes,
+ AC_MSG_ERROR(Must specify --with-waitfunc when cross-compiling)))
+
+ has_xsig=no;
+ if test "$ac_cv_func_sigblock" = "yes"
+ then
+ has_xsig=yes
+ fi
+ if test "$has_sighold" = "yes"
+ then
+ has_xsig=yes
+ fi
+
+ if test "$waitlib_cv_SYS_WAITBROKEN$has_xsig$ac_cv_func_wait3" = "yesyesyes"
+ then
+ AC_CACHE_CHECK([if wait3 function is broken],waitlib_cv_SYS_WAIT3BROKEN,
+ AC_TRY_RUN([
+#define USE_WAIT3 1
+#include "confdefs.h"
+#include "$srcdir/confwait.c"
+ ], waitlib_cv_SYS_WAIT3BROKEN=no,
+ waitlib_cv_SYS_WAIT3BROKEN=yes,
+ AC_MSG_ERROR(Must specify --with-waitfunc when cross-compiling)))
+ use_wait3=yes
+ if test $waitlib_cv_SYS_WAIT3BROKEN = yes
+ then
+ use_wait3=no
+ fi
+ else
+ use_wait3=no
+ fi
+
+ if test "$waitlib_cv_SYS_WAITBROKEN$use_wait3" = "yesno"
+ then
+ AC_MSG_ERROR([I give up -- neither wait nor wait3 works properly])
+ fi
+
+ if test "$use_wait3" = "yes"
+ then
+ AC_DEFINE_UNQUOTED(USE_WAIT3)
+ fi
+ ;;
+*)
+ AC_MSG_ERROR(Invalid --with-wait option.)
+ ;;
+esac
+
+if test x$GCC = xyes
+then
+ CFLAGS="-Wall $CFLAGS"
+fi
+
+AC_OUTPUT(Makefile)
diff --git a/waitlib/confwait.c b/waitlib/confwait.c
new file mode 100644
index 0000000..4ee8b60
--- /dev/null
+++ b/waitlib/confwait.c
@@ -0,0 +1,105 @@
+/*
+** Copyright 1998 - 1999 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#include <stdio.h>
+#include <signal.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <time.h>
+
+#define INCLUDED_FROM_CONFIGURE
+#include "waitlib.c"
+
+#define NUMPROCS 10
+
+static int numterminated=0;
+
+
+static void cntreaped(pid_t p, int n)
+{
+ if ( ++numterminated == NUMPROCS ) _exit(0);
+}
+
+static RETSIGTYPE childsig(int n)
+{
+ n=n;
+
+ wait_reap(cntreaped, childsig);
+
+#if RETSIGTYPE != void
+ return (0);
+#endif
+}
+
+int main()
+{
+int pipefd[2];
+int pipefd2[2];
+pid_t p;
+int i;
+time_t t;
+char c;
+
+ if (pipe(pipefd) || pipe(pipefd2))
+ {
+ perror("pipe");
+ exit(1);
+ }
+
+ signal(SIGCHLD, childsig);
+
+ for (i=0; i<NUMPROCS; i++)
+ {
+ while ((p=fork()) == -1)
+ {
+ perror("fork");
+ sleep(5);
+ }
+
+ if (p == 0)
+ {
+ close(pipefd[1]);
+ close(pipefd2[0]);
+ close(pipefd2[1]);
+ read(pipefd[0], &c, 1);
+ _exit(0);
+ }
+ }
+ close(pipefd2[1]);
+ close(pipefd[0]);
+ if (read(pipefd2[0], &c, 1) != 0)
+ {
+ perror("read");
+ }
+
+ wait_block();
+
+ close(pipefd2[0]);
+ close(pipefd[1]);
+ sleep(3);
+ time(&t);
+ wait_clear(&childsig);
+
+ do
+ {
+ sleep(3);
+ } while ( time(0) < t+3);
+ if (numterminated == NUMPROCS)
+ exit(0);
+ exit(1);
+ return (0);
+}
diff --git a/waitlib/testwait.c b/waitlib/testwait.c
new file mode 100644
index 0000000..fb0fe48
--- /dev/null
+++ b/waitlib/testwait.c
@@ -0,0 +1,99 @@
+/*
+** Copyright 1998 - 2006 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#include "waitlib.h"
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+
+/* Stress test waitlib.c */
+
+#define NUMCHILDREN 100 /* Start 100 child processes */
+#define INITCHILDREN 10 /* Start with these many child procs */
+
+static unsigned started, finished;
+
+static void reap_child(pid_t p, int dummy)
+{
+ ++finished;
+}
+
+static RETSIGTYPE sighandler(int sig)
+{
+ wait_reap(&reap_child, &sighandler);
+#if RETSIGTYPE != void
+ return (0);
+#endif
+}
+
+static pid_t start_child()
+{
+pid_t p;
+
+ wait_block();
+ while ((p=fork()) == (pid_t)-1)
+ {
+ perror("fork");
+ sleep(3);
+ }
+ ++started;
+ if (p == 0)
+ {
+ wait_restore();
+ }
+ else
+ wait_clear(&sighandler);
+ return (p);
+}
+
+extern void foobar();
+
+int main()
+{
+int pipefd[2];
+int pipefd2[2];
+char c;
+
+ if (pipe(pipefd) || pipe(pipefd2))
+ {
+ perror("pipe");
+ exit(1);
+ }
+
+ signal(SIGCHLD, sighandler);
+
+ started=finished=0;
+ while (started < INITCHILDREN)
+ {
+ if (start_child() == 0)
+ {
+ close(pipefd2[0]);
+ close(pipefd2[1]);
+ close(pipefd[1]);
+ if (read(pipefd[0], &c, 1) != 1)
+ ; /* Shut gcc up */
+ close(pipefd[0]);
+ _exit(0);
+ }
+ }
+ close(pipefd2[1]);
+ close(pipefd[0]);
+ if (read(pipefd2[0], &c, 1) != 1)
+ ; /* Shut gcc up */
+ close(pipefd[1]);
+ close(pipefd2[0]);
+
+ while (started < NUMCHILDREN)
+ if (start_child() == 0)
+ _exit(0);
+
+ alarm(30);
+ while (finished < started)
+ foobar();
+ exit(0);
+}
diff --git a/waitlib/testwait2.c b/waitlib/testwait2.c
new file mode 100644
index 0000000..f64cc78
--- /dev/null
+++ b/waitlib/testwait2.c
@@ -0,0 +1,9 @@
+/*
+** Copyright 1998 - 1999 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+
+void foobar()
+{
+}
diff --git a/waitlib/waitlib.c b/waitlib/waitlib.c
new file mode 100644
index 0000000..9a5a2e1
--- /dev/null
+++ b/waitlib/waitlib.c
@@ -0,0 +1,110 @@
+/*
+** Copyright 1998 - 2005 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#ifndef INCLUDED_FROM_CONFIGURE
+#include "waitlib.h"
+#endif
+#include <signal.h>
+#include <stdio.h>
+
+
+#if HAVE_SIGPROCMASK
+
+#define HOLD_CHILDREN {\
+ sigset_t ss; sigemptyset(&ss); sigaddset(&ss, SIGCHLD); \
+ sigprocmask(SIG_BLOCK, &ss, NULL);\
+ }
+
+#define RELEASE_CHILDREN {\
+ sigset_t ss; sigemptyset(&ss); sigaddset(&ss, SIGCHLD); \
+ sigprocmask(SIG_UNBLOCK, &ss, NULL);\
+ }
+
+#else
+#if HAVE_SIGHOLD
+
+#define HOLD_CHILDREN sighold(SIGCHLD)
+#define RELEASE_CHILDREN sigrelse(SIGCHLD)
+
+#else
+
+#define HOLD_CHILDREN sigblock(sigmask(SIGCHLD))
+#define RELEASE_CHILDREN sigsetmask(0)
+
+#endif
+#endif
+
+#if USE_WAIT3
+
+void wait_block()
+{
+ HOLD_CHILDREN;
+}
+
+void wait_clear(RETSIGTYPE (*func)(int))
+{
+ RELEASE_CHILDREN;
+}
+
+void wait_restore()
+{
+ signal(SIGCHLD, SIG_DFL);
+ RELEASE_CHILDREN;
+}
+
+#else
+
+void wait_block()
+{
+ signal(SIGCHLD, SIG_DFL);
+}
+
+void wait_clear(RETSIGTYPE (*func)(int))
+{
+ signal(SIGCHLD, func);
+}
+
+void wait_restore()
+{
+ signal(SIGCHLD, SIG_DFL);
+}
+
+#endif
+
+void wait_reap( void (*func)(pid_t, int), RETSIGTYPE (*handler)(int))
+{
+int dummy;
+pid_t p;
+
+#if USE_WAIT3
+
+ HOLD_CHILDREN;
+
+ while ((p=wait3(&dummy, WNOHANG, 0)) > 0)
+#else
+ if ((p=wait(&dummy)) > 0)
+#endif
+ {
+ (*func)(p, dummy);
+ }
+
+ signal(SIGCHLD, handler);
+
+#if USE_WAIT3
+ RELEASE_CHILDREN;
+#endif
+
+}
+
+void wait_forchild( void (*reap)(pid_t, int), RETSIGTYPE (*func)(int))
+{
+pid_t p;
+int wait_stat;
+
+ signal(SIGCHLD, SIG_DFL);
+ p=wait(&wait_stat);
+ signal(SIGCHLD, func);
+ (*reap)(p, wait_stat);
+}
diff --git a/waitlib/waitlib.h b/waitlib/waitlib.h
new file mode 100644
index 0000000..7d36287
--- /dev/null
+++ b/waitlib/waitlib.h
@@ -0,0 +1,90 @@
+#ifndef waitlib_h
+#define waitlib_h
+
+/*
+** Copyright 1998 - 1999 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#include <sys/types.h>
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+/*
+** Ok, wait() pecularities are handled by the following functions. Except
+** for them, nobody else should care about wait's quirks.
+**
+** First, call signal(SIGCHLD) as usual to set up your signal handler.
+** Within the signal handler, call wait_reap to reap one (or more)
+** child processes.
+*/
+
+void wait_reap( void (*)(pid_t, int), /* Called to process reaped child */
+ RETSIGTYPE (*)(int)); /* Should point back to signal handler */
+
+/*
+** Main program can call wait_block and wait_clear to temporarily
+** suspend reaping while in a critical section.
+*/
+
+void wait_block();
+void wait_clear(RETSIGTYPE (*)(int)); /* The signal handler */
+
+/*
+** wait_restore should be called instead of signal(SIGCHLD, SIG_DFL)
+** to restore the signal handler just before exiting. It should also
+** be called by any forked process.
+*/
+
+void wait_restore();
+
+/*
+** Sometimes the parent wants to wait for one child to terminate.
+** call wait_forchild for that. First, wait_block() must be called to
+** suspend all asynchronous reaping. Then, call wait_forchild. Before
+** wait_forchild returns, the reaper function is guaranteed to be called.
+** Asynchronous reaping is still blocked upon exit, call wait_clear() to
+** reenable it.
+*/
+
+void wait_forchild( void (*)(pid_t, int), /* Reaper */
+ RETSIGTYPE (*)(int)); /* Signal handler stub */
+
+/*
+** wait_startchildren() is a convenient function to start a given number
+** of child processes. The function returns 0 for the parent process, >0
+** for each child process, and < 0 if there was an error starting child
+** processes. pidptr points to a pointer to the array of started pids,
+** which wait_startchildren initializes, if *pidptr is NULL, wait_startchildren
+** mallocs this array. If pidptr is NULL, wait_startchildren uses its own
+** internal array.
+*/
+
+int wait_startchildren(unsigned nchildren, pid_t **pidptr);
+
+/*
+** wait_reforkchild() is used in conjunction with wait_startchildren's array,
+** and is intended to be called from the wait handler. It checks if the
+** pid is one of the listed children, and, if so, reforks it.
+** wait_reforkchild() returns < 0 if there was a problem reforking the child
+** process, 0 if the child process started succesfully, or if the terminated
+** pid is unknown, > 0 in the reforked process.
+*/
+
+int wait_reforkchild(unsigned nchildren, pid_t *pidptr, pid_t pid);
+
+
+
+#endif
diff --git a/waitlib/waitlib2.c b/waitlib/waitlib2.c
new file mode 100644
index 0000000..52dfc26
--- /dev/null
+++ b/waitlib/waitlib2.c
@@ -0,0 +1,114 @@
+/*
+** Copyright 2000-2006 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#include "config.h"
+#include "waitlib.h"
+#include <stdlib.h>
+#include <sys/types.h>
+#include <string.h>
+#include <signal.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+
+static pid_t *static_pid_buf=0;
+
+static void start_reaper(pid_t pid, int exit_stat)
+{
+}
+
+static RETSIGTYPE start_reap(int signum)
+{
+ wait_reap(start_reaper, start_reap);
+
+#if RETSIGTYPE != void
+ return (0);
+#endif
+}
+
+void wait_forchild( void (*)(pid_t, int), /* Reaper */
+ RETSIGTYPE (*)(int)); /* Signal handler stub */
+
+int wait_startchildren(unsigned nchildren, pid_t **pidptr)
+{
+int pipefd[2];
+pid_t p;
+unsigned i;
+
+ if (!pidptr)
+ {
+ if (static_pid_buf) free(static_pid_buf);
+ static_pid_buf=0;
+ pidptr= &static_pid_buf;
+ }
+
+ if (*pidptr == 0 && (*pidptr=malloc(nchildren * sizeof(pid_t))) == 0)
+ return (-1);
+
+ if (pipe(pipefd) < 0) return (-1);
+
+ signal(SIGCHLD, start_reap);
+ wait_block();
+ for (i=0; i<nchildren; i++)
+ {
+ p=fork();
+ if (p < 0)
+ {
+ while (i)
+ {
+ kill( (*pidptr)[--i], SIGKILL);
+ wait_forchild(start_reaper, start_reap);
+ }
+ close(pipefd[0]);
+ close(pipefd[1]);
+ wait_clear(start_reap);
+ signal(SIGCHLD, SIG_DFL);
+ return (-1);
+ }
+
+ if (p == 0)
+ {
+ char buf;
+
+ wait_restore();
+ close(pipefd[1]);
+ if (read(pipefd[0], &buf, 1) != 1)
+ exit(1);
+ close(pipefd[0]);
+ return (1);
+ }
+
+ (*pidptr)[i]=p;
+ }
+ wait_restore();
+ close(pipefd[0]);
+ for (i=0; i<nchildren; i++)
+ if (write(pipefd[1], "", 1) < 0)
+ ; /* Shut gcc up */
+ close(pipefd[1]);
+ return (0);
+}
+
+int wait_reforkchild(unsigned nchildren, pid_t *pidptr, pid_t pid)
+{
+unsigned i;
+
+ for (i=0; i<nchildren; i++)
+ if (pidptr[i] == pid) break;
+
+ if (i >= nchildren) return (0);
+
+ switch ((pidptr[i]=fork())) {
+ case 0:
+ wait_restore(); /* Just in case */
+ return (1);
+ case -1:
+ return (-1);
+ default:
+ break;
+ }
+ return (0);
+}