Description:
[grader] box.cc now reports running status when die git-svn-id: http://theory.cpe.ku.ac.th/grader/judge/trunk/scripts@172 6386c4cd-e34a-4fa8-8920-d93eb39b512e
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r46:31f3935d33aa - - 2 files changed: 61 inserted, 47 deleted

@@ -9,141 +9,159
9
9
10 #include <errno.h>
10 #include <errno.h>
11 #include <stdio.h>
11 #include <stdio.h>
12 #include <fcntl.h>
12 #include <fcntl.h>
13 #include <stdlib.h>
13 #include <stdlib.h>
14 #include <string.h>
14 #include <string.h>
15 #include <stdarg.h>
15 #include <stdarg.h>
16 #include <unistd.h>
16 #include <unistd.h>
17 #include <getopt.h>
17 #include <getopt.h>
18 #include <time.h>
18 #include <time.h>
19 #include <sys/wait.h>
19 #include <sys/wait.h>
20 #include <sys/user.h>
20 #include <sys/user.h>
21 #include <sys/time.h>
21 #include <sys/time.h>
22 #include <sys/ptrace.h>
22 #include <sys/ptrace.h>
23 #include <sys/signal.h>
23 #include <sys/signal.h>
24 #include <sys/sysinfo.h>
24 #include <sys/sysinfo.h>
25 #include <sys/syscall.h>
25 #include <sys/syscall.h>
26 #include <sys/resource.h>
26 #include <sys/resource.h>
27
27
28 #define NONRET __attribute__((noreturn))
28 #define NONRET __attribute__((noreturn))
29 #define UNUSED __attribute__((unused))
29 #define UNUSED __attribute__((unused))
30
30
31 static int filter_syscalls; /* 0=off, 1=liberal, 2=totalitarian */
31 static int filter_syscalls; /* 0=off, 1=liberal, 2=totalitarian */
32 static int timeout;
32 static int timeout;
33 static int pass_environ;
33 static int pass_environ;
34 static int use_wall_clock;
34 static int use_wall_clock;
35 static int file_access;
35 static int file_access;
36 static int verbose;
36 static int verbose;
37 static int memory_limit;
37 static int memory_limit;
38 static int allow_times;
38 static int allow_times;
39 static char *redir_stdin, *redir_stdout;
39 static char *redir_stdin, *redir_stdout;
40 static char *set_cwd;
40 static char *set_cwd;
41
41
42 static pid_t box_pid;
42 static pid_t box_pid;
43 static int is_ptraced;
43 static int is_ptraced;
44 static volatile int timer_tick;
44 static volatile int timer_tick;
45 static time_t start_time;
45 static time_t start_time;
46 static int ticks_per_sec;
46 static int ticks_per_sec;
47
47
48 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ > 0
48 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ > 0
49 /* glibc 2.1 or newer -> has lseek64 */
49 /* glibc 2.1 or newer -> has lseek64 */
50 #define long_seek(f,o,w) lseek64(f,o,w)
50 #define long_seek(f,o,w) lseek64(f,o,w)
51 #else
51 #else
52 /* Touching clandestine places in glibc */
52 /* Touching clandestine places in glibc */
53 extern loff_t llseek(int fd, loff_t pos, int whence);
53 extern loff_t llseek(int fd, loff_t pos, int whence);
54 #define long_seek(f,o,w) llseek(f,o,w)
54 #define long_seek(f,o,w) llseek(f,o,w)
55 #endif
55 #endif
56
56
57 + int max_mem_used = 0;
58 +
59 + void print_running_stat(double wall_time,
60 + double user_time,
61 + double system_time,
62 + int mem_usage)
63 + {
64 + fprintf(stderr,"%.4lfr%.4lfu%.4lfs%dm\n",
65 + wall_time, user_time, system_time, mem_usage);
66 + }
67 +
57 static void NONRET
68 static void NONRET
58 box_exit(void)
69 box_exit(void)
59 {
70 {
60 - if (box_pid > 0)
71 + if (box_pid > 0) {
61 - {
72 + if (is_ptraced)
62 - if (is_ptraced)
73 + ptrace(PTRACE_KILL, box_pid);
63 - ptrace(PTRACE_KILL, box_pid);
74 + kill(-box_pid, SIGKILL);
64 - kill(-box_pid, SIGKILL);
75 + kill(box_pid, SIGKILL);
65 - kill(box_pid, SIGKILL);
76 + }
66 - }
67 - exit(1);
68 - }
69
77
70 - static void
78 + struct timeval total;
71 - box_kill(void)
79 + int wall;
72 - {
80 + struct rusage rus;
73 - if (box_pid > 0)
81 + int stat;
74 - {
82 + pid_t p;
75 - if (is_ptraced)
83 +
76 - ptrace(PTRACE_KILL, box_pid);
84 + // wait so that we can get information
77 - kill(-box_pid, SIGKILL);
85 + p = wait4(box_pid, &stat, WUNTRACED, &rus);
78 - kill(box_pid, SIGKILL);
86 + if (p < 0) {
79 - }
87 + fprintf(stderr,"wait4: error\n");
88 + print_running_stat(0,0,0,max_mem_used);
89 + } else if (p != box_pid) {
90 + fprintf(stderr,"wait4: unknown pid %d exited!\n", p);
91 + print_running_stat(0,0,0,max_mem_used);
92 + } else {
93 + if (!WIFEXITED(stat))
94 + fprintf(stderr,"wait4: unknown status\n");
95 + struct timeval total;
96 + int wall;
97 + wall = time(NULL) - start_time;
98 + timeradd(&rus.ru_utime, &rus.ru_stime, &total);
99 +
100 + print_running_stat((double)wall,
101 + (double) rus.ru_utime.tv_sec +
102 + ((double) rus.ru_utime.tv_usec/1000000.0),
103 + (double) rus.ru_stime.tv_sec +
104 + ((double) rus.ru_stime.tv_usec/1000000.0),
105 + max_mem_used);
106 + }
107 + exit(1);
80 }
108 }
81
109
82 static void NONRET __attribute__((format(printf,1,2)))
110 static void NONRET __attribute__((format(printf,1,2)))
83 die(char *msg, ...)
111 die(char *msg, ...)
84 {
112 {
85 va_list args;
113 va_list args;
86 va_start(args, msg);
114 va_start(args, msg);
87 vfprintf(stderr, msg, args);
115 vfprintf(stderr, msg, args);
88 fputc('\n', stderr);
116 fputc('\n', stderr);
89 box_exit();
117 box_exit();
90 }
118 }
91
119
92 - static void __attribute__((format(printf,1,2)))
93 - die_report(char *msg, ...)
94 - {
95 - va_list args;
96 - va_start(args, msg);
97 - vfprintf(stderr, msg, args);
98 - fputc('\n', stderr);
99 - box_kill();
100 - }
101 -
102 static void __attribute__((format(printf,1,2)))
120 static void __attribute__((format(printf,1,2)))
103 log(char *msg, ...)
121 log(char *msg, ...)
104 {
122 {
105 va_list args;
123 va_list args;
106 va_start(args, msg);
124 va_start(args, msg);
107 if (verbose)
125 if (verbose)
108 {
126 {
109 vfprintf(stderr, msg, args);
127 vfprintf(stderr, msg, args);
110 fflush(stderr);
128 fflush(stderr);
111 }
129 }
112 va_end(args);
130 va_end(args);
113 }
131 }
114
132
115 static void
133 static void
116 valid_filename(unsigned long addr)
134 valid_filename(unsigned long addr)
117 {
135 {
118 char namebuf[4096], *p, *end;
136 char namebuf[4096], *p, *end;
119 static int mem_fd;
137 static int mem_fd;
120
138
121 if (!file_access)
139 if (!file_access)
122 die("File access forbidden.");
140 die("File access forbidden.");
123 if (file_access >= 9)
141 if (file_access >= 9)
124 return;
142 return;
125
143
126 if (!mem_fd)
144 if (!mem_fd)
127 {
145 {
128 sprintf(namebuf, "/proc/%d/mem", (int) box_pid);
146 sprintf(namebuf, "/proc/%d/mem", (int) box_pid);
129 mem_fd = open(namebuf, O_RDONLY);
147 mem_fd = open(namebuf, O_RDONLY);
130 if (mem_fd < 0)
148 if (mem_fd < 0)
131 die("open(%s): %m", namebuf);
149 die("open(%s): %m", namebuf);
132 }
150 }
133 p = end = namebuf;
151 p = end = namebuf;
134 do
152 do
135 {
153 {
136 if (p >= end)
154 if (p >= end)
137 {
155 {
138 int remains = PAGE_SIZE - (addr & (PAGE_SIZE-1));
156 int remains = PAGE_SIZE - (addr & (PAGE_SIZE-1));
139 int l = namebuf + sizeof(namebuf) - end;
157 int l = namebuf + sizeof(namebuf) - end;
140 if (l > remains)
158 if (l > remains)
141 l = remains;
159 l = remains;
142 if (!l)
160 if (!l)
143 die("Access to file with name too long.");
161 die("Access to file with name too long.");
144 if (long_seek(mem_fd, addr, SEEK_SET) < 0)
162 if (long_seek(mem_fd, addr, SEEK_SET) < 0)
145 die("long_seek(mem): %m");
163 die("long_seek(mem): %m");
146 remains = read(mem_fd, end, l);
164 remains = read(mem_fd, end, l);
147 if (remains < 0)
165 if (remains < 0)
148 die("read(mem): %m");
166 die("read(mem): %m");
149 if (!remains)
167 if (!remains)
@@ -304,102 +322,100
304 /* Interrupts are fatal, so no synchronization requirements. */
322 /* Interrupts are fatal, so no synchronization requirements. */
305 die("Interrupted.");
323 die("Interrupted.");
306 }
324 }
307
325
308 static void
326 static void
309 check_timeout(void)
327 check_timeout(void)
310 {
328 {
311 int sec;
329 int sec;
312
330
313 if (use_wall_clock)
331 if (use_wall_clock)
314 sec = time(NULL) - start_time;
332 sec = time(NULL) - start_time;
315 else
333 else
316 {
334 {
317 char buf[4096], *x;
335 char buf[4096], *x;
318 int c, utime, stime;
336 int c, utime, stime;
319 static int proc_status_fd;
337 static int proc_status_fd;
320 if (!proc_status_fd)
338 if (!proc_status_fd)
321 {
339 {
322 sprintf(buf, "/proc/%d/stat", (int) box_pid);
340 sprintf(buf, "/proc/%d/stat", (int) box_pid);
323 proc_status_fd = open(buf, O_RDONLY);
341 proc_status_fd = open(buf, O_RDONLY);
324 if (proc_status_fd < 0)
342 if (proc_status_fd < 0)
325 die("open(%s): %m", buf);
343 die("open(%s): %m", buf);
326 }
344 }
327 lseek(proc_status_fd, 0, SEEK_SET);
345 lseek(proc_status_fd, 0, SEEK_SET);
328 if ((c = read(proc_status_fd, buf, sizeof(buf)-1)) < 0)
346 if ((c = read(proc_status_fd, buf, sizeof(buf)-1)) < 0)
329 die("read on /proc/$pid/stat: %m");
347 die("read on /proc/$pid/stat: %m");
330 if (c >= (int) sizeof(buf) - 1)
348 if (c >= (int) sizeof(buf) - 1)
331 die("/proc/$pid/stat too long");
349 die("/proc/$pid/stat too long");
332 buf[c] = 0;
350 buf[c] = 0;
333 x = buf;
351 x = buf;
334 while (*x && *x != ' ')
352 while (*x && *x != ' ')
335 x++;
353 x++;
336 while (*x == ' ')
354 while (*x == ' ')
337 x++;
355 x++;
338 if (*x++ != '(')
356 if (*x++ != '(')
339 die("proc syntax error 1");
357 die("proc syntax error 1");
340 while (*x && (*x != ')' || x[1] != ' '))
358 while (*x && (*x != ')' || x[1] != ' '))
341 x++;
359 x++;
342 while (*x == ')' || *x == ' ')
360 while (*x == ')' || *x == ' ')
343 x++;
361 x++;
344 if (sscanf(x, "%*c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d %d", &utime, &stime) != 2)
362 if (sscanf(x, "%*c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d %d", &utime, &stime) != 2)
345 die("proc syntax error 2");
363 die("proc syntax error 2");
346 //printf("%s - %d\n",x,ticks_per_sec);
364 //printf("%s - %d\n",x,ticks_per_sec);
347 sec = (utime + stime + ticks_per_sec-1)/ticks_per_sec;
365 sec = (utime + stime + ticks_per_sec-1)/ticks_per_sec;
348 }
366 }
349 if (verbose > 1)
367 if (verbose > 1)
350 fprintf(stderr, "[timecheck: %d seconds]\n", sec);
368 fprintf(stderr, "[timecheck: %d seconds]\n", sec);
351 if (sec > timeout) {
369 if (sec > timeout) {
352 - die_report("Time limit exceeded.");
370 + die("Time limit exceeded.");
353 }
371 }
354 }
372 }
355
373
356 - int max_mem_used = 0;
357 -
358 static void
374 static void
359 check_memory_usage()
375 check_memory_usage()
360 {
376 {
361 char proc_fname[100];
377 char proc_fname[100];
362 sprintf(proc_fname,"/proc/%d/statm",box_pid);
378 sprintf(proc_fname,"/proc/%d/statm",box_pid);
363 //printf("proc fname: %s\n",proc_fname);
379 //printf("proc fname: %s\n",proc_fname);
364 FILE *fp = fopen(proc_fname,"r");
380 FILE *fp = fopen(proc_fname,"r");
365 if(fp!=NULL) {
381 if(fp!=NULL) {
366 char line[1000];
382 char line[1000];
367 fgets(line,999,fp);
383 fgets(line,999,fp);
368 //printf("%s\n",line);
384 //printf("%s\n",line);
369 int m;
385 int m;
370
386
371 if(sscanf(line,"%d",&m)==1)
387 if(sscanf(line,"%d",&m)==1)
372 if(m>max_mem_used)
388 if(m>max_mem_used)
373 max_mem_used = m;
389 max_mem_used = m;
374
390
375 fclose(fp);
391 fclose(fp);
376 }
392 }
377 }
393 }
378
394
379 static void
395 static void
380 boxkeeper(void)
396 boxkeeper(void)
381 {
397 {
382 int syscall_count = 0;
398 int syscall_count = 0;
383 struct sigaction sa;
399 struct sigaction sa;
384
400
385 is_ptraced = 1;
401 is_ptraced = 1;
386 bzero(&sa, sizeof(sa));
402 bzero(&sa, sizeof(sa));
387 sa.sa_handler = signal_int;
403 sa.sa_handler = signal_int;
388 sigaction(SIGINT, &sa, NULL);
404 sigaction(SIGINT, &sa, NULL);
389 start_time = time(NULL);
405 start_time = time(NULL);
390 ticks_per_sec = sysconf(_SC_CLK_TCK);
406 ticks_per_sec = sysconf(_SC_CLK_TCK);
391 if (ticks_per_sec <= 0)
407 if (ticks_per_sec <= 0)
392 die("Invalid ticks_per_sec!");
408 die("Invalid ticks_per_sec!");
393
409
394 check_memory_usage();
410 check_memory_usage();
395
411
396 sa.sa_handler = signal_alarm;
412 sa.sa_handler = signal_alarm;
397 sigaction(SIGALRM, &sa, NULL);
413 sigaction(SIGALRM, &sa, NULL);
398 //alarm(1);
414 //alarm(1);
399
415
400 struct itimerval val;
416 struct itimerval val;
401 val.it_interval.tv_sec = 0;
417 val.it_interval.tv_sec = 0;
402 val.it_interval.tv_usec = 50000;
418 val.it_interval.tv_usec = 50000;
403 val.it_value.tv_sec = 0;
419 val.it_value.tv_sec = 0;
404 val.it_value.tv_usec = 50000;
420 val.it_value.tv_usec = 50000;
405 setitimer(ITIMER_REAL,&val,NULL);
421 setitimer(ITIMER_REAL,&val,NULL);
@@ -407,129 +423,127
407 /*
423 /*
408 --- add alarm handler no matter what..
424 --- add alarm handler no matter what..
409 if (timeout)
425 if (timeout)
410 {
426 {
411 sa.sa_handler = signal_alarm;
427 sa.sa_handler = signal_alarm;
412 sigaction(SIGALRM, &sa, NULL);
428 sigaction(SIGALRM, &sa, NULL);
413 alarm(1);
429 alarm(1);
414 }
430 }
415 */
431 */
416
432
417 for(;;)
433 for(;;)
418 {
434 {
419 struct rusage rus;
435 struct rusage rus;
420 int stat;
436 int stat;
421 pid_t p;
437 pid_t p;
422
438
423 if (timer_tick)
439 if (timer_tick)
424 {
440 {
425 check_timeout();
441 check_timeout();
426 check_memory_usage();
442 check_memory_usage();
427 timer_tick = 0;
443 timer_tick = 0;
428 }
444 }
429 p = wait4(box_pid, &stat, WUNTRACED, &rus);
445 p = wait4(box_pid, &stat, WUNTRACED, &rus);
430
446
431 if (p < 0)
447 if (p < 0)
432 {
448 {
433 if (errno == EINTR)
449 if (errno == EINTR)
434 continue;
450 continue;
435 die("wait4: %m");
451 die("wait4: %m");
436 }
452 }
437 if (p != box_pid)
453 if (p != box_pid)
438 die("wait4: unknown pid %d exited!", p);
454 die("wait4: unknown pid %d exited!", p);
439 if (WIFEXITED(stat))
455 if (WIFEXITED(stat))
440 {
456 {
441 struct timeval total;
457 struct timeval total;
442 int wall;
458 int wall;
443 wall = time(NULL) - start_time;
459 wall = time(NULL) - start_time;
444 timeradd(&rus.ru_utime, &rus.ru_stime, &total);
460 timeradd(&rus.ru_utime, &rus.ru_stime, &total);
445
461
446 box_pid = 0;
462 box_pid = 0;
447 if (WEXITSTATUS(stat))
463 if (WEXITSTATUS(stat))
448 fprintf(stderr,"Exited with error status %d.\n", WEXITSTATUS(stat));
464 fprintf(stderr,"Exited with error status %d.\n", WEXITSTATUS(stat));
449 else if ((use_wall_clock ? wall : total.tv_sec) > timeout)
465 else if ((use_wall_clock ? wall : total.tv_sec) > timeout)
450 fprintf(stderr,"Time limit exceeded.\n");
466 fprintf(stderr,"Time limit exceeded.\n");
451 else
467 else
452 // report OK and statistics
468 // report OK and statistics
453 fprintf(stderr,"OK\n");
469 fprintf(stderr,"OK\n");
454
470
455 - fprintf(stderr,"%dr%.4lfu%.4lfs%dm\n",
471 + print_running_stat((double) wall,
456 - wall,
472 + (double) rus.ru_utime.tv_sec +
457 - (double) rus.ru_utime.tv_sec +
473 + ((double) rus.ru_utime.tv_usec/1000000.0),
458 - ((double) rus.ru_utime.tv_usec/1000000.0),
474 + (double) rus.ru_stime.tv_sec +
459 - (double) rus.ru_stime.tv_sec +
475 + ((double) rus.ru_stime.tv_usec/1000000.0),
460 - ((double) rus.ru_stime.tv_usec/1000000.0),
476 + max_mem_used);
461 - max_mem_used);
462 /*
477 /*
463 (%.4lf sec real (%d), %d sec wall, %d syscalls, %d kb)\n",
478 (%.4lf sec real (%d), %d sec wall, %d syscalls, %d kb)\n",
464 (double) total.tv_sec + ((double)total.tv_usec / 1000000.0),
479 (double) total.tv_sec + ((double)total.tv_usec / 1000000.0),
465 (int) total.tv_usec,
480 (int) total.tv_usec,
466 wall,
481 wall,
467 syscall_count,
482 syscall_count,
468 max_mem_used);
483 max_mem_used);
469 */
484 */
470 exit(0);
485 exit(0);
471 }
486 }
472 if (WIFSIGNALED(stat))
487 if (WIFSIGNALED(stat))
473 {
488 {
474 box_pid = 0;
489 box_pid = 0;
475 fprintf(stderr,"Caught fatal signal %d.\n", WTERMSIG(stat));
490 fprintf(stderr,"Caught fatal signal %d.\n", WTERMSIG(stat));
476
491
477 struct timeval total;
492 struct timeval total;
478 int wall;
493 int wall;
479 wall = time(NULL) - start_time;
494 wall = time(NULL) - start_time;
480 timeradd(&rus.ru_utime, &rus.ru_stime, &total);
495 timeradd(&rus.ru_utime, &rus.ru_stime, &total);
481 - fprintf(stderr,"%dr%.4lfu%.4lfs%dm\n",
496 + print_running_stat((double) wall,
482 - wall,
497 + (double) rus.ru_utime.tv_sec +
483 - (double) rus.ru_utime.tv_sec +
498 + ((double) rus.ru_utime.tv_usec/1000000.0),
484 - ((double) rus.ru_utime.tv_usec/1000000.0),
499 + (double) rus.ru_stime.tv_sec +
485 - (double) rus.ru_stime.tv_sec +
500 + ((double) rus.ru_stime.tv_usec/1000000.0),
486 - ((double) rus.ru_stime.tv_usec/1000000.0),
501 + max_mem_used);
487 - max_mem_used);
488 exit(0);
502 exit(0);
489 }
503 }
490 if (WIFSTOPPED(stat))
504 if (WIFSTOPPED(stat))
491 {
505 {
492 int sig = WSTOPSIG(stat);
506 int sig = WSTOPSIG(stat);
493 if (sig == SIGTRAP)
507 if (sig == SIGTRAP)
494 {
508 {
495 struct user u;
509 struct user u;
496 static int stop_count = -1;
510 static int stop_count = -1;
497 if (ptrace(PTRACE_GETREGS, box_pid, NULL, &u) < 0)
511 if (ptrace(PTRACE_GETREGS, box_pid, NULL, &u) < 0)
498 die("ptrace(PTRACE_GETREGS): %m");
512 die("ptrace(PTRACE_GETREGS): %m");
499 stop_count++;
513 stop_count++;
500 if (!stop_count) /* Traceme request */
514 if (!stop_count) /* Traceme request */
501 log(">> Traceme request caught\n");
515 log(">> Traceme request caught\n");
502 else if (stop_count & 1) /* Syscall entry */
516 else if (stop_count & 1) /* Syscall entry */
503 {
517 {
504 log(">> Syscall %3ld (%08lx,%08lx,%08lx) ", u.regs.orig_eax, u.regs.ebx, u.regs.ecx, u.regs.edx);
518 log(">> Syscall %3ld (%08lx,%08lx,%08lx) ", u.regs.orig_eax, u.regs.ebx, u.regs.ecx, u.regs.edx);
505 syscall_count++;
519 syscall_count++;
506 if (!valid_syscall(&u))
520 if (!valid_syscall(&u))
507 {
521 {
508 /*
522 /*
509 * Unfortunately, PTRACE_KILL kills _after_ the syscall completes,
523 * Unfortunately, PTRACE_KILL kills _after_ the syscall completes,
510 * so we have to change it to something harmless (e.g., an undefined
524 * so we have to change it to something harmless (e.g., an undefined
511 * syscall) and make the program continue.
525 * syscall) and make the program continue.
512 */
526 */
513 unsigned int sys = u.regs.orig_eax;
527 unsigned int sys = u.regs.orig_eax;
514 u.regs.orig_eax = 0xffffffff;
528 u.regs.orig_eax = 0xffffffff;
515 if (ptrace(PTRACE_SETREGS, box_pid, NULL, &u) < 0)
529 if (ptrace(PTRACE_SETREGS, box_pid, NULL, &u) < 0)
516 die("ptrace(PTRACE_SETREGS): %m");
530 die("ptrace(PTRACE_SETREGS): %m");
517 die("Forbidden syscall %d.", sys);
531 die("Forbidden syscall %d.", sys);
518 }
532 }
519 }
533 }
520 else /* Syscall return */
534 else /* Syscall return */
521 log("= %ld\n", u.regs.eax);
535 log("= %ld\n", u.regs.eax);
522 ptrace(PTRACE_SYSCALL, box_pid, 0, 0);
536 ptrace(PTRACE_SYSCALL, box_pid, 0, 0);
523 }
537 }
524 else if (sig != SIGSTOP && sig != SIGXCPU && sig != SIGXFSZ)
538 else if (sig != SIGSTOP && sig != SIGXCPU && sig != SIGXFSZ)
525 {
539 {
526 log(">> Signal %d\n", sig);
540 log(">> Signal %d\n", sig);
527 ptrace(PTRACE_SYSCALL, box_pid, 0, sig);
541 ptrace(PTRACE_SYSCALL, box_pid, 0, sig);
528 }
542 }
529 else
543 else
530 die("Received signal %d.", sig);
544 die("Received signal %d.", sig);
531 }
545 }
532 else
546 else
533 die("wait4: unknown status %x, giving up!", stat);
547 die("wait4: unknown status %x, giving up!", stat);
534 }
548 }
535 }
549 }
@@ -196,97 +196,97
196 :exit_status= => nil,
196 :exit_status= => nil,
197 :memory_usage= => nil,
197 :memory_usage= => nil,
198 :save => nil})
198 :save => nil})
199 end
199 end
200
200
201 it "should clean up problem directory after running test request" do
201 it "should clean up problem directory after running test request" do
202 problem = stub(Problem,
202 problem = stub(Problem,
203 :id => 1, :name => 'test_normal')
203 :id => 1, :name => 'test_normal')
204 grader_should(:grade => 'test1_correct.c',
204 grader_should(:grade => 'test1_correct.c',
205 :on => problem,
205 :on => problem,
206 :with => 'in1.txt',
206 :with => 'in1.txt',
207 :and_report => {
207 :and_report => {
208 :graded_at= => nil,
208 :graded_at= => nil,
209 :compiler_message= => '',
209 :compiler_message= => '',
210 :grader_comment= => '',
210 :grader_comment= => '',
211 :running_stat= => nil,
211 :running_stat= => nil,
212 :output_file_name= => nil,
212 :output_file_name= => nil,
213 :running_time= => nil,
213 :running_time= => nil,
214 :exit_status= => nil,
214 :exit_status= => nil,
215 :memory_usage= => nil,
215 :memory_usage= => nil,
216 :save => nil})
216 :save => nil})
217 File.exists?(@config.user_result_dir + "/test_request/test_normal/test_cases/1/input-1.txt").should be_false
217 File.exists?(@config.user_result_dir + "/test_request/test_normal/test_cases/1/input-1.txt").should be_false
218 end
218 end
219
219
220 it "should compile test request with error and report compilation error" do
220 it "should compile test request with error and report compilation error" do
221 problem = stub(Problem,
221 problem = stub(Problem,
222 :id => 1, :name => 'test_normal')
222 :id => 1, :name => 'test_normal')
223 grader_should(:grade => 'test1_compile_error.c',
223 grader_should(:grade => 'test1_compile_error.c',
224 :on => problem,
224 :on => problem,
225 :with => 'in1.txt',
225 :with => 'in1.txt',
226 :and_report => {
226 :and_report => {
227 :graded_at= => nil,
227 :graded_at= => nil,
228 :compiler_message= => /.+/,
228 :compiler_message= => /.+/,
229 :grader_comment= => /[Cc]ompil.*error/,
229 :grader_comment= => /[Cc]ompil.*error/,
230 :running_stat= => '',
230 :running_stat= => '',
231 :save => nil})
231 :save => nil})
232 end
232 end
233
233
234 it "should report exit status" do
234 it "should report exit status" do
235 problem = stub(Problem,
235 problem = stub(Problem,
236 :id => 1, :name => 'test_normal')
236 :id => 1, :name => 'test_normal')
237 grader_should(:grade => 'add_nonzero_exit_status.c',
237 grader_should(:grade => 'add_nonzero_exit_status.c',
238 :on => problem,
238 :on => problem,
239 :with => 'in1.txt',
239 :with => 'in1.txt',
240 :and_report => {
240 :and_report => {
241 :graded_at= => nil,
241 :graded_at= => nil,
242 :compiler_message= => '',
242 :compiler_message= => '',
243 :grader_comment= => '',
243 :grader_comment= => '',
244 - :running_stat= => /[Ee]xit.*status.*10.*0\.0 sec/m,
244 + :running_stat= => /[Ee]xit.*status.*10.*0\.0\d* sec/m,
245 :output_file_name= => lambda { |fname|
245 :output_file_name= => lambda { |fname|
246 File.exists?(fname).should be_true
246 File.exists?(fname).should be_true
247 },
247 },
248 :running_time= => nil,
248 :running_time= => nil,
249 :exit_status= => /10/,
249 :exit_status= => /10/,
250 :memory_usage= => nil,
250 :memory_usage= => nil,
251 :save => nil})
251 :save => nil})
252 end
252 end
253
253
254 it "should produce running statistics for normal submission" do
254 it "should produce running statistics for normal submission" do
255 problem = stub(Problem,
255 problem = stub(Problem,
256 :id => 1, :name => 'test_normal')
256 :id => 1, :name => 'test_normal')
257 grader_should(:grade => 'test_run_stat.c',
257 grader_should(:grade => 'test_run_stat.c',
258 :on => problem,
258 :on => problem,
259 :with => 'in1.txt',
259 :with => 'in1.txt',
260 :and_report => {
260 :and_report => {
261 :graded_at= => nil,
261 :graded_at= => nil,
262 :compiler_message= => '',
262 :compiler_message= => '',
263 :grader_comment= => '',
263 :grader_comment= => '',
264 :running_stat= => nil,
264 :running_stat= => nil,
265 :output_file_name= => lambda { |fname|
265 :output_file_name= => lambda { |fname|
266 File.exists?(fname).should be_true
266 File.exists?(fname).should be_true
267 },
267 },
268 :running_time= => lambda { |t|
268 :running_time= => lambda { |t|
269 (t>=0.14) and (t<=0.16)
269 (t>=0.14) and (t<=0.16)
270 },
270 },
271 :exit_status= => nil,
271 :exit_status= => nil,
272 :memory_usage= => lambda { |s|
272 :memory_usage= => lambda { |s|
273 (s>=500) and (s<=1000)
273 (s>=500) and (s<=1000)
274 },
274 },
275 :save => nil})
275 :save => nil})
276 end
276 end
277
277
278 protected
278 protected
279 def grader_should(args)
279 def grader_should(args)
280 @user1 = stub(User,
280 @user1 = stub(User,
281 :id => 1, :login => 'user1')
281 :id => 1, :login => 'user1')
282
282
283 problem = args[:on]
283 problem = args[:on]
284 input_file = @config.test_request_input_base_dir + "/" + args[:with]
284 input_file = @config.test_request_input_base_dir + "/" + args[:with]
285
285
286 submission =
286 submission =
287 create_submission_from_file(1, @user1, args[:on], args[:grade])
287 create_submission_from_file(1, @user1, args[:on], args[:grade])
288
288
289 test_request = stub(TestRequest,
289 test_request = stub(TestRequest,
290 :id => 1,
290 :id => 1,
291 :user => @user1,
291 :user => @user1,
292 :problem => problem,
292 :problem => problem,
You need to be logged in to leave comments. Login now