1 /* Author: attractivechaos */
3 /* last modified: 2008-0306 */
22 int check_interval
, interval
;
28 int fd_out
[2], fd_err
[2];
34 double utime
, stime
, rtime
;
35 size_t max_rss
, max_vsize
;
37 double avg_rss
, avg_vsize
;
40 /* declarations to provide consistent linkage */
45 int getopt_standard(int nargc
, char * const *nargv
, const char *ostr
);
47 RunStruct
*run_new_RunStruct()
49 RunStruct
*rs
= (RunStruct
*)malloc(sizeof(RunStruct
));
51 rs
->check_interval
= 1;
53 rs
->out
= STDOUT_FILENO
;
54 rs
->err
= STDERR_FILENO
;
62 void run_upd_RunStruct(RunStruct
*rs
)
66 char *prefix
= rs
->prefix
;
67 char *tmp
= (char*)malloc(strlen(prefix
) + 5);
68 pipe(rs
->fd_out
); pipe(rs
->fd_err
);
69 strcpy(tmp
, prefix
); strcat(tmp
, ".log");
70 rs
->log_fp
= fopen(tmp
, "w");
71 strcpy(tmp
, prefix
); strcat(tmp
, ".out");
72 rs
->out
= open(tmp
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0644);
73 strcpy(tmp
, prefix
); strcat(tmp
, ".err");
74 rs
->err
= open(tmp
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0644);
78 void run_free_RunStruct(RunStruct
*rs
)
80 /* rs->out, rs->err, rs->fd_out[2], rs->fd_err[2] will be closed elsewhere */
81 if (rs
->log_fp
!= stderr
) fclose(rs
->log_fp
);
85 int run_fill_RunStruct(int argc
, char *argv
[], RunStruct
*rs
)
88 while ((c
= getopt_standard(argc
, argv
, "c:m:p:T:M:")) >= 0) {
90 case 'c': rs
->cpu_limit
= atof(optarg
); break;
91 case 'm': rs
->mem_limit
= atof(optarg
); break;
92 case 'T': rs
->timeout
= atoi(optarg
); break;
93 case 'M': rs
->memoryout
= atoi(optarg
); break;
94 case 'p': rs
->prefix
= strdup(optarg
); break;
100 static void *write_out(void *arg
)
102 RunStruct
*rs
= (RunStruct
*)arg
;
105 close(rs
->fd_out
[1]);
106 while ((len
= read(rs
->fd_out
[0], buf
, 10)) != 0)
107 write(rs
->out
, buf
, len
);
108 close(rs
->fd_out
[0]);
112 static void *write_err(void *arg
)
114 RunStruct
*rs
= (RunStruct
*)arg
;
117 close(rs
->fd_err
[1]);
118 while ((len
= read(rs
->fd_err
[0], buf
, 10)) != 0)
119 write(rs
->err
, buf
, len
);
120 close(rs
->fd_err
[0]);
125 RunResult
*runit(int argc
, char *argv
[], RunStruct
*rs
)
128 if ((pid
= fork()) != 0) {
129 struct tms time_used
;
130 int status
, ret
, check_time
;
132 double sum_rss
, sum_vsize
;
139 pthread_t outid
, errid
;
141 run_get_static_sys_info(&rss
);
142 run_get_dynamic_sys_info(&rsd
);
143 start_time
= rsd
.wall_clock
;
144 rr
= (RunResult
*)malloc(sizeof(RunResult
));
145 rr
->max_rss
= rr
->max_vsize
= 0;
148 sum_rss
= sum_vsize
= 0.0;
152 pthread_create(&outid
, 0, write_out
, rs
);
153 pthread_create(&errid
, 0, write_err
, rs
);
155 while ((ret
= waitpid(pid
, &status
, WNOHANG
)) != pid
) {
156 run_get_dynamic_sys_info(&rsd
);
157 run_get_dynamic_proc_info(pid
, &rpd
);
158 if (rpd
.rss
> rr
->max_rss
) rr
->max_rss
= rpd
.rss
;
159 if (rpd
.vsize
> rr
->max_vsize
) rr
->max_vsize
= rpd
.vsize
;
160 sum_rss
+= rpd
.rss
* (rpd
.utime
+ rpd
.stime
- last_time
);
161 sum_vsize
+= rpd
.vsize
* (rpd
.utime
+ rpd
.stime
- last_time
);
162 last_time
= rpd
.utime
+ rpd
.stime
;
163 if (rs
->memoryout
&& rpd
.rss
> rs
->memoryout
) {
165 fprintf(rs
->log_fp
, "++ memory out!\n");
168 if (rs
->timeout
&& rpd
.utime
+ rpd
.stime
> rs
->timeout
) {
170 fprintf(rs
->log_fp
, "++ time out!\n");
173 if ((double)rsd
.mem_available
/rss
.mem_total
< rs
->mem_limit
174 && (double)rpd
.rss
/rss
.mem_total
> rs
->mem_limit
)
177 fprintf(rs
->log_fp
, "++ memory insufficient: %lu/%lu vs %lu\n", rsd
.mem_free
, rsd
.mem_available
, rss
.mem_total
);
180 if ((int)((rpd
.utime
+ rpd
.stime
) / rs
->check_interval
+ 0.5) == check_time
) {
181 if ((rpd
.utime
+ rpd
.stime
)/(rsd
.wall_clock
- start_time
) > rs
->cpu_limit
) {
182 double stop_time
= rpd
.utime
+ rpd
.stime
- (rsd
.wall_clock
- start_time
) * rs
->cpu_limit
;
183 if (stop_time
> 0.0) {
185 if (stop_time
>= 1.0) {
186 sleep((int)stop_time
);
187 stop_time
-= (int)stop_time
;
189 usleep((int)(stop_time
*1e6
));
195 usleep(rs
->interval
);
197 if (ret
< 0) rr
->error
|= 1;
200 if (is_killed
) rr
->error
|= 2;
202 run_get_dynamic_sys_info(&rsd
);
203 rr
->retval
= WEXITSTATUS(status
);
204 rr
->rtime
= rsd
.wall_clock
- start_time
;
205 rr
->utime
= (is_killed
)? rpd
.utime
: time_used
.tms_cutime
/ 100.0;
206 rr
->stime
= (is_killed
)? rpd
.stime
: time_used
.tms_cstime
/ 100.0;
207 rr
->avg_rss
= sum_rss
/ (rpd
.utime
+ rpd
.stime
);
208 rr
->avg_vsize
= sum_vsize
/ (rpd
.utime
+ rpd
.stime
);
210 pthread_join(outid
, 0);
211 pthread_join(errid
, 0);
215 char **true_argv
= (char**)malloc(sizeof(char*) * (argc
+ 1));
217 for (i
= 0; i
< argc
; ++i
) true_argv
[i
] = argv
[i
];
221 dup2(rs
->fd_out
[1], STDOUT_FILENO
);
222 close(rs
->fd_out
[0]); close(rs
->fd_out
[1]);
223 dup2(rs
->fd_err
[1], STDERR_FILENO
);
224 close(rs
->fd_err
[0]); close(rs
->fd_err
[1]);
226 if (execvp(true_argv
[0], true_argv
) == -1) {
227 fprintf(stderr
, "** fail to lauch the program '%s'!\n", true_argv
[0]);
235 static void show_sys_info(FILE *fpout
)
239 run_get_static_sys_info(&rss
);
240 run_get_dynamic_sys_info(&rsd
);
241 fprintf(fpout
, "\n");
242 fprintf(fpout
, "-- totalmem %16.3f kB\n", rss
.mem_total
/ 1024.0);
243 fprintf(fpout
, "-- available %16.3f kB\n", rsd
.mem_available
/ 1024.0);
244 fprintf(fpout
, "-- free %16.3f kB\n", rsd
.mem_free
/ 1024.0);
245 /* fprintf(fpout, "-- page size %16.3f kB\n", rss.page_size / 1024.0); */
246 /* fprintf(fpout, "-- virtual %16.3f kB\n", rss.swap_total / 1024.0); */
251 show_sys_info(stderr
);
252 fprintf(stderr
, "\n");
253 fprintf(stderr
, "Program: runit (a program launcher)\n");
254 fprintf(stderr
, "Usage: runit [run_options] command [command_options]\n\n");
255 fprintf(stderr
, "Options: -c FLOAT average CPU usage [1.0]\n");
256 fprintf(stderr
, " -m FLOAT lowest system memory [0.05]\n");
257 fprintf(stderr
, " -T INT timeout in second [0]\n");
258 fprintf(stderr
, " -M INT memoryout in kB [0]\n");
259 fprintf(stderr
, " -p STR log output and send to the background [null]\n\n");
263 int main_core(int argc
, char *argv
[], int offset
, RunStruct
*rs
)
267 run_upd_RunStruct(rs
);
268 rr
= runit(argc
-offset
, argv
+offset
, rs
);
270 fprintf(rs
->log_fp
, "-- CMD:");
271 for (i
= 0; i
!= argc
; ++i
)
272 fprintf(rs
->log_fp
, " %s", argv
[i
]);
273 fprintf(rs
->log_fp
, "\n");
274 show_sys_info(rs
->log_fp
);
275 fprintf(rs
->log_fp
, "\n");
276 fprintf(rs
->log_fp
, "-- retval %16d\n", rr
->retval
);
277 fprintf(rs
->log_fp
, "-- real %16.3f sec\n", rr
->rtime
);
278 fprintf(rs
->log_fp
, "-- user %16.3f sec\n", rr
->utime
);
279 fprintf(rs
->log_fp
, "-- sys %16.3f sec\n", rr
->stime
);
280 fprintf(rs
->log_fp
, "-- maxrss %16.3f kB\n", rr
->max_rss
/ 1024.0);
281 fprintf(rs
->log_fp
, "-- avgrss %16.3f kB\n", rr
->avg_rss
/ 1024.0);
282 fprintf(rs
->log_fp
, "-- maxvsize %16.3f kB\n", rr
->max_vsize
/ 1024.0);
283 fprintf(rs
->log_fp
, "-- avgvsize %16.3f kB\n", rr
->avg_vsize
/ 1024.0);
284 fprintf(rs
->log_fp
, "\n");
288 run_free_RunStruct(rs
);
292 int main(int argc
, char *argv
[])
296 if (argc
== 1) return usage();
297 rs
= run_new_RunStruct();
298 offset
= run_fill_RunStruct(argc
, argv
, rs
);
301 if (setsid() == -1) perror("Could mot become a session leader");
302 return main_core(argc
, argv
, offset
, rs
);
306 return main_core(argc
, argv
, offset
, rs
);
309 /*********************** standard getopt() ***********************************/
315 * Standard UNIX getopt function. Code is from BSD.
317 * Copyright (c) 1987-2002 The Regents of the University of California.
318 * All rights reserved.
320 * Redistribution and use in source and binary forms, with or without
321 * modification, are permitted provided that the following conditions are met:
323 * A. Redistributions of source code must retain the above copyright notice,
324 * this list of conditions and the following disclaimer.
325 * B. Redistributions in binary form must reproduce the above copyright notice,
326 * this list of conditions and the following disclaimer in the documentation
327 * and/or other materials provided with the distribution.
328 * C. Neither the names of the copyright holders nor the names of its
329 * contributors may be used to endorse or promote products derived from this
330 * software without specific prior written permission.
332 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
333 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
334 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
335 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
336 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
337 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
338 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
339 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
340 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
341 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
342 * POSSIBILITY OF SUCH DAMAGE.
345 /* #if !defined(lint)
346 * static char sccsid[] = "@(#)getopt.c 8.2 (Berkeley) 4/2/94";
350 int opterr
= 1, /* if error message should be printed */
351 optind
= 1, /* index into parent argv vector */
352 optopt
, /* character checked for validity */
353 optreset
; /* reset getopt */
354 char *optarg
; /* argument associated with option */
356 #define BADCH (int)'?'
357 #define BADARG (int)':'
362 * Parse argc/argv argument vector.
364 int getopt_standard(int nargc
, char * const *nargv
, const char *ostr
)
366 static char *place
= EMSG
; /* option letter processing */
367 char *oli
; /* option letter list index */
369 if (optreset
|| !*place
) { /* update scanning pointer */
371 if (optind
>= nargc
|| *(place
= nargv
[optind
]) != '-') {
375 if (place
[1] && *++place
== '-') { /* found "--" */
380 } /* option letter okay? */
381 if ((optopt
= (int)*place
++) == (int)':' ||
382 !(oli
= strchr(ostr
, optopt
))) {
384 * if the user didn't specify '-' as an option,
385 * assume it means EOF.
387 if (optopt
== (int)'-')
391 if (opterr
&& *ostr
!= ':')
392 (void)fprintf(stderr
,
393 "%s: illegal option -- %c\n", __FILE__
, optopt
);
396 if (*++oli
!= ':') { /* don't need argument */
401 else { /* need an argument */
402 if (*place
) /* no white space */
404 else if (nargc
<= ++optind
) { /* no arg */
409 (void)fprintf(stderr
,
410 "%s: option requires an argument -- %c\n",
414 else /* white space */
415 optarg
= nargv
[optind
];
419 return (optopt
); /* dump back option letter */