Mercurial > projects > dstress
annotate crashRun.c @ 1607:1bbcc6407d4b
Update module statement for renamed tests.
author | Christian Kamm <kamm incasoftware de> |
---|---|
date | Mon, 13 Apr 2009 13:48:46 +0200 |
parents | 37d80331f28f |
children |
rev | line source |
---|---|
490 | 1 /* |
545 | 2 * crashRun - execute command with restricted CPU time and memory usage |
490 | 3 * |
502 | 4 * Copyright (C) |
940 | 5 * 2005, 2006 Thomas Kuehne <thomas@kuehne.cn> |
6 * 2005 Anders F Björrklund <afb@algonet.se> (BSD) | |
7 * 2005 Stewart Gordon <smjg_1998@yahoo.com> (Windows) | |
490 | 8 * |
9 * This program is free software; you can redistribute it and/or modify | |
10 * it under the terms of the GNU General Public License as published by | |
11 * the Free Software Foundation; either version 2 of the License, or | |
12 * (at your option) any later version. | |
13 * | |
14 * This program is distributed in the hope that it will be useful, | |
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 * GNU General Public License for more details. | |
18 * | |
19 * You should have received a copy of the GNU General Public License | |
20 * along with this program; if not, write to the Free Software | |
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
22 * | |
23 * $HeadURL$ | |
24 * $Date$ | |
25 * $Author$ | |
26 * | |
27 */ | |
28 | |
498 | 29 #include <errno.h> |
30 #include <string.h> | |
31 #include <stdlib.h> | |
32 #include <stdio.h> | |
545 | 33 #include <signal.h> |
498 | 34 |
940 | 35 #undef WAIT_GUARD |
36 #define WAIT_GUARD 3 | |
37 | |
38 /* time-out in seconds | |
39 * Posix: cpu time(timeOut) and system time(timeOut * WAIT_GUARD) | |
40 * Windows: system time(timeOut) | |
41 */ | |
42 long int timeOut; | |
43 | |
44 /* max memory usage in megabytes (Posix only) */ | |
45 long int memoryLimit; | |
498 | 46 |
716 | 47 /* identify system API */ |
940 | 48 #if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE) |
49 #define USE_POSIX 1 | |
50 #endif | |
51 | |
52 #if defined(__GNU_LIBRARY__) || defined(__GLIBC__) | |
53 #define USE_POSIX 1 | |
498 | 54 #endif |
55 | |
684 | 56 #if defined(linux) || defined(__FreeBsd__) || defined(__OpenBSD__) |
940 | 57 #define USE_POSIX 1 |
490 | 58 #endif |
502 | 59 |
490 | 60 #if defined(__APPLE__) && defined(__MACH__) |
940 | 61 #define USE_POSIX 1 |
490 | 62 #endif |
63 | |
545 | 64 #if !defined(USE_POSIX) && \ |
940 | 65 (defined(WINDOWS) || defined(WIN) || defined(WINVER) || defined(WIN32) \ |
66 || defined(WIN64)) | |
67 #define USE_WINDOWS 1 | |
545 | 68 #endif |
498 | 69 |
545 | 70 |
71 /* is the environment sane? */ | |
72 #if defined(USE_POSIX) && defined(USE_WINDOWS) | |
73 #error USE_WINDOWS and USE_POSIX are defined | |
74 #endif | |
75 | |
76 #if !defined(USE_POSIX) && !defined(USE_WINDOWS) | |
77 #error neither USE_POSIX nor USE_WINDOWS are defined | |
78 #endif | |
79 | |
80 | |
81 /* API inludes and config */ | |
490 | 82 #ifdef USE_POSIX |
545 | 83 #define USE_POSIX_LIMITS |
84 #include <sys/types.h> | |
490 | 85 #include <unistd.h> |
86 #include <sys/wait.h> | |
545 | 87 static pid_t pID; |
88 #endif | |
490 | 89 |
545 | 90 #ifdef USE_POSIX_LIMITS |
91 #ifndef USE_POSIX | |
92 #error USE_POSIX_LIMITS requires USE_POSIX | |
93 #endif | |
94 #include <sys/resource.h> | |
502 | 95 #include <sys/types.h> |
96 #endif | |
97 | |
940 | 98 #ifdef USE_WINDOWS |
99 #include <windows.h> | |
100 #define snprintf _snprintf | |
101 #endif | |
545 | 102 |
940 | 103 |
923 | 104 |
940 | 105 #ifdef USE_POSIX |
495 | 106 |
545 | 107 void handleSignal(int signalID){ |
108 if( signalID==SIGALRM | |
498 | 109 #ifdef SIGXCPU |
545 | 110 || signalID==SIGXCPU |
498 | 111 #endif |
545 | 112 ) |
940 | 113 printf("EXIT CODE: signal %d (time-out after CPU/total %li/%li seconds)\n", |
114 signalID, timeOut, timeOut * WAIT_GUARD); | |
545 | 115 else |
940 | 116 printf("EXIT CODE: signal %d, errno %d\n", signalID, errno); |
498 | 117 |
490 | 118 fflush(stdout); |
119 fflush(stderr); | |
545 | 120 |
502 | 121 kill(-pID, SIGTERM); |
122 sleep(1); | |
495 | 123 kill(-pID, SIGKILL); |
490 | 124 |
545 | 125 exit(EXIT_FAILURE); |
126 } | |
127 | |
128 void setupLimits(){ | |
129 struct rlimit limit; | |
130 | |
940 | 131 limit.rlim_cur = timeOut; |
132 limit.rlim_max = timeOut; | |
545 | 133 if(0!=setrlimit(RLIMIT_CPU, &limit)){ |
134 fprintf(stderr, "failed to set cpu limit [%d]\n", errno); | |
498 | 135 exit(EXIT_FAILURE); |
545 | 136 } |
137 | |
940 | 138 limit.rlim_cur = memoryLimit * 1024L * 1024L; |
139 limit.rlim_max = memoryLimit * 1024L * 1024L; | |
545 | 140 #ifdef RLIMIT_AS |
141 if(0!=setrlimit(RLIMIT_AS, &limit)){ | |
940 | 142 fprintf(stderr, "failed to set mem limit (AS) %s [%d]\n", strerror(errno), errno); |
545 | 143 exit(EXIT_FAILURE); |
498 | 144 } |
545 | 145 #endif |
146 | |
147 if(0!=setrlimit(RLIMIT_DATA, &limit)){ | |
940 | 148 fprintf(stderr, "failed to set mem limit (DATA) %s [%d]\n", strerror(errno), errno); |
545 | 149 exit(EXIT_FAILURE); |
150 } | |
151 | |
152 if(0!=setrlimit(RLIMIT_RSS, &limit)){ | |
940 | 153 fprintf(stderr, "failed to set mem limit (RSS) %s [%d]\n", strerror(errno), errno); |
545 | 154 exit(EXIT_FAILURE); |
155 } | |
156 #if defined(RLIMIT_MEMLOCK) && !defined(linux) | |
157 if(0!=setrlimit(RLIMIT_MEMLOCK, &limit)){ | |
940 | 158 fprintf(stderr, "failed to set mem limit (MEMLOCK): %s [%d]\n", strerror(errno), errno); |
545 | 159 exit(EXIT_FAILURE); |
160 } | |
161 #endif | |
490 | 162 } |
163 | |
545 | 164 void setupHandlers(){ |
165 #ifdef SIGHUP | |
166 signal(SIGHUP, &handleSignal); | |
167 #endif | |
168 signal(SIGINT, &handleSignal); | |
169 #ifdef SIGQUIT | |
170 signal(SIGQUIT, &handleSignal); | |
171 #endif | |
172 signal(SIGILL, &handleSignal); | |
173 #ifdef SIGTRAP | |
174 signal(SIGTRAP, &handleSignal); | |
175 #endif | |
176 signal(SIGABRT, &handleSignal); | |
177 #ifdef SIGIOT | |
178 signal(SIGIOT, &handleSignal); | |
179 #endif | |
180 #ifdef SIGBUS | |
181 signal(SIGBUS, &handleSignal); | |
182 #endif | |
183 signal(SIGFPE, &handleSignal); | |
184 #ifdef SIGUSR1 | |
185 signal(SIGUSR1, &handleSignal); | |
186 #endif | |
187 signal(SIGSEGV, &handleSignal); | |
188 #ifdef SIGUSR2 | |
189 signal(SIGUSR2, &handleSignal); | |
190 #endif | |
191 #ifdef SIGPIPE | |
192 signal(SIGPIPE, &handleSignal); | |
193 #endif | |
194 signal(SIGALRM, &handleSignal); | |
195 signal(SIGTERM, &handleSignal); | |
196 #ifdef SIGSTKFLT | |
197 signal(SIGSTKFLT, &handleSignal); | |
198 #endif | |
199 #ifdef SIGTSTP | |
200 signal(SIGTSTP, &handleSignal); | |
201 #endif | |
202 #ifdef SIGXCPU | |
203 signal(SIGXCPU, &handleSignal); | |
204 #endif | |
205 #ifdef SIGXFSZ | |
206 signal(SIGXFSZ, &handleSignal); | |
207 #endif | |
208 #ifdef SIGVTALRM | |
209 signal(SIGVTALRM, &handleSignal); | |
210 #endif | |
211 #ifdef SIGSYS | |
212 signal(SIGSYS, &handleSignal); | |
213 #endif | |
940 | 214 } |
545 | 215 #endif /* USE_POSIX */ |
923 | 216 |
545 | 217 char* reconstructCmd(int argc, char** argv){ |
684 | 218 size_t cmdLen=1; |
219 size_t tmpLen; | |
220 size_t i; | |
221 char* tmp; | |
940 | 222 char* cmd; |
545 | 223 |
224 for(i=0; i<argc; i++){ | |
225 cmdLen+=strlen(argv[i]); | |
971
8da09834526d
* Valgrind support is now part of dstress.c instead of crashRun.c
thomask
parents:
969
diff
changeset
|
226 cmdLen+=1; |
502 | 227 } |
545 | 228 |
1205 | 229 cmd = (char*) malloc(++cmdLen); |
940 | 230 if(!cmd){ |
231 fprintf(stderr, "failed to allocate enough memory"); | |
232 exit(EXIT_FAILURE); | |
233 } | |
923 | 234 |
545 | 235 *cmd = '\x00'; |
684 | 236 tmp = cmd; |
495 | 237 |
545 | 238 for(i=0; i<argc; i++){ |
971
8da09834526d
* Valgrind support is now part of dstress.c instead of crashRun.c
thomask
parents:
969
diff
changeset
|
239 tmpLen = snprintf(tmp, cmdLen, "%s ", argv[i]); |
684 | 240 tmp += tmpLen; |
241 cmdLen -= tmpLen; | |
545 | 242 } |
243 return cmd; | |
244 } | |
490 | 245 |
545 | 246 int main(int argc, char** argv){ |
940 | 247 char* cmd; |
248 char* end; | |
249 | |
250 if(argc<4){ | |
251 fprintf(stderr, "crashRun <timeOut (s)> <maxMemory (MB)> <command> [<command arg> ...]\n"); | |
252 return EXIT_FAILURE; | |
253 } | |
254 timeOut = strtol(argv[1], &end, 10); | |
255 if(*end){ | |
256 fprintf(stderr, "the timeOut argument contains the illegal character: %c (0x%X)", *end, *end); | |
257 return EXIT_FAILURE; | |
258 }else if(timeOut < 1){ | |
259 fprintf(stderr, "minimum timeOut is 1 second, got %li seconds\n", timeOut); | |
545 | 260 return EXIT_FAILURE; |
261 } | |
940 | 262 |
263 memoryLimit = strtol(argv[2], &end, 10); | |
264 if(*end){ | |
265 fprintf(stderr, "the maxMemory argument contains the illegal character: %c (0x%X)", *end, *end); | |
266 return EXIT_FAILURE; | |
267 }else if(memoryLimit < 1){ | |
268 fprintf(stderr, "minimum memoryLimit is 1MB second, got %li MB\n", memoryLimit); | |
269 return EXIT_FAILURE; | |
270 } | |
271 cmd = reconstructCmd(argc-3, argv+3); | |
272 | |
273 #ifdef DEBUG | |
274 printf("cmd[%li sec, %li MB]: %s \n", timeOut, memoryLimit, cmd); | |
275 #endif | |
545 | 276 |
277 #ifdef USE_POSIX | |
278 setupLimits(); | |
279 pID = fork(); | |
280 if(pID == 0){ | |
281 /* child */ | |
282 pID=setsid(); | |
498 | 283 printf("EXIT CODE: %d\n", system(cmd)); |
545 | 284 }else if(pID < 0){ |
285 fprintf(stderr, "failed to fork\n"); | |
490 | 286 return EXIT_FAILURE; |
287 }else{ | |
545 | 288 /* parent */ |
289 setupHandlers(); | |
290 #if !(defined(USE_POSIX_LIMITS) && defined(SIGXCPU)) | |
940 | 291 alarm(timeOut); |
292 #else | |
293 /* safe guard against childs without CPU usage */ | |
294 alarm(timeOut * WAIT_GUARD); | |
502 | 295 #endif |
490 | 296 wait(NULL); |
297 } | |
298 return EXIT_SUCCESS; | |
940 | 299 #elif USE_WINDOWS |
300 /* BUG: maxMemory not implemented */ | |
301 | |
302 PROCESS_INFORMATION processInfo; | |
303 STARTUPINFO startupInfo; | |
304 SECURITY_ATTRIBUTES sa = { | |
305 sizeof(SECURITY_ATTRIBUTES), NULL, TRUE | |
306 }; | |
307 unsigned long exitCode; | |
308 long int timeLeft = timeOut; /* time limit in iterations of WFX loop */ | |
309 | |
310 memset(&processInfo, 0, sizeof(PROCESS_INFORMATION)); | |
311 memset(&startupInfo, 0, sizeof(STARTUPINFO)); | |
312 startupInfo.cb = sizeof(STARTUPINFO); | |
313 | |
314 if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, | |
315 &startupInfo, &processInfo)) { | |
316 void *message; | |
317 | |
318 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | |
319 | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, | |
320 (char*) &message, 0, NULL); | |
490 | 321 |
940 | 322 /* this should never happen */ |
323 fprintf(stderr, "ERROR running %s:\n", cmd); | |
324 fprintf(stderr, "%s\n", message); | |
325 LocalFree((HLOCAL) message); | |
326 return RAND_MAX; | |
327 } | |
328 | |
329 /* wait for exit */ | |
330 while (TRUE) { | |
331 Sleep(1000); | |
332 GetExitCodeProcess(processInfo.hProcess, &exitCode); | |
333 if (exitCode == 0x103) { | |
334 if (--timeLeft == 0) { | |
335 TerminateProcess(processInfo.hProcess, EXIT_FAILURE); | |
336 printf("EXIT CODE: timeout after %li seconds\n", timeOut); | |
337 Sleep(100); | |
338 return EXIT_SUCCESS; | |
339 } | |
340 } else { | |
341 printf("EXIT CODE: %i\n", exitCode); | |
342 return EXIT_SUCCESS; | |
343 } | |
344 } | |
345 | |
346 fprintf(stderr, "crashRun: BUG\n"); | |
347 return EXIT_FAILURE; | |
348 #else | |
349 | |
350 #error no implmentation for your system found (supported: Posix, Windows) | |
490 | 351 |
352 #endif /* USE_POSIX else */ | |
545 | 353 } |