File: timeout.c

package info (click to toggle)
cmix 2.0.12-6
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 6,924 kB
  • ctags: 6,063
  • sloc: cpp: 27,155; ansic: 11,923; sh: 3,000; exp: 2,270; yacc: 1,724; makefile: 1,251; lex: 488; perl: 278
file content (107 lines) | stat: -rw-r--r-- 3,023 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/* Spawn a process and wait a certain amount of time for it to finish.
   Input: 1st arg is the number of seconds to wait.
          2nd arg is the path to the executable.
          3rd-nth args are the arguments to the executable. 
   Return values: */
enum { OK, FAILED, TIMEOUT, GOTSIGNAL, NOFORK, NOEXEC };

#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

#define TIMEARG 1
#define PGMARG  2

char const* signames[NSIG]={NULL} ;

const char *getsigname(int sig) {
  static char buffer[30];
#define ONESIG(SIGX) if (sig==SIGX) return #SIGX ;
#include <initsigs.i>
#undef ONESIG
  sprintf(buffer,"unknown signal %d",sig);
  return buffer ;
}

static volatile signal_handled = 0;

/* The signal handler */
static void handler()
{
  /* Simply return (this should wake up the waiting process?) */
  signal_handled = 1;
  return;
}

int main(int argc, char** argv)
{
  /* Get the time from the arguments (divided by TIMESTEP) */
  int time = atoi(argv[TIMEARG]) ;
  pid_t child = vfork();
  if (child == -1) {
    /* Fork was not possible. */
    return NOFORK;
  }
  else if (child == 0) {
    /* This is the child process */
    /* Redirect stderr to stdout */
    /* (tcl assumes any output to stderr means failure) */
    dup2(1,2);
    /* Run the command. */
    if (execvp(argv[PGMARG],argv+PGMARG) == -1) {
      printf("Could not execute '%s ...': %s\n", argv[PGMARG],
             strerror(errno));
      return 1 ;
    }
  }
  else {
    /* This is the parent process. Wait for the child to terminate or
       timeout. */ 
    int childstatus ;
    pid_t waitstatus ;
    /* Setup handler for child termination. */
    static struct sigaction act ;
    act.sa_handler = handler ;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0 ;
    sigaction(SIGALRM,&act,NULL);
    alarm(time);
    /* wait for the child to terminate or the alarm to sound
     * (whichever comes first)
     */
    waitstatus = wait(&childstatus);
    if ( waitstatus != child ) {
      /* We timed out. */
      /* Kill the child. */
      kill(child, SIGKILL);
      if ( signal_handled )
        printf("\n@UNRESOLVED@\n%s: timed out after %d seconds\n",
               argv[PGMARG],time);
      else
        printf("\n@UNRESOLVED@\n%s: wait() failed\n",argv[0]);
      return TIMEOUT;
    }
    if ( waitstatus != child ) {
      printf("@@!!@@\nwait returned %d, but the child is %d\n",
             (int)waitstatus,(int)child);
    }
    if ( WIFEXITED(childstatus) ) {
      if ( WEXITSTATUS(childstatus) == 0 )
        return OK ;
      printf("%s: failed with exit status %d\n",
             argv[PGMARG],(int)WEXITSTATUS(childstatus));
      return FAILED ;
    }
    if ( WIFSIGNALED(childstatus) ) {
      printf("@DEAD@\n%s: got %s\n",argv[PGMARG],
             getsigname(WTERMSIG(childstatus)));
      return GOTSIGNAL ;
    }
    printf("\n@UNRESOLVED@\n%s: bizarre return status %d\n",
           argv[PGMARG],childstatus);
    return TIMEOUT;
  }
}