Skip to content

Instantly share code, notes, and snippets.

@ytoshima
Created February 21, 2013 09:18
Show Gist options
  • Save ytoshima/5003429 to your computer and use it in GitHub Desktop.
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.
#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