Created
February 21, 2013 09:18
-
-
Save ytoshima/5003429 to your computer and use it in GitHub Desktop.
Check whether the specified command line completed in the specified duration in seconds.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <errno.h> | |
#include <sys/types.h> | |
#include <sys/wait.h> | |
#include <sys/time.h> | |
#include <signal.h> | |
#include <string.h> | |
typedef unsigned long long u8; | |
typedef long long i8; | |
static verbose = 0; | |
typedef struct { | |
int dursec; | |
char **argv; | |
int valid; | |
pid_t cpid; | |
int waitDone; | |
int waitStatus; | |
} param_t; | |
void usage() | |
{ | |
const char *msg = "usage: ck-runtime <limit-second> <command> [arg...]\n" \ | |
" return code: 0: command completed in <limit-second>\n" \ | |
" 1: error found in command line parsing (command is not execute)\n" \ | |
" 2: command did not complete in <limit-second>" \ | |
" 3: exec failed // does not work..."; | |
printf("%s\n", msg); | |
} | |
param_t* parseArgs(int argc, char **argv) | |
{ | |
param_t *pp = (param_t*)calloc(1, sizeof(param_t)); | |
pp->valid = 0; | |
if (argc < 3) return pp; | |
pp->dursec = atoi(argv[1]); | |
if (pp->dursec < 1) return pp; | |
pp->argv = &argv[2]; | |
pp->valid = 1; | |
return pp; | |
} | |
void dumpParam(param_t *pp) | |
{ | |
int idx = 0; | |
char **ap = NULL; | |
printf("dursec: %d\n", pp->dursec); | |
printf("args:"); | |
for (ap = pp->argv; *ap; ap++) { | |
printf(" %d: '%s'", idx, *ap); | |
idx++; | |
} | |
printf("\n"); | |
} | |
i8 tv2llmsec(struct timeval *tv) | |
{ | |
i8 llv = tv->tv_sec*1000ll + tv->tv_usec/1000ll; | |
return llv; | |
} | |
int execFailed = 0; | |
pid_t startCommand(char **argv) | |
{ | |
pid_t cpid = fork(); | |
int exrv = -1; | |
if (cpid == 0) { | |
/* child */ | |
exrv = execvp(argv[0], argv); | |
execFailed = 1; | |
if (exrv) { | |
perror("execvp"); | |
} | |
} else if (cpid > 0) { | |
/* parent */ | |
return cpid; | |
} else { | |
perror("fork"); | |
return -1; | |
} | |
} | |
param_t *gpp = NULL; | |
void alrmHandler(int signo) | |
{ | |
static char msg[] = "hit alarm\n"; | |
int r = 0; | |
r = write(1, msg, sizeof(msg)-1); | |
if (! gpp->waitDone) { | |
static char msg1[] = "child is still running\n"; | |
r = write(1, msg1, sizeof(msg1)-1); | |
kill(gpp->cpid, SIGQUIT); | |
} | |
exit(2); | |
} | |
void setupAlarm(param_t *pp) | |
{ | |
struct sigaction act, oact; | |
int r = -1; | |
gpp = pp; | |
memset(&act, 0, sizeof(act)); | |
memset(&act, 0, sizeof(oact)); | |
act.sa_handler = alrmHandler; | |
sigemptyset(&act.sa_mask); | |
r = sigaction(SIGALRM, &act, &oact); | |
if (r) { perror("sigaction"); } | |
alarm(pp->dursec); | |
} | |
int main(int argc, char *argv[]) | |
{ | |
param_t *pp = parseArgs(argc, argv); | |
pid_t cpid = -1; | |
if (pp->valid) { | |
int wr = -1, status = 0; | |
struct timeval tv0, tv1; | |
if (0) dumpParam(pp); | |
cpid = startCommand(pp->argv); | |
pp->cpid = cpid; | |
setupAlarm(pp); | |
gettimeofday(&tv0, NULL); | |
wr = waitpid(cpid, &status, 0); | |
gettimeofday(&tv1, NULL); | |
pp->waitDone; | |
pp->waitStatus = status; | |
if (verbose) { | |
printf("command took %lld msec.\n", tv2llmsec(&tv1)-tv2llmsec(&tv0)); | |
} | |
if (wr == -1) { | |
perror("waitpid"); | |
} else { | |
if (WIFEXITED(status)) { | |
int sc = WEXITSTATUS(status); | |
if (verbose) { | |
printf("pid %d exited with %d\n", cpid, sc); | |
} else if (sc) { | |
printf("pid %d exited with %d\n", cpid, sc); | |
} | |
} else if (WIFSIGNALED(status)) { | |
printf("pid %d signaled %d\n", cpid, WTERMSIG(status)); | |
if (WCOREDUMP(status)) { printf("coredumped\n"); } | |
} else if (WIFSTOPPED(status)) { | |
printf("pid %d was stopped by sig %d\n", cpid, WSTOPSIG(status)); | |
} else if (WIFCONTINUED(status)) { | |
printf("pid %d was continued.\n", cpid); | |
} else { | |
printf("unknown status %#x\n", status); | |
} | |
} | |
} else { | |
/* !pp->valid */ | |
usage(); | |
return 1; | |
} | |
/* trying to pick up exec error, but this does not work... | |
need to communicate via pipe, etc ? */ | |
if (execFailed) return 3; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment