798 lines
21 KiB
C
798 lines
21 KiB
C
/*
|
|
* Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of version 2 of the GNU General Public License as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it would be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
*
|
|
* Further, this software is distributed without any warranty that it is
|
|
* free of the rightful claim of any third person regarding infringement
|
|
* or the like. Any license provided herein, whether implied or
|
|
* otherwise, applies only to this software file. Patent licenses, if
|
|
* any, provided herein do not apply to combinations of this program with
|
|
* other software, or any other product whatsoever.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
|
|
* Mountain View, CA 94043, or:
|
|
*
|
|
* http://www.sgi.com
|
|
*
|
|
* For further information regarding this notice, see:
|
|
*
|
|
* http://oss.sgi.com/projects/GenInfo/NoticeExplan/
|
|
*
|
|
*/
|
|
/* $Id: sigrelse01.c,v 1.14 2009/08/28 14:10:16 vapier Exp $ */
|
|
/*****************************************************************************
|
|
* OS Test - Silicon Graphics, Inc. Eagan, Minnesota
|
|
*
|
|
* TEST IDENTIFIER : sigrelse01 Releasing held signals.
|
|
*
|
|
* PARENT DOCUMENT : sgrtds01 sigrelse system call
|
|
*
|
|
* AUTHOR : Bob Clark
|
|
* : Rewrote 12/92 by Richard Logan
|
|
*
|
|
* CO-PILOT : Dave Baumgartner
|
|
*
|
|
* DATE STARTED : 10/08/86
|
|
*
|
|
* TEST ITEMS
|
|
*
|
|
* 1. sigrelse turns on the receipt of signals held by sighold.
|
|
*
|
|
* SPECIAL PROCEDURAL REQUIRMENTS
|
|
* None
|
|
*
|
|
* DETAILED DESCRIPTION
|
|
* set up pipe for parent/child communications
|
|
* fork off a child process
|
|
*
|
|
* parent():
|
|
* set up for unexpected signals
|
|
* wait for child to send ready message over pipe
|
|
* send all catchable signals to child process
|
|
* send alarm signal to speed up timeout
|
|
* wait for child to terminate and check exit value
|
|
*
|
|
* if exit value is EXIT_OK
|
|
* get message from pipe (contains array of signal counters)
|
|
* loop through array of signal counters and record any
|
|
* signals which were not caught once.
|
|
* record PASS or FAIL depending on what was found in the array.
|
|
*
|
|
* else if exit is SIG_CAUGHT then BROK (signal caught
|
|
* before released)
|
|
* else if exit is WRITE_BROK then BROK (write() to pipe failed)
|
|
* else if exit is HANDLE_ERR then BROK (error in child's
|
|
* signal handler)
|
|
* else unexpected exit value - BROK
|
|
*
|
|
* child():
|
|
* phase 1:
|
|
* set up to catch all catchable signals (exit SIG_CAUGHT
|
|
* if caught)
|
|
* hold each signal with sighold()
|
|
* send parent ready message if setup went ok.
|
|
* wait for signals to arrive - timeout if they don't
|
|
*
|
|
* phase 2:
|
|
* release each signal and wait a second for the handler to
|
|
* catch it.
|
|
* (the handler will record each signal it catches in an array
|
|
* and exit HANDLE_ERR if an error occurs)
|
|
*
|
|
* send array of counters back to parent for processing.
|
|
* exit EXIT_OK
|
|
* NOTES
|
|
* since child is executing system calls under test, no
|
|
* system call times are printed.
|
|
*
|
|
***************************************************************************/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <signal.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
#include "test.h"
|
|
#include "safe_macros.h"
|
|
|
|
#ifdef __linux__
|
|
/* glibc2.2 definition needs -D_XOPEN_SOURCE, which breaks other things. */
|
|
extern int sighold(int __sig);
|
|
extern int sigrelse(int __sig);
|
|
#endif
|
|
|
|
/* Needed for NPTL */
|
|
#define SIGCANCEL 32
|
|
#define SIGTIMER 33
|
|
|
|
void setup(void);
|
|
void cleanup(void);
|
|
static void parent(void);
|
|
static void child(void);
|
|
static void timeout(int sig);
|
|
static int setup_sigs(void);
|
|
static void handler(int sig);
|
|
static void wait_a_while(void);
|
|
static char *read_pipe(int fd);
|
|
static int write_pipe(int fd, char *msg);
|
|
static int set_timeout(void);
|
|
static void clear_timeout(void);
|
|
static void getout(void);
|
|
int choose_sig(int sig);
|
|
|
|
#define TRUE 1
|
|
#define FALSE 0
|
|
|
|
#ifndef DEBUG
|
|
#define DEBUG 0
|
|
#endif
|
|
|
|
#define CHILD_EXIT(VAL) ((VAL >> 8) & 0377) /* exit value of child process */
|
|
#define CHILD_SIG(VAL) (VAL & 0377) /* signal value of child proc */
|
|
|
|
#define MAXMESG 512 /* the size of the message string */
|
|
|
|
#define READY "ready" /* signal to parent that child is set up */
|
|
|
|
#define TIMEOUT 30 /* time (sec) used in the alarm calls */
|
|
|
|
/* child exit values */
|
|
#define EXIT_OK 0
|
|
#define SIG_CAUGHT 8
|
|
#define WRITE_BROK 16
|
|
#define HANDLE_ERR 32
|
|
|
|
int TST_TOTAL = 1; /* number of test items */
|
|
|
|
char *TCID = "sigrelse01"; /* test case identifier */
|
|
static char mesg[MAXMESG]; /* message buffer for tst_res */
|
|
static int pid; /* process id of child */
|
|
static int pipe_fd[2]; /* file descriptors for pipe parent read */
|
|
static int pipe_fd2[2]; /* file descriptors for pipe child read */
|
|
static int phase; /* flag for phase1 or phase2 of */
|
|
/* signal handler */
|
|
static int sig_caught; /* flag TRUE if signal caught */
|
|
/* (see wait_a_while ()) */
|
|
|
|
/* ensure that NUMSIGS is defined. */
|
|
#ifndef NUMSIGS
|
|
#define NUMSIGS NSIG
|
|
#endif
|
|
|
|
/* array of counters for signals caught by handler() */
|
|
static int sig_array[NUMSIGS];
|
|
|
|
/***********************************************************************
|
|
* M A I N
|
|
***********************************************************************/
|
|
int main(int argc, char **argv)
|
|
{
|
|
int lc;
|
|
|
|
/* gcc -Wall complains about sig_caught not being ref'd because of the
|
|
external declarations. */
|
|
sig_caught = FALSE;
|
|
|
|
/*
|
|
* parse standard options
|
|
*/
|
|
tst_parse_opts(argc, argv, NULL, NULL);
|
|
#ifdef UCLINUX
|
|
maybe_run_child(&child, "dd", &pipe_fd[1], &pipe_fd2[0]);
|
|
#endif
|
|
|
|
/*
|
|
* perform global setup for test
|
|
*/
|
|
setup();
|
|
|
|
for (lc = 0; TEST_LOOPING(lc); lc++) {
|
|
|
|
tst_count = 0;
|
|
|
|
/*
|
|
* fork off a child process
|
|
*/
|
|
if ((pid = FORK_OR_VFORK()) < 0) {
|
|
tst_brkm(TBROK | TERRNO, cleanup, "fork() failed");
|
|
|
|
} else if (pid > 0) {
|
|
parent();
|
|
|
|
} else {
|
|
#ifdef UCLINUX
|
|
if (self_exec(argv[0], "dd", pipe_fd[1], pipe_fd2[0]) <
|
|
0) {
|
|
tst_brkm(TBROK | TERRNO, cleanup,
|
|
"self_exec() failed");
|
|
}
|
|
#else
|
|
child();
|
|
#endif
|
|
}
|
|
|
|
}
|
|
|
|
cleanup();
|
|
tst_exit();
|
|
|
|
} /* end main */
|
|
|
|
/****************************************************************************
|
|
* parent() : wait for "ready" from child, send signals to child, wait for
|
|
* child to exit and report what happened.
|
|
***************************************************************************/
|
|
static void parent(void)
|
|
{
|
|
int term_stat; /* child return status */
|
|
int rv; /* function return value */
|
|
int sig; /* current signal number */
|
|
char *str; /* string returned from read_pipe() */
|
|
int *array; /* pointer to sig_array returned from child */
|
|
int fail = FALSE; /* flag indicating test item failure */
|
|
char big_mesg[MAXMESG * 6]; /* storage for big failure message */
|
|
int caught_sigs;
|
|
|
|
/* wait for "ready" message from child */
|
|
if ((str = read_pipe(pipe_fd[0])) == NULL) {
|
|
/* read_pipe() failed. */
|
|
tst_brkm(TBROK, getout, "%s", mesg);
|
|
}
|
|
|
|
if (strcmp(str, READY) != 0) {
|
|
/* child setup did not go well */
|
|
tst_brkm(TBROK, getout, "%s", str);
|
|
}
|
|
|
|
/*
|
|
* send signals to child and see if it holds them
|
|
*/
|
|
|
|
for (sig = 1; sig < NUMSIGS; sig++) {
|
|
if (choose_sig(sig)) {
|
|
if (kill(pid, sig) < 0) {
|
|
if (errno == ESRCH) {
|
|
if (kill(pid, SIGTERM) < 0)
|
|
tst_brkm(TBROK | TERRNO, getout,
|
|
"kill(%d, %d) and kill(%d, SIGTERM) failed",
|
|
pid, sig, pid);
|
|
else
|
|
tst_brkm(TBROK | TERRNO, getout,
|
|
"kill(%d, %d) failed, but kill(%d, SIGTERM) worked",
|
|
pid, sig, pid);
|
|
} else
|
|
tst_brkm(TBROK | TERRNO, getout,
|
|
"kill(%d, %d) failed", pid,
|
|
sig);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (write_pipe(pipe_fd2[1], READY) < 0) {
|
|
tst_brkm(TBROK | TERRNO, getout,
|
|
"Unable to tell child to go, write to pipe failed");
|
|
}
|
|
|
|
/*
|
|
* child is now releasing signals, wait and check exit value
|
|
*/
|
|
SAFE_WAIT(getout, &term_stat);
|
|
|
|
/* check child's signal exit value */
|
|
if ((sig = CHILD_SIG(term_stat)) != 0)
|
|
/* the child was zapped by a signal */
|
|
tst_brkm(TBROK, cleanup, "Unexpected signal %d killed child",
|
|
sig);
|
|
|
|
/* get child exit value */
|
|
|
|
rv = CHILD_EXIT(term_stat);
|
|
|
|
switch (rv) {
|
|
case EXIT_OK:
|
|
/* sig_array sent back on pipe, check it out */
|
|
if ((array = (int *)read_pipe(pipe_fd[0])) == NULL) {
|
|
/* read_pipe() failed. */
|
|
tst_resm(TBROK, "%s", mesg);
|
|
break;
|
|
}
|
|
#if DEBUG > 1
|
|
for (sig = 1; sig < NUMSIGS; sig++) {
|
|
printf("array[%d] = %d\n", sig, array[sig]);
|
|
}
|
|
#endif
|
|
caught_sigs = 0;
|
|
for (sig = 1; sig < NUMSIGS; sig++) {
|
|
if (choose_sig(sig)) {
|
|
if (array[sig] != 1) {
|
|
/* sig was not caught or caught too many times */
|
|
(void)sprintf(mesg,
|
|
"\tsignal %d caught %d times (expected 1).\n",
|
|
sig, array[sig]);
|
|
(void)strcat(big_mesg, mesg);
|
|
fail = TRUE;
|
|
} else {
|
|
caught_sigs++;
|
|
}
|
|
}
|
|
} /* endfor */
|
|
|
|
if (fail == TRUE)
|
|
tst_resm(TFAIL, "%s", big_mesg);
|
|
else
|
|
tst_resm(TPASS,
|
|
"sigrelse() released all %d signals under test.",
|
|
caught_sigs);
|
|
break;
|
|
|
|
case TBROK:
|
|
/* get BROK message from pipe */
|
|
if ((str = read_pipe(pipe_fd[0])) == NULL) {
|
|
/* read_pipe() failed. */
|
|
tst_resm(TBROK, "%s", mesg);
|
|
break;
|
|
}
|
|
|
|
/* call tst_res: str contains the message */
|
|
tst_resm(TBROK, "%s", str);
|
|
break;
|
|
case SIG_CAUGHT:
|
|
/* a signal was caught before it was released */
|
|
tst_resm(TBROK, "A signal was caught before being released.");
|
|
break;
|
|
case WRITE_BROK:
|
|
/* the write() call failed in child's write_pipe */
|
|
tst_resm(TBROK, "write() pipe failed for child.");
|
|
break;
|
|
case HANDLE_ERR:
|
|
/* more than one signal tried to be handled at the same time */
|
|
tst_resm(TBROK, "Error occured in signal handler.");
|
|
break;
|
|
default:
|
|
tst_resm(TBROK, "Unexpected exit code %d from child", rv);
|
|
break;
|
|
}
|
|
|
|
} /* end of parent */
|
|
|
|
/****************************************************************************
|
|
* child() : hold signals, notify parent and wait for parent to send signals.
|
|
* If none were caught (sighold worked), release the signals one at a time
|
|
* and wait for them to be caught. Send results back to parent
|
|
* for processing.
|
|
***************************************************************************/
|
|
static void child(void)
|
|
{
|
|
int rv; /* return value from sighold() and sigrelse() */
|
|
int sig; /* signal value */
|
|
int exit_val; /* exit value to send to parent */
|
|
char note[MAXMESG]; /* message buffer for pipe */
|
|
char *str;
|
|
|
|
phase = 1; /* tell handler that we do not want to catch signals */
|
|
|
|
/* set note to READY and if an error occurs, overwrite it */
|
|
(void)strcpy(note, READY);
|
|
|
|
/* set alarm in case something hangs */
|
|
if (set_timeout() < 0) {
|
|
/* an error occured - put mesg in note and send it back to parent */
|
|
(void)strcpy(note, mesg);
|
|
|
|
} else if (setup_sigs() < 0) {
|
|
/* an error occured - put mesg in note and send it back to parent */
|
|
(void)strcpy(note, mesg);
|
|
|
|
} else {
|
|
/* all set up to catch signals, now hold them */
|
|
|
|
for (sig = 1; sig < NUMSIGS; sig++) {
|
|
if (choose_sig(sig)) {
|
|
if ((rv = sighold(sig)) != 0) {
|
|
/* THEY say sighold ALWAYS returns 0 */
|
|
(void)sprintf(note,
|
|
"sighold did not return 0. rv:%d",
|
|
rv);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* send note to parent (if not READY, parent will BROK) and
|
|
* wait for parent to send signals. The timeout clock is set so
|
|
* that we will not wait forever - if sighold() did its job, we
|
|
* will not receive the signals. If sighold() blew it we will
|
|
* catch a signal and the interrupt handler will exit with a
|
|
* value of SIG_CAUGHT.
|
|
*/
|
|
if (write_pipe(pipe_fd[1], note) < 0) {
|
|
/*
|
|
* write_pipe() failed. Set exit value to WRITE_BROK to let
|
|
* parent know what happened
|
|
*/
|
|
clear_timeout();
|
|
exit(WRITE_BROK);
|
|
}
|
|
|
|
/*
|
|
* if we get to this point, all signals have been held and the
|
|
* timer has expired. Now what we want to do is release each
|
|
* signal and see if we catch it. If we catch all signals,
|
|
* sigrelse passed, else it failed.
|
|
*/
|
|
|
|
phase = 2; /* let handler know we are now expecting signals */
|
|
|
|
#if DEBUG > 0
|
|
printf("child: PHASE II\n");
|
|
#endif
|
|
|
|
/* assume success and overwrite exit_val if an error occurs */
|
|
exit_val = EXIT_OK;
|
|
|
|
#if DEBUG > 0
|
|
printf("child: pid=%d waiting for parent's ready...\n", getpid());
|
|
#endif
|
|
|
|
/*
|
|
* wait for parent to tell us that sigals were all sent
|
|
*/
|
|
|
|
/* wait for "ready" message from parent */
|
|
if ((str = read_pipe(pipe_fd2[0])) == NULL) {
|
|
/* read_pipe() failed. */
|
|
printf(" child: read_pipe failed\n");
|
|
exit(TBROK);
|
|
}
|
|
|
|
if (strcmp(str, READY) != 0) {
|
|
/* parent/pipe problem */
|
|
printf("child: didn't proper ready message\n");
|
|
exit(TBROK);
|
|
}
|
|
|
|
for (sig = 1; sig < NUMSIGS; sig++) {
|
|
if (choose_sig(sig)) {
|
|
|
|
/* all set up, release and catch a signal */
|
|
|
|
sig_caught = FALSE; /* handler sets it to TRUE when caught */
|
|
#if DEBUG > 1
|
|
printf("child: releasing sig %d...\n", sig);
|
|
#endif
|
|
if ((rv = sigrelse(sig)) != 0) {
|
|
/* THEY say sigrelse ALWAYS returns 0 */
|
|
(void)sprintf(note,
|
|
"sigrelse did not return 0. rv:%d",
|
|
rv);
|
|
exit_val = TBROK;
|
|
break;
|
|
}
|
|
|
|
/* give signal handler some time to process signal */
|
|
wait_a_while();
|
|
}
|
|
|
|
} /* endfor */
|
|
|
|
/*
|
|
* If we are error free so far...
|
|
* check the sig_array array for one occurence of
|
|
* each of the catchable signals. If this is true,
|
|
* then PASS, otherwise FAIL.
|
|
*/
|
|
|
|
if (exit_val == EXIT_OK) {
|
|
(void)memcpy(note, (char *)sig_array,
|
|
sizeof(note) < sizeof(sig_array) ?
|
|
sizeof(note) : sizeof(sig_array));
|
|
}
|
|
|
|
/* send note to parent and exit */
|
|
if (write_pipe(pipe_fd[1], note) < 0) {
|
|
/*
|
|
* write_pipe() failed. Set exit value to WRITE_BROK to let
|
|
* parent know what happened
|
|
*/
|
|
exit(WRITE_BROK);
|
|
}
|
|
|
|
exit(exit_val);
|
|
|
|
} /* end of child */
|
|
|
|
/*****************************************************************************
|
|
* setup_sigs() : set child up to catch all signals. If there is
|
|
* trouble, write message in mesg and return -1, else return 0.
|
|
* The signal handler has two functions depending on which phase
|
|
* of the test we are in. The first section is executed after the
|
|
* signals have been held (should not ever be used). The second
|
|
* section is executed after the signals have been released (should
|
|
* be executed for each signal).
|
|
****************************************************************************/
|
|
static int setup_sigs(void)
|
|
{
|
|
int sig;
|
|
|
|
/* set up signal handler routine */
|
|
for (sig = 1; sig < NUMSIGS; sig++) {
|
|
if (choose_sig(sig)) {
|
|
if (signal(sig, handler) == SIG_ERR) {
|
|
/* set up mesg to send back to parent */
|
|
(void)sprintf(mesg,
|
|
"signal() failed for signal %d. error:%d %s.",
|
|
sig, errno, strerror(errno));
|
|
return (-1);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
} /* end of setup_sigs */
|
|
|
|
/*****************************************************************************
|
|
* handler() : child's interrupt handler for all signals. The phase variable
|
|
* is set in the child process indicating what action is to be taken.
|
|
* The phase 1 section will be run if the child process catches a signal
|
|
* after the signal has been held resulting in a test item BROK.
|
|
* The parent detects this situation by a child exit value of SIG_CAUGHT.
|
|
* The phase 2 section will be run if the child process catches a
|
|
* signal after the signal has been released. All signals must be
|
|
* caught in order for a PASS.
|
|
****************************************************************************/
|
|
static void handler(int sig)
|
|
{
|
|
static int s = 0; /* semaphore so that we don't handle 2 */
|
|
/* sigs at once */
|
|
#if DEBUG > 1
|
|
printf("child: handler phase%d: caught signal %d.\n", phase, sig);
|
|
#endif
|
|
|
|
if (phase == 1) {
|
|
/* exit the child process with a value of -1 */
|
|
exit(SIG_CAUGHT);
|
|
|
|
} else {
|
|
/* phase 2 (error if s gets incremented twice) */
|
|
++s;
|
|
|
|
if (s > 1) {
|
|
exit(HANDLE_ERR);
|
|
}
|
|
|
|
/* increment the array element for this signal */
|
|
++sig_array[sig];
|
|
sig_caught = TRUE; /* flag for wait_a_while () */
|
|
--s;
|
|
}
|
|
|
|
return;
|
|
|
|
} /* end of handler */
|
|
|
|
/*****************************************************************************
|
|
* read_pipe() : read data from pipe and return in buf. If an error occurs
|
|
* put message in mesg and return NULL. Note: this routine sets a
|
|
* timeout signal in case the pipe is blocked.
|
|
****************************************************************************/
|
|
static char *read_pipe(int fd)
|
|
{
|
|
static char buf[MAXMESG]; /* buffer for pipe read */
|
|
int ret;
|
|
|
|
#if DEBUG > 0
|
|
printf("read_pipe: pid=%d waiting...\n", getpid());
|
|
#endif
|
|
|
|
/* set timeout alarm in case the pipe is blocked */
|
|
if (set_timeout() < 0) {
|
|
/* an error occured, message in mesg */
|
|
return NULL;
|
|
}
|
|
|
|
ret = -1;
|
|
while (ret == -1) { /* while empty reads */
|
|
if ((ret = read(fd, buf, MAXMESG)) == 0) {
|
|
(void)sprintf(mesg, "read() pipe failed. error:%d %s.",
|
|
errno, strerror(errno));
|
|
|
|
clear_timeout();
|
|
return NULL;
|
|
}
|
|
}
|
|
clear_timeout();
|
|
|
|
#if DEBUG > 0
|
|
printf("read_pipe: pid=%d received: %s.\n", getpid(), buf);
|
|
#endif
|
|
return (buf);
|
|
|
|
} /* end of read_pipe */
|
|
|
|
/*****************************************************************************
|
|
* write_pipe(msg) : write msg to pipe. If it fails, put message in
|
|
* mesg and return -1, else return 0.
|
|
****************************************************************************/
|
|
static int write_pipe(int fd, char *msg)
|
|
{
|
|
|
|
#if DEBUG > 0
|
|
printf("write_pipe: pid=%d, sending %s.\n", getpid(), msg);
|
|
#endif
|
|
|
|
if (write(fd, msg, MAXMESG) < 0) {
|
|
(void)sprintf(mesg, "write() pipe failed. error:%d %s.",
|
|
errno, strerror(errno));
|
|
|
|
return (-1);
|
|
}
|
|
return 0;
|
|
|
|
} /* end of write_pipe */
|
|
|
|
/*****************************************************************************
|
|
* set_timeout() : set alarm to signal process after the period of time
|
|
* indicated by TIMEOUT. If the signal occurs, the routine timeout()
|
|
* will be executed. If all goes ok, return 0, else load message
|
|
* into mesg and return -1.
|
|
****************************************************************************/
|
|
static int set_timeout(void)
|
|
{
|
|
if (signal(SIGALRM, timeout) == SIG_ERR) {
|
|
(void)sprintf(mesg,
|
|
"signal() failed for signal %d. error:%d %s.",
|
|
SIGALRM, errno, strerror(errno));
|
|
return (-1);
|
|
}
|
|
|
|
(void)alarm(TIMEOUT);
|
|
return 0;
|
|
|
|
} /* end of set_timeout */
|
|
|
|
/*****************************************************************************
|
|
* clear_timeout() : turn off the alarm so that SIGALRM will not get sent.
|
|
****************************************************************************/
|
|
static void clear_timeout(void)
|
|
{
|
|
(void)alarm(0);
|
|
|
|
} /* end of clear_timeout */
|
|
|
|
/*****************************************************************************
|
|
* timeout() : this routine is executed when the SIGALRM signal is
|
|
* caught. It does nothing but return - the read() on the pipe
|
|
* will fail.
|
|
****************************************************************************/
|
|
static void timeout(int sig)
|
|
{
|
|
#if DEBUG > 0
|
|
printf("timeout: pid=%d sigalrm caught.\n", getpid());
|
|
#endif
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* wait_a_while () : wait a while before returning.
|
|
****************************************************************************/
|
|
static void wait_a_while(void)
|
|
{
|
|
long btime;
|
|
|
|
btime = time(NULL);
|
|
while (time(NULL) - btime < TIMEOUT) {
|
|
if (sig_caught == TRUE)
|
|
break;
|
|
}
|
|
} /* end of wait_a_while */
|
|
|
|
static void getout(void)
|
|
{
|
|
if (pid > 0 && kill(pid, SIGKILL) < 0)
|
|
tst_resm(TWARN, "kill(%d, SIGKILL) failed", pid);
|
|
cleanup();
|
|
|
|
} /* end of getout */
|
|
|
|
#ifdef VAX
|
|
static int sighold(int signo)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int sigrelse(signo)
|
|
int signo;
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
int choose_sig(int sig)
|
|
{
|
|
switch (sig) {
|
|
|
|
case SIGKILL:
|
|
case SIGSTOP:
|
|
case SIGTSTP:
|
|
case SIGCONT:
|
|
case SIGALRM:
|
|
case SIGCANCEL:
|
|
case SIGTIMER:
|
|
#ifdef SIGNOBDM
|
|
case SIGNOBDM:
|
|
#endif
|
|
#ifdef SIGTTIN
|
|
case SIGTTIN:
|
|
#endif
|
|
#ifdef SIGTTOU
|
|
case SIGTTOU:
|
|
#endif
|
|
#ifdef SIGPTINTR
|
|
case SIGPTINTR:
|
|
#endif
|
|
#ifdef SIGSWAP
|
|
case SIGSWAP:
|
|
#endif
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
void setup(void)
|
|
{
|
|
|
|
tst_sig(FORK, DEF_HANDLER, cleanup);
|
|
|
|
TEST_PAUSE;
|
|
|
|
tst_tmpdir();
|
|
|
|
/* set up pipe for parent/child communications */
|
|
SAFE_PIPE(cleanup, pipe_fd);
|
|
|
|
/*
|
|
* Cause the read to return 0 once EOF is encountered and the
|
|
* read to return -1 if pipe is empty.
|
|
*/
|
|
if (fcntl(pipe_fd[0], F_SETFL, O_NONBLOCK) == -1)
|
|
tst_brkm(TBROK | TERRNO, cleanup,
|
|
"fcntl(Fds[0], F_SETFL, O_NONBLOCK) failed");
|
|
|
|
/* set up pipe for parent/child communications */
|
|
SAFE_PIPE(cleanup, pipe_fd2);
|
|
|
|
/*
|
|
* Cause the read to return 0 once EOF is encountered and the
|
|
* read to return -1 if pipe is empty.
|
|
*/
|
|
if (fcntl(pipe_fd2[0], F_SETFL, O_NONBLOCK) == -1)
|
|
tst_brkm(TBROK | TERRNO, cleanup,
|
|
"fcntl(Fds[0], F_SETFL, O_NONBLOCK) failed");
|
|
}
|
|
|
|
void cleanup(void)
|
|
{
|
|
tst_rmdir();
|
|
|
|
}
|