cpulimit-unix.c 3.97 KB
Newer Older
Andrei Paskevich's avatar
Andrei Paskevich committed
1 2 3
/********************************************************************/
/*                                                                  */
/*  The Why3 Verification Platform   /   The Why3 Development Team  */
Andrei Paskevich's avatar
Andrei Paskevich committed
4
/*  Copyright 2010-2016   --   INRIA - CNRS - Paris-Sud University  */
Andrei Paskevich's avatar
Andrei Paskevich committed
5 6 7 8
/*                                                                  */
/*  This software is distributed under the terms of the GNU Lesser  */
/*  General Public License version 2.1, with the special exception  */
/*  on linking described in file LICENSE.                           */
9
/*                                                                  */
Andrei Paskevich's avatar
Andrei Paskevich committed
10
/********************************************************************/
Francois Bobot's avatar
Francois Bobot committed
11

12 13
#ifndef _WIN32

Francois Bobot's avatar
Francois Bobot committed
14 15
#include <sys/types.h>
#include <sys/time.h>
16 17
#include <time.h>
#include <sys/times.h>
Francois Bobot's avatar
Francois Bobot committed
18 19 20 21
#include <sys/resource.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
22
#include <signal.h>
Francois Bobot's avatar
Francois Bobot committed
23
#include <errno.h>
MARCHE Claude's avatar
MARCHE Claude committed
24
#include <string.h>
25
#include <sys/wait.h>
Francois Bobot's avatar
Francois Bobot committed
26

27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
static int wallclock_timelimit = 60;
static int showtime = 0, hidetime = 0;

void show_time() {
  struct tms tms;
  double time;
  if (showtime) {
    times(&tms);
    time = (double)((tms.tms_cutime + tms.tms_cstime + 0.0)
                    / sysconf(_SC_CLK_TCK));
    fprintf(stderr, "why3cpulimit time : %f s\n", time);
  }
}

void wallclock_timelimit_reached() {
  fprintf(stderr,
          "Why3cpulimit: wallclock timelimit %d reached, killing command\n",
          wallclock_timelimit);
}

47 48 49 50 51 52 53 54 55

void usage(char *argv0) {
  fprintf(stderr,
          "usage: %s <time limit in seconds> <virtual memory limit in MiB>\n"
          "          <show/hide cpu time: -s|-h> <command> <args>...\n\n"
          "Zero sets no limit (keeps the actual limit)\n", argv0);
  exit(EXIT_FAILURE);
}

Francois Bobot's avatar
Francois Bobot committed
56
int main(int argc, char *argv[]) {
57
  long timelimit, memlimit;
Francois Bobot's avatar
Francois Bobot committed
58 59
  struct rlimit res;

60
  if (argc < 5) usage(argv[0]);
Andrei Paskevich's avatar
Andrei Paskevich committed
61

62 63
  showtime = !strcmp("-s", argv[3]);
  hidetime = !strcmp("-h", argv[3]);
Andrei Paskevich's avatar
Andrei Paskevich committed
64

65
  if (!(showtime || hidetime)) usage(argv[0]);
Andrei Paskevich's avatar
Andrei Paskevich committed
66

67 68 69
  /* get time limit in seconds from command line */
  timelimit = atol(argv[1]);
  if (timelimit < 0) usage(argv[0]);
Andrei Paskevich's avatar
Andrei Paskevich committed
70

71 72 73
  /* get virtual memory limit in MiB from command line */
  memlimit = atol(argv[2]);
  if (memlimit < 0) usage(argv[0]);
Andrei Paskevich's avatar
Andrei Paskevich committed
74

75 76 77 78 79 80 81 82 83 84 85 86
  /* Fork if requested */
  if (showtime || timelimit) {
    pid_t pid = fork ();

    if (pid == -1) {
      perror("fork");
      exit(EXIT_FAILURE);
    }

    if (pid > 0) {
      int status;
      pid_t p;
87 88 89 90 91 92 93 94 95 96 97

      if (timelimit) {
        /* set a wallclock time limit as last resort */
        struct sigaction sa;
        sa.sa_handler = &wallclock_timelimit_reached;
        sigemptyset(&sa.sa_mask);
        sa.sa_flags = 0;
        sigaction(SIGALRM, &sa, NULL);
        wallclock_timelimit = 2*timelimit + 60;
        alarm(wallclock_timelimit);
      }
98

99
      /* wait for the subprocess */
100 101 102 103 104 105 106 107 108 109
      p = waitpid(pid, &status, 0);

      if (p <= 0) {
        kill(pid, SIGKILL);
        p = waitpid(pid, &status, 0);
        if (p <= 0) {
          perror("why3cpulimit waitpid");
          kill(getpid(), SIGTERM);
        }
      }
110

111
      show_time();
112

113 114 115 116 117 118 119
      if (WIFEXITED(status)) return WEXITSTATUS(status);
      if (WIFSIGNALED(status)) kill(getpid(), WTERMSIG(status));

      fprintf(stderr, "why3cpulimit: child exited neither normally nor because of a signal\n");
      kill(getpid(), SIGTERM);
    }
  }
Francois Bobot's avatar
Francois Bobot committed
120

121 122 123 124 125 126 127
  if (timelimit > 0) {
    /* set the CPU time limit */
    getrlimit(RLIMIT_CPU,&res);
    res.rlim_cur = timelimit;
    setrlimit(RLIMIT_CPU,&res);
  }

128
  if (memlimit > 0) {
129
    /* set the CPU memory limit */
130 131 132 133 134
    getrlimit(RLIMIT_AS,&res);
    res.rlim_cur = memlimit * 1024 * 1024;
    setrlimit(RLIMIT_AS,&res);
  }

135 136 137 138 139 140 141
  if (timelimit > 0 || memlimit > 0) {
    /* do not generate core dumps */
    getrlimit(RLIMIT_CORE,&res);
    res.rlim_cur = 0;
    setrlimit(RLIMIT_CORE,&res);
  }

142
  /* execute the command */
143 144 145
  execvp(argv[4],argv+4);
  fprintf(stderr, "%s: exec of '%s' failed (%s)\n",
          argv[0],argv[4],strerror(errno));
Andrei Paskevich's avatar
Andrei Paskevich committed
146

147 148
  return EXIT_FAILURE;

Francois Bobot's avatar
Francois Bobot committed
149
}
150 151

#endif /* _WIN32 */