diff options
Diffstat (limited to 'waitlib')
| -rw-r--r-- | waitlib/.gitignore | 1 | ||||
| -rw-r--r-- | waitlib/Makefile.am | 18 | ||||
| -rw-r--r-- | waitlib/configure.in | 108 | ||||
| -rw-r--r-- | waitlib/confwait.c | 105 | ||||
| -rw-r--r-- | waitlib/testwait.c | 99 | ||||
| -rw-r--r-- | waitlib/testwait2.c | 9 | ||||
| -rw-r--r-- | waitlib/waitlib.c | 110 | ||||
| -rw-r--r-- | waitlib/waitlib.h | 90 | ||||
| -rw-r--r-- | waitlib/waitlib2.c | 114 |
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); +} |
