Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Indent include and src using this command:
[simgrid.git] / tools / tesh2 / src / runner.c
1 /*\r
2  * src/runner.c - type representing the runner.\r
3  *\r
4  * Copyright 2008,2009 Martin Quinson, Malek Cherier All right reserved. \r
5  *\r
6  * This program is free software; you can redistribute it and/or modify it \r
7  * under the terms of the license (GNU LGPL) which comes with this package.\r
8  *\r
9  * Purpose:\r
10  *              This file contains all the definitions of the functions related with\r
11  *              the tesh runner type.\r
12  *\r
13  */\r
14 #include <runner.h>\r
15 #include <units.h>\r
16 #include <unit.h>\r
17 #include <xerrno.h>\r
18 #include <variable.h>\r
19 \r
20 #include <errno.h>      /* for error code       */\r
21 #include <stdlib.h>     /* for calloc()         */\r
22 #include <stdio.h>\r
23 \r
24 #include <readline.h>\r
25 #include <explode.h>\r
26 \r
27 #ifndef _XBT_WIN32\r
28 #include <sys/resource.h>\r
29 #endif\r
30 \r
31 \r
32 \r
33 \r
34 \r
35 #define _RUNNER_HASHCODE                0xFEFEAAAA      \r
36 \r
37 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh);\r
38 \r
39 #if (!defined(__BUILTIN) && defined(__CHKCMD) && !defined(_XBT_WIN32))\r
40 static const char* builtin[] =\r
41 {\r
42         "alias",\r
43         "bind",\r
44         "builtin",\r
45         "caller",\r
46         "cd",\r
47         "command",\r
48         "compgen",\r
49         "complete",\r
50         "declare",\r
51         "disown",\r
52         "echo",\r
53         "enable",\r
54         "eval",\r
55         "exec",\r
56         "export",\r
57         "false",\r
58         "fc",\r
59         "function",\r
60         "getopts",\r
61         "hash",\r
62         "history",\r
63         "jobs",\r
64         "let",\r
65         "logout",\r
66         "printf",\r
67         "pwd",\r
68         "readonly",\r
69         "shift",\r
70         "shopt",\r
71         "source",\r
72         "suspend",\r
73         "test",\r
74         "time",\r
75         "times",\r
76         "trap",\r
77         "true",\r
78         "type",\r
79         "typeset",\r
80         "ulimit",\r
81         "umask",\r
82         "unalias",\r
83         "unset",\r
84         NULL\r
85 };\r
86 \r
87 #define __BUILTIN_MAX ((size_t)42)\r
88 #endif\r
89 \r
90 \r
91 # ifdef __APPLE__\r
92 /* under darwin, the environment gets added to the process at startup time. So, it's not defined at library link time, forcing us to extra tricks */\r
93 # include <crt_externs.h>\r
94 # define environ (*_NSGetEnviron())\r
95 # else\r
96         #ifdef _XBT_WIN32\r
97          /* the environment, as specified by the opengroup, used to initialize the process properties */\r
98                 # define environ **wenviron;\r
99         #else\r
100                 extern char **environ;\r
101         #endif\r
102 # endif\r
103 \r
104 #ifndef _XBT_WIN32\r
105 extern char**\r
106 environ;\r
107 #endif\r
108 \r
109 /* the unique tesh runner */\r
110 static runner_t\r
111 runner = NULL;\r
112 \r
113 /* wait for the tesh runner terminaison */\r
114 static void\r
115 runner_wait(void);\r
116 \r
117 static void*\r
118 runner_start_routine(void* p);\r
119 \r
120 \r
121 /* check the syntax of the tesh files if \r
122  * the check_syntax_flag is specified. Returns\r
123  * 0 if the syntax is clean.\r
124  */\r
125 /*static void\r
126 check_syntax(void);*/\r
127 \r
128 #ifdef _XBT_WIN32\r
129 \r
130 static HANDLE \r
131 timer_handle = NULL;\r
132 \r
133 \r
134 static void*\r
135 runner_start_routine(void* p)\r
136 {\r
137         \r
138     LARGE_INTEGER li;\r
139 \r
140     li.QuadPart=- runner->timeout * 10000000;   /* 10000000 = 10 000 000 * 100 nanoseconds = 1 second */\r
141 \r
142     /* create the waitable timer */\r
143     timer_handle = CreateWaitableTimer(NULL, TRUE, NULL);\r
144 \r
145     /* set a timer to wait for timeout seconds */\r
146     SetWaitableTimer(timer_handle, &li, 0, NULL, NULL, 0);\r
147     \r
148     /* wait for the timer */\r
149     WaitForSingleObject(timer_handle, INFINITE);\r
150 \r
151         if(runner->waiting)\r
152         {\r
153                 exit_code = ELEADTIME;\r
154                 err_kind = 1;\r
155                 runner->timeouted = 1;\r
156                 xbt_os_sem_release(units_sem);\r
157         }\r
158 \r
159         return NULL;\r
160 }\r
161 \r
162 #else\r
163 static void*\r
164 runner_start_routine(void* p)\r
165 {\r
166         struct timespec ts;\r
167         int timeout = runner->timeout;\r
168         \r
169         \r
170         while(timeout-- && runner->waiting)\r
171         {\r
172                 ts.tv_sec = 1;\r
173                 ts.tv_nsec = 0L;\r
174 \r
175                 do\r
176                 {\r
177                         nanosleep(&ts, &ts);\r
178                 }while(EINTR == errno);\r
179         }\r
180         \r
181         if(errno)\r
182         {\r
183                 /* TODO process the error */\r
184         }\r
185         else\r
186         {\r
187                 if(runner->waiting)\r
188                 {\r
189                         exit_code = ELEADTIME;\r
190                         err_kind = 1;\r
191                         runner->timeouted = 1;\r
192                         xbt_os_sem_release(units_sem);\r
193                 }\r
194         }\r
195         \r
196         return NULL;\r
197 }\r
198 #endif\r
199 \r
200 \r
201 int\r
202 runner_init(/*int check_syntax_flag, */int timeout, fstreams_t fstreams)\r
203 {\r
204         \r
205         int i;\r
206         char* val;\r
207         char buffer[PATH_MAX + 1] = {0};\r
208 \r
209         int code;\r
210         const char* cstr;\r
211         variable_t variable;\r
212         \r
213         #if (defined(__CHKCMD) && defined(__BUILTIN) && !defined(_XBT_WIN32))\r
214         FILE* s;\r
215         int n = 0;\r
216         size_t len;\r
217         char* line = NULL;\r
218         int is_blank;\r
219         #endif\r
220         \r
221         \r
222         if(runner)\r
223         {\r
224                 ERROR0("The runner is already initialized");\r
225                 return -1;\r
226         }\r
227                 \r
228         runner = xbt_new0(s_runner_t, 1);\r
229         \r
230         runner->path = NULL;\r
231         runner->builtin = NULL;\r
232         \r
233         if(!(runner->units = units_new(runner, fstreams)))\r
234         {\r
235                 free(runner);\r
236                 runner = NULL;\r
237                 return -1;\r
238         }\r
239 \r
240         runner->timeout = timeout;\r
241         runner->timeouted = 0;\r
242         runner->interrupted = 0;\r
243         runner->number_of_ended_units = 0;\r
244         runner->number_of_runned_units = 0;\r
245         runner->waiting = 0;\r
246         \r
247         runner->total_of_tests = 0;\r
248         runner->total_of_successeded_tests = 0;\r
249         runner->total_of_failed_tests = 0;\r
250         runner->total_of_interrupted_tests = 0;\r
251         \r
252         runner->total_of_units = 0;\r
253         runner->total_of_successeded_units = 0;\r
254         runner->total_of_failed_units = 0;\r
255         runner->total_of_interrupted_units = 0;\r
256         \r
257         runner->total_of_suites = 0;\r
258         runner->total_of_successeded_suites = 0;\r
259         runner->total_of_failed_suites = 0;\r
260         runner->total_of_interrupted_suites = 0;\r
261         \r
262         /* initialize the vector of variables */\r
263         runner->variables = xbt_dynar_new(sizeof(variable_t), (void_f_pvoid_t)variable_free);\r
264         \r
265         /* add the environment variables in the vector */\r
266         for(i = 0; environ[i] != NULL; i++)\r
267         {\r
268                 val = strchr(environ[i], '=');\r
269                 \r
270                 if(val)\r
271                 {\r
272                         val++;\r
273                                 \r
274                         if(val[0] != '\0')\r
275                                 strncpy(buffer, environ[i], (val - environ[i] -1));\r
276                                 \r
277                         if(!strcmp("TESH_PPID", buffer))\r
278                                 is_tesh_root = 0;\r
279                         \r
280                         variable = variable_new(buffer, val);\r
281                         variable->env = 1;\r
282                         xbt_dynar_push(runner->variables, &variable);\r
283                         \r
284                         #ifndef _XBT_WIN32\r
285                         if(!strcmp("PATH", buffer))\r
286                         #else\r
287                         if(!strcmp("Path", buffer) || !strcmp("PATH", buffer))\r
288                         #endif\r
289                         {\r
290                                 char* p;\r
291                                 size_t j,k, len;\r
292                                 \r
293                                 /* get the list of paths */\r
294                                 \r
295                                 #ifdef _XBT_WIN32\r
296                                 runner->path = explode(';', val);\r
297                                 #else\r
298                                 runner->path = explode(':', val);\r
299                                 #endif\r
300 \r
301                                 /* remove spaces and backslahes at the end of the path */\r
302                                 for (k = 0; runner->path[k] != NULL; k++)\r
303                                 {\r
304                                 p = runner->path[k];\r
305                                 \r
306                                 len = strlen(p);\r
307                                 \r
308                                         #ifndef _XBT_WIN32\r
309                                 for(j = len - 1; p[j] == '/' || p[j] == ' '; j--)\r
310                                         #else\r
311                                         for(j = len - 1; p[j] == '\\' || p[j] == ' '; j--)\r
312                                         #endif\r
313                                         p[j] = '\0';\r
314                                 }\r
315                         }\r
316                         \r
317                                 \r
318                         memset(buffer, 0, PATH_MAX + 1);\r
319                 }\r
320         }\r
321         \r
322         if(is_tesh_root)\r
323         {\r
324                 char* tesh_dir = getcwd(NULL, 0);\r
325                 \r
326                 sprintf(buffer,"%d",getpid());\r
327                 \r
328                 #ifndef _XBT_WIN32\r
329                 setenv("TESH_PPID", buffer, 0);\r
330                 setenv("TESH_DIR", tesh_dir, 0);\r
331                 #else\r
332                 SetEnvironmentVariable("TESH_PPID", buffer);\r
333                 SetEnvironmentVariable("TESH_DIR", tesh_dir);\r
334                 #endif\r
335                 \r
336                 variable = variable_new("TESH_PPID", buffer);\r
337                 variable->err = 1;\r
338                         \r
339                 xbt_dynar_push(runner->variables, &variable);\r
340 \r
341                 variable = variable_new("TESH_DIR", tesh_dir);\r
342                 variable->err = 1;\r
343                         \r
344                 xbt_dynar_push(runner->variables, &variable);\r
345                 \r
346                 free(tesh_dir);\r
347         }\r
348         \r
349         variable = variable_new("EXIT_SUCCESS", "0");\r
350         variable->err = 1;\r
351                         \r
352         xbt_dynar_push(runner->variables, &variable);\r
353 \r
354         variable = variable_new("EXIT_FAILURE", "1");\r
355         variable->err = 1;\r
356                         \r
357         xbt_dynar_push(runner->variables, &variable);\r
358 \r
359         variable = variable_new("TRUE", "0");\r
360         variable->err = 1;\r
361                         \r
362         xbt_dynar_push(runner->variables, &variable);\r
363 \r
364         variable = variable_new("FALSE", "1");\r
365         variable->err = 1;\r
366                         \r
367         xbt_dynar_push(runner->variables, &variable);\r
368 \r
369         i = 0;\r
370         \r
371         /* add the errors variables */\r
372         while((cstr = error_get_at(i++, &code)))\r
373         {\r
374                 sprintf(buffer,"%d",code);\r
375                 variable = variable_new(cstr, buffer);\r
376                 variable->err = 1;\r
377                 xbt_dynar_push(runner->variables, &variable);\r
378         }\r
379         \r
380         /* if the user want check the syntax, check it */\r
381         /*if(check_syntax_flag)\r
382                 check_syntax();\r
383         */\r
384         \r
385         #if (!defined(_XBT_WIN32) && defined(__CHKCMD))\r
386         #if defined(__BUILTIN)\r
387         \r
388         if(!is_tesh_root)\r
389         {\r
390                 /* compute the full path the builtin.def file */\r
391                 sprintf(buffer,"%s/builtin.def",getenv("TESH_DIR"));\r
392                 \r
393                 if(!(s = fopen(buffer, "r")))   \r
394                 {\r
395                         ERROR1("File `(%s)' not found", buffer);\r
396                         return -1;\r
397                 }\r
398                 \r
399         }\r
400         else\r
401         {\r
402                 if(!(s = fopen("builtin.def", "r")))    \r
403                 {\r
404                         ERROR0("File `(builtin.def)' not found");\r
405                         return -1;\r
406                 }\r
407         }\r
408         \r
409         if(s)\r
410         {\r
411                 fpos_t begin;\r
412 \r
413                 fgetpos(s, &begin);\r
414 \r
415                 while(readline(s, &line, &len) != -1)\r
416                 {\r
417                         i = 0;\r
418                         is_blank = 1;\r
419                         \r
420 \r
421                         while(line[i] != '\0') \r
422                         {\r
423                                 if (line[i] != ' ' && line[i] != '\t' && line[i]!='\n' && line[i]!='\r')\r
424                                 {\r
425                                         is_blank = 0;\r
426                                         break;\r
427                                 }\r
428                                 \r
429                                 i++;\r
430                         }\r
431 \r
432                         if(!is_blank)\r
433                                 n++;\r
434                 }\r
435 \r
436                 fsetpos(s, &begin);\r
437                 free(line);\r
438                 line = NULL;\r
439 \r
440                 if(n)\r
441                 {\r
442                         char* l;\r
443                         \r
444                         runner->builtin = xbt_new0(char*, n + 1); /* (char**) calloc(n + 1, sizeof(char*));*/\r
445                         \r
446                         n = 0;\r
447                         \r
448                         while(readline(s, &line, &len) != -1)\r
449                         {\r
450                                 i = 0;\r
451                                 is_blank = 1;\r
452 \r
453                                 while(line[i] != '\0') \r
454                                 {\r
455                                         if (line[i] != ' ' && line[i] != '\t' && line[i]!='\n' && line[i]!='\r')\r
456                                         {\r
457                                                 is_blank = 0;\r
458                                                 break;\r
459                                         }\r
460                                         \r
461                                         i++;\r
462                                 }\r
463 \r
464                                 if(!is_blank)\r
465                                 {\r
466                                         l = strdup(line);\r
467 \r
468                                         l[strlen(l) - 1] = '\0';\r
469 \r
470                                         (runner->builtin)[n++] = l;\r
471                                         \r
472                                 }\r
473                         }\r
474                         \r
475                 }\r
476                 else\r
477                 {\r
478                         WARN0("The file `(builtin.def)' is empty");\r
479                         free(runner->builtin);\r
480                         runner->builtin = NULL;\r
481                 }\r
482                 \r
483 \r
484                 fclose(s);\r
485                 \r
486                 if(line)\r
487                         free(line);\r
488                 \r
489         }\r
490         \r
491         #else\r
492                 runner->builtin = xbt_new0(char*, __BUILTIN_MAX + 1); /* (char**) calloc(__BUILTIN_MAX + 1, sizeof(char*));*/\r
493                 \r
494                 for(i = 0; i < __BUILTIN_MAX; i++)\r
495                         runner->builtin[i] = strdup(builtin[i]);        \r
496         #endif\r
497         #endif\r
498 \r
499         return exit_code ? -1 : 0;\r
500 }\r
501 \r
502 void\r
503 runner_destroy(void)\r
504 {\r
505         int i;\r
506         \r
507         if(runner->units)\r
508                 units_free((void**)(&(runner->units)));\r
509         \r
510         if(runner->variables)\r
511                 xbt_dynar_free(&runner->variables);\r
512         \r
513         #ifdef _XBT_WIN32\r
514         CloseHandle(timer_handle);\r
515         #endif\r
516 \r
517         if(runner->thread)\r
518                 xbt_os_thread_join(runner->thread, NULL);\r
519         \r
520         if(runner->path)\r
521         {\r
522                 for (i = 0; runner->path[i] != NULL; i++)\r
523                         free(runner->path[i]);\r
524                 \r
525                 free(runner->path);\r
526         }\r
527 \r
528         if(runner->builtin)\r
529         {\r
530                 for (i = 0; runner->builtin[i] != NULL; i++)\r
531                         free(runner->builtin[i]);\r
532                 \r
533                 free(runner->builtin);\r
534         }\r
535 \r
536         free(runner);\r
537         \r
538 \r
539         runner = NULL;\r
540 }\r
541 \r
542 void\r
543 runner_run(void)\r
544 {\r
545         /* allocate the mutex used by the units to asynchronously access \r
546          * to the properties of the runner.\r
547          */\r
548         xbt_os_mutex_t mutex = xbt_os_mutex_init();\r
549         \r
550         /* run all the units */\r
551         units_run_all(runner->units, mutex);\r
552         \r
553         \r
554         if(!interrupted)\r
555                 runner_wait();\r
556 \r
557         \r
558         /* if the runner is timeouted or receive a interruption request\r
559          * , interrupt all the active units.\r
560          */\r
561         if(runner->timeouted || interrupted)\r
562                 runner_interrupt();\r
563         \r
564         /* joins all the units */\r
565         units_join_all(runner->units);\r
566         \r
567         /* release the mutex resource */\r
568         xbt_os_mutex_destroy(mutex);\r
569 \r
570 }\r
571 \r
572 static void\r
573 runner_wait(void)\r
574 {\r
575         if(runner->timeout > 0)\r
576                 runner->thread = xbt_os_thread_create("", runner_start_routine, NULL);\r
577         \r
578         /* signal that the runner is waiting */\r
579         runner->waiting = 1;\r
580         \r
581         /* wait for the end of all the units */\r
582         xbt_os_sem_acquire(units_sem);\r
583 \r
584         \r
585         runner->waiting = 0;\r
586 }\r
587 \r
588 \r
589 \r
590 /*\r
591  * interrupt all the active units.\r
592  * this function is called when the lead time of the execution is reached\r
593  * or when a failed unit requests an interruption of the execution.\r
594  */\r
595 void\r
596 runner_interrupt(void)\r
597 {\r
598         units_interrupt_all(runner->units);\r
599 }\r
600 \r
601 void\r
602 runner_summarize(void)\r
603 {\r
604         \r
605         if(!dry_run_flag)\r
606         {\r
607                 #ifndef _XBT_WIN32\r
608                 struct rusage r_usage;\r
609                 #else\r
610                 FILETIME start_time;\r
611                 FILETIME exit_time;\r
612                 FILETIME kernel_time;\r
613                 FILETIME user_time;\r
614                 SYSTEMTIME si;\r
615                 #endif\r
616                 \r
617                 printf("\n  TEst SHell utility - mini shell specialized in running test units.\n");\r
618                 printf(" =============================================================================\n");\r
619                 \r
620                 units_summuarize(runner->units);\r
621                 \r
622                 printf(" =====================================================================%s\n",\r
623                 runner->total_of_failed_tests ? "== FAILED": (runner->total_of_interrupted_tests || runner->total_of_interrupted_units) ? "==== INTR" : "====== OK");\r
624                 \r
625                 printf(" TOTAL : Suite(s): %.0f%% ok (%d suite(s): %d ok",\r
626                 (runner->total_of_suites ? (1-((double)runner->total_of_failed_suites + (double)runner->total_of_interrupted_suites)/(double)runner->total_of_suites)*100.0 : 100.0),\r
627                 runner->total_of_suites, runner->total_of_successeded_suites);\r
628                 \r
629                 if(runner->total_of_failed_suites > 0)\r
630                         printf(", %d failed", runner->total_of_failed_suites);\r
631                 \r
632                 if(runner->total_of_interrupted_suites > 0)\r
633                         printf(", %d interrupted)", runner->total_of_interrupted_suites);\r
634                 \r
635                 printf(")\n");  \r
636                 \r
637                 printf("         Unit(s):  %.0f%% ok (%d unit(s): %d ok",\r
638                 (runner->total_of_units ? (1-((double)runner->total_of_failed_units + (double)runner->total_of_interrupted_units)/(double)runner->total_of_units)*100.0 : 100.0),\r
639                 runner->total_of_units, runner->total_of_successeded_units);\r
640                 \r
641                 if(runner->total_of_failed_units > 0)\r
642                         printf(", %d failed", runner->total_of_failed_units);\r
643                 \r
644                 if(runner->total_of_interrupted_units > 0)\r
645                         printf(", %d interrupted)", runner->total_of_interrupted_units);\r
646                 \r
647                 printf(")\n");\r
648                 \r
649                 printf("         Test(s):  %.0f%% ok (%d test(s): %d ok",\r
650                 (runner->total_of_tests ? (1-((double)runner->total_of_failed_tests + (double)runner->total_of_interrupted_tests)/(double)runner->total_of_tests)*100.0 : 100.0),\r
651                 runner->total_of_tests, runner->total_of_successeded_tests);\r
652                 \r
653                 if(runner->total_of_failed_tests > 0)\r
654                         printf(", %d failed", runner->total_of_failed_tests);\r
655                 \r
656                 if(runner->total_of_interrupted_tests > 0)\r
657                         printf(", %d interrupted)", runner->total_of_interrupted_tests);\r
658                 \r
659                 printf(")\n\n");\r
660                 \r
661                 #ifndef _XBT_WIN32\r
662                 if(!getrusage(RUSAGE_SELF, &r_usage))\r
663                 {\r
664                 \r
665                         printf("         Total tesh user time used:       %ld second(s) %ld microsecond(s)\n", r_usage.ru_utime.tv_sec, r_usage.ru_utime.tv_usec);\r
666                         printf("         Total tesh system time used:     %ld second(s) %ld microsecond(s)\n\n", r_usage.ru_stime.tv_sec, r_usage.ru_stime.tv_usec);\r
667                 \r
668                         if(!getrusage(RUSAGE_CHILDREN, &r_usage))\r
669                         {\r
670                                 printf("         Total children user time used:   %ld second(s) %ld microsecond(s)\n", r_usage.ru_utime.tv_sec, r_usage.ru_utime.tv_usec);\r
671                                 printf("         Total children system time used: %ld second(s) %ld microsecond(s)\n\n", r_usage.ru_stime.tv_sec, r_usage.ru_stime.tv_usec);\r
672                 \r
673                         }       \r
674                 }\r
675                 #else\r
676         \r
677                 if(GetProcessTimes(GetCurrentProcess(), &start_time, &exit_time, &kernel_time, &user_time))\r
678                 {\r
679                         FileTimeToSystemTime(&user_time, &si);\r
680                         \r
681                         printf(" User time used:   %2u Hour(s) %2u Minute(s) %2u Second(s) %3u Millisecond(s)\n", si.wHour, si.wMinute, si.wSecond, si.wMilliseconds );\r
682                         \r
683                         FileTimeToSystemTime(&kernel_time, &si);\r
684                         \r
685                         printf(" Kernel time used: %2u Hour(s) %2u Minute(s) %2u Second(s) %3u Millisecond(s)\n", si.wHour, si.wMinute, si.wSecond, si.wMilliseconds );\r
686                 }\r
687 \r
688 \r
689 \r
690                 #endif\r
691         }\r
692         else\r
693         {\r
694                 if(exit_code)\r
695                         ERROR0("Syntax NOK");\r
696                 else if(!exit_code)\r
697                         INFO0("Syntax 0K");\r
698         }\r
699 }\r
700 \r
701 int\r
702 runner_is_timedout(void)\r
703 {\r
704         return runner->timeouted;\r
705 }\r
706 \r