Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Indent the rest of the code (examples, buildtools, doc...) except for examples/SMPI...
[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\r\r\r\r
31 #define _RUNNER_HASHCODE                0xFEFEAAAA      \r
32     \rXBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh);
33 \r\r
34 #if (!defined(__BUILTIN) && defined(__CHKCMD) && !defined(_XBT_WIN32))\r
35 static const char *builtin[] = \r
36     { \r"alias", \r"bind", \r"builtin", \r"caller", \r"cd", \r"command",
37 \r"compgen", \r"complete", \r"declare", \r"disown", \r"echo", \r"enable", \r"eval", \r"exec", \r"export",
38 \r"false", \r"fc", \r"function", \r"getopts", \r"hash", \r"history", \r"jobs", \r"let", \r"logout",
39 \r"printf", \r"pwd", \r"readonly", \r"shift", \r"shopt", \r"source", \r"suspend", \r"test", \r"time",
40 \r"times", \r"trap", \r"true", \r"type", \r"typeset", \r"ulimit", \r"umask", \r"unalias", \r"unset",
41 \rNULL \r
42 };
43
44 \r\r
45 #define __BUILTIN_MAX ((size_t)42)\r
46 #endif  /* \r */
47     \r\r
48 # ifdef __APPLE__\r
49 /* 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
50 # include <crt_externs.h>\r
51 # define environ (*_NSGetEnviron())\r
52 # else\r
53 #ifdef _XBT_WIN32\r
54     /* the environment, as specified by the opengroup, used to initialize the process properties */ \r
55 # define environ **wenviron;\r
56 #else   /* \r */
57 extern char **environ;
58 \r
59 #endif  /* \r */
60 # endif\r
61     \r
62 #ifndef _XBT_WIN32\r
63 extern char **\r environ;
64 \r
65 #endif  /* \r */
66     \r
67 /* the unique tesh runner */ \r
68 static runner_t \r runner = NULL;
69 \r\r
70 /* wait for the tesh runner terminaison */ \r
71 static void \r runner_wait(void);
72 \r\rstatic void *\r runner_start_routine(void *p);
73 \r\r\r
74 /* check the syntax of the tesh files if \r
75  * the check_syntax_flag is specified. Returns\r
76  * 0 if the syntax is clean.\r
77  */ \r
78 /*static void\r
79 check_syntax(void);*/ \r
80     \r
81 #ifdef _XBT_WIN32\r
82 \rstatic HANDLE \r timer_handle = NULL;
83 \r\r\rstatic void *\r runner_start_routine(void *p) \r
84 {
85   \r\rLARGE_INTEGER li;
86   \r\rli.QuadPart = -runner->timeout * 10000000;  /* 10000000 = 10 000 000 * 100 nanoseconds = 1 second */
87   \r\r
88       /* create the waitable timer */ \r
89       timer_handle = CreateWaitableTimer(NULL, TRUE, NULL);
90   \r\r
91       /* set a timer to wait for timeout seconds */ \r
92       SetWaitableTimer(timer_handle, &li, 0, NULL, NULL, 0);
93   \r\r
94       /* wait for the timer */ \r
95       WaitForSingleObject(timer_handle, INFINITE);
96   \r\rif (runner->waiting)
97     \r {
98     \rexit_code = ELEADTIME;
99     \rerr_kind = 1;
100     \rrunner->timeouted = 1;
101     \rxbt_os_sem_release(units_sem);
102     \r}
103   \r\rreturn NULL;
104 \r}
105
106 \r\r
107 #else   /* \r */
108 static void *\r runner_start_routine(void *p) \r
109 {
110   \rstruct timespec ts;
111   \rint timeout = runner->timeout;
112   \r\r\rwhile (timeout-- && runner->waiting)
113     \r {
114     \rts.tv_sec = 1;
115     \rts.tv_nsec = 0L;
116     \r\r
117     do
118       \r {
119       \rnanosleep(&ts, &ts);
120     \r} while (EINTR == errno);
121     \r}
122   \r\rif (errno)
123     \r {
124     \r
125         /* TODO process the error */ \r
126     }
127   \r
128   else
129     \r {
130     \rif (runner->waiting)
131       \r {
132       \rexit_code = ELEADTIME;
133       \rerr_kind = 1;
134       \rrunner->timeouted = 1;
135       \rxbt_os_sem_release(units_sem);
136       \r}
137     \r}
138   \r\rreturn NULL;
139 \r}
140
141 \r
142 #endif  /* \r */
143 \r\rint \r
144 runner_init( /*int check_syntax_flag, */ int timeout,
145             fstreams_t fstreams) \r
146 {
147   \r\rint i;
148   \rchar *val;
149   \rchar buffer[PATH_MAX + 1] = { 0 };
150   \r\rint code;
151   \rconst char *cstr;
152   \rvariable_t variable;
153   \r\r
154 #if (defined(__CHKCMD) && defined(__BUILTIN) && !defined(_XBT_WIN32))\r
155       FILE * s;
156   \rint n = 0;
157   \rsize_t len;
158   \rchar *line = NULL;
159   \rint is_blank;
160   \r
161 #endif  /* \r */
162       \r\rif (runner)
163     \r {
164     \rERROR0("The runner is already initialized");
165     \rreturn -1;
166     \r}
167   \r\rrunner = xbt_new0(s_runner_t, 1);
168   \r\rrunner->path = NULL;
169   \rrunner->builtin = NULL;
170   \r\rif (!(runner->units = units_new(runner, fstreams)))
171     \r {
172     \rfree(runner);
173     \rrunner = NULL;
174     \rreturn -1;
175     \r}
176   \r\rrunner->timeout = timeout;
177   \rrunner->timeouted = 0;
178   \rrunner->interrupted = 0;
179   \rrunner->number_of_ended_units = 0;
180   \rrunner->number_of_runned_units = 0;
181   \rrunner->waiting = 0;
182   \r\rrunner->total_of_tests = 0;
183   \rrunner->total_of_successeded_tests = 0;
184   \rrunner->total_of_failed_tests = 0;
185   \rrunner->total_of_interrupted_tests = 0;
186   \r\rrunner->total_of_units = 0;
187   \rrunner->total_of_successeded_units = 0;
188   \rrunner->total_of_failed_units = 0;
189   \rrunner->total_of_interrupted_units = 0;
190   \r\rrunner->total_of_suites = 0;
191   \rrunner->total_of_successeded_suites = 0;
192   \rrunner->total_of_failed_suites = 0;
193   \rrunner->total_of_interrupted_suites = 0;
194   \r\r
195       /* initialize the vector of variables */ \r
196       runner->variables =
197       xbt_dynar_new(sizeof(variable_t), (void_f_pvoid_t) variable_free);
198   \r\r
199       /* add the environment variables in the vector */ \r
200       for (i = 0; environ[i] != NULL; i++)
201     \r {
202     \rval = strchr(environ[i], '=');
203     \r\rif (val)
204       \r {
205       \rval++;
206       \r\rif (val[0] != '\0')
207         \rstrncpy(buffer, environ[i], (val - environ[i] - 1));
208       \r\rif (!strcmp("TESH_PPID", buffer))
209         \ris_tesh_root = 0;
210       \r\rvariable = variable_new(buffer, val);
211       \rvariable->env = 1;
212       \rxbt_dynar_push(runner->variables, &variable);
213       \r\r
214 #ifndef _XBT_WIN32\r
215           if (!strcmp("PATH", buffer))
216         \r
217 #else   /* \r */
218           if (!strcmp("Path", buffer) || !strcmp("PATH", buffer))
219         \r
220 #endif  /* \r */
221       {
222         \rchar *p;
223         \rsize_t j, k, len;
224         \r\r
225             /* get the list of paths */ \r
226             \r
227 #ifdef _XBT_WIN32\r
228             runner->path = explode(';', val);
229         \r
230 #else   /* \r */
231             runner->path = explode(':', val);
232         \r
233 #endif  /* \r */
234             \r
235             /* remove spaces and backslahes at the end of the path */ \r
236             for (k = 0; runner->path[k] != NULL; k++)
237           \r {
238           \rp = runner->path[k];
239           \r\rlen = strlen(p);
240           \r\r
241 #ifndef _XBT_WIN32\r
242               for (j = len - 1; p[j] == '/' || p[j] == ' '; j--)
243             \r
244 #else   /* \r */
245               for (j = len - 1; p[j] == '\\' || p[j] == ' '; j--)
246             \r
247 #endif  /* \r */
248                 p[j] = '\0';
249           \r}
250       \r}
251       \r\r\rmemset(buffer, 0, PATH_MAX + 1);
252       \r}
253     \r}
254   \r\rif (is_tesh_root)
255     \r {
256     \rchar *tesh_dir = getcwd(NULL, 0);
257     \r\rsprintf(buffer, "%d", getpid());
258     \r\r
259 #ifndef _XBT_WIN32\r
260         setenv("TESH_PPID", buffer, 0);
261     \rsetenv("TESH_DIR", tesh_dir, 0);
262     \r
263 #else   /* \r */
264         SetEnvironmentVariable("TESH_PPID", buffer);
265     \rSetEnvironmentVariable("TESH_DIR", tesh_dir);
266     \r
267 #endif  /* \r */
268         \rvariable = variable_new("TESH_PPID", buffer);
269     \rvariable->err = 1;
270     \r\rxbt_dynar_push(runner->variables, &variable);
271     \r\rvariable = variable_new("TESH_DIR", tesh_dir);
272     \rvariable->err = 1;
273     \r\rxbt_dynar_push(runner->variables, &variable);
274     \r\rfree(tesh_dir);
275     \r}
276   \r\rvariable = variable_new("EXIT_SUCCESS", "0");
277   \rvariable->err = 1;
278   \r\rxbt_dynar_push(runner->variables, &variable);
279   \r\rvariable = variable_new("EXIT_FAILURE", "1");
280   \rvariable->err = 1;
281   \r\rxbt_dynar_push(runner->variables, &variable);
282   \r\rvariable = variable_new("TRUE", "0");
283   \rvariable->err = 1;
284   \r\rxbt_dynar_push(runner->variables, &variable);
285   \r\rvariable = variable_new("FALSE", "1");
286   \rvariable->err = 1;
287   \r\rxbt_dynar_push(runner->variables, &variable);
288   \r\ri = 0;
289   \r\r
290       /* add the errors variables */ \r
291       while ((cstr = error_get_at(i++, &code)))
292     \r {
293     \rsprintf(buffer, "%d", code);
294     \rvariable = variable_new(cstr, buffer);
295     \rvariable->err = 1;
296     \rxbt_dynar_push(runner->variables, &variable);
297     \r}
298   \r\r
299       /* if the user want check the syntax, check it */ \r
300       /*if(check_syntax_flag)\r
301          check_syntax();\r
302        */ \r
303       \r
304 #if (!defined(_XBT_WIN32) && defined(__CHKCMD))\r
305 #if defined(__BUILTIN)\r
306       \rif (!is_tesh_root)
307     \r {
308     \r
309         /* compute the full path the builtin.def file */ \r
310         sprintf(buffer, "%s/builtin.def", getenv("TESH_DIR"));
311     \r\rif (!(s = fopen(buffer, "r")))
312       \r {
313       \rERROR1("File `(%s)' not found", buffer);
314       \rreturn -1;
315       \r}
316     \r\r}
317   \r
318   else
319     \r {
320     \rif (!(s = fopen("builtin.def", "r")))
321       \r {
322       \rERROR0("File `(builtin.def)' not found");
323       \rreturn -1;
324       \r}
325     \r}
326   \r\rif (s)
327     \r {
328     \rfpos_t begin;
329     \r\rfgetpos(s, &begin);
330     \r\rwhile (readline(s, &line, &len) != -1)
331       \r {
332       \ri = 0;
333       \ris_blank = 1;
334       \r\r\rwhile (line[i] != '\0')
335         \r {
336         \rif (line[i] != ' ' && line[i] != '\t' && line[i] != '\n'
337              && line[i] != '\r')
338           \r {
339           \ris_blank = 0;
340           \rbreak;
341           \r}
342         \r\ri++;
343         \r}
344       \r\rif (!is_blank)
345         \rn++;
346       \r}
347     \r\rfsetpos(s, &begin);
348     \rfree(line);
349     \rline = NULL;
350     \r\rif (n)
351       \r {
352       \rchar *l;
353       \r\rrunner->builtin = xbt_new0(char *, n + 1);      /* (char**) calloc(n + 1, sizeof(char*)); */
354       \r\rn = 0;
355       \r\rwhile (readline(s, &line, &len) != -1)
356         \r {
357         \ri = 0;
358         \ris_blank = 1;
359         \r\rwhile (line[i] != '\0')
360           \r {
361           \rif (line[i] != ' ' && line[i] != '\t' && line[i] != '\n'
362                && line[i] != '\r')
363             \r {
364             \ris_blank = 0;
365             \rbreak;
366             \r}
367           \r\ri++;
368           \r}
369         \r\rif (!is_blank)
370           \r {
371           \rl = strdup(line);
372           \r\rl[strlen(l) - 1] = '\0';
373           \r\r(runner->builtin)[n++] = l;
374           \r\r}
375         \r}
376       \r\r}
377     \r
378     else
379       \r {
380       \rWARN0("The file `(builtin.def)' is empty");
381       \rfree(runner->builtin);
382       \rrunner->builtin = NULL;
383       \r}
384     \r\r\rfclose(s);
385     \r\rif (line)
386       \rfree(line);
387     \r\r}
388   \r\r
389 #else   /* \r */
390       runner->builtin = xbt_new0(char *, __BUILTIN_MAX + 1);    /* (char**) calloc(__BUILTIN_MAX + 1, sizeof(char*)); */
391   \r\rfor (i = 0; i < __BUILTIN_MAX; i++)
392     \rrunner->builtin[i] = strdup(builtin[i]);
393   \r
394 #endif  /* \r */
395 #endif  /* \r */
396       \rreturn exit_code ? -1 : 0;
397 \r}
398
399 \r\rvoid \r runner_destroy(void) \r
400 {
401   \rint i;
402   \r\rif (runner->units)
403     \runits_free((void **) (&(runner->units)));
404   \r\rif (runner->variables)
405     \rxbt_dynar_free(&runner->variables);
406   \r\r
407 #ifdef _XBT_WIN32\r
408       CloseHandle(timer_handle);
409   \r
410 #endif  /* \r */
411       \rif (runner->thread)
412     \rxbt_os_thread_join(runner->thread, NULL);
413   \r\rif (runner->path)
414     \r {
415     \rfor (i = 0; runner->path[i] != NULL; i++)
416       \rfree(runner->path[i]);
417     \r\rfree(runner->path);
418     \r}
419   \r\rif (runner->builtin)
420     \r {
421     \rfor (i = 0; runner->builtin[i] != NULL; i++)
422       \rfree(runner->builtin[i]);
423     \r\rfree(runner->builtin);
424     \r}
425   \r\rfree(runner);
426   \r\r\rrunner = NULL;
427 \r}
428
429 \r\rvoid \r runner_run(void) \r
430 {
431   \r
432       /* allocate the mutex used by the units to asynchronously access \r
433        * to the properties of the runner.\r
434        */ \r
435       xbt_os_mutex_t mutex = xbt_os_mutex_init();
436   \r\r
437       /* run all the units */ \r
438       units_run_all(runner->units, mutex);
439   \r\r\rif (!interrupted)
440     \rrunner_wait();
441   \r\r\r
442       /* if the runner is timeouted or receive a interruption request\r
443        * , interrupt all the active units.\r
444        */ \r
445       if (runner->timeouted || interrupted)
446     \rrunner_interrupt();
447   \r\r
448       /* joins all the units */ \r
449       units_join_all(runner->units);
450   \r\r
451       /* release the mutex resource */ \r
452       xbt_os_mutex_destroy(mutex);
453 \r\r}
454
455 \r\rstatic void \r runner_wait(void) \r
456 {
457   \rif (runner->timeout > 0)
458     \rrunner->thread = xbt_os_thread_create("", runner_start_routine, NULL);
459   \r\r
460       /* signal that the runner is waiting */ \r
461       runner->waiting = 1;
462   \r\r
463       /* wait for the end of all the units */ \r
464       xbt_os_sem_acquire(units_sem);
465   \r\r\rrunner->waiting = 0;
466 \r}
467
468 \r\r\r\r
469 /*\r
470  * interrupt all the active units.\r
471  * this function is called when the lead time of the execution is reached\r
472  * or when a failed unit requests an interruption of the execution.\r
473  */ \r
474 void \r runner_interrupt(void) \r
475 {
476   \runits_interrupt_all(runner->units);
477 \r\r\rvoid \r runner_summarize(void) \r
478 {
479   \r\rif (!dry_run_flag)
480     \r {
481     \r
482 #ifndef _XBT_WIN32\r
483     struct rusage r_usage;
484     \r
485 #else   /* \r */
486         FILETIME start_time;
487     \rFILETIME exit_time;
488     \rFILETIME kernel_time;
489     \rFILETIME user_time;
490     \rSYSTEMTIME si;
491     \r
492 #endif  /* \r */
493         \rprintf
494         ("\n  TEst SHell utility - mini shell specialized in running test units.\n");
495     \rprintf
496         (" =============================================================================\n");
497     \r\runits_summuarize(runner->units);
498     \r\rprintf
499         (" =====================================================================%s\n",
500          \rrunner->total_of_failed_tests ? "== FAILED" : (runner->
501                                                          total_of_interrupted_tests
502                                                          || runner->
503                                                          total_of_interrupted_units)
504          ? "==== INTR" : "====== OK");
505     \r\rprintf(" TOTAL : Suite(s): %.0f%% ok (%d suite(s): %d ok",
506              \r(runner->
507                total_of_suites ? (1 -
508                                   ((double) runner->
509                                    total_of_failed_suites +
510                                    (double) runner->
511                                    total_of_interrupted_suites) /
512                                   (double) runner->total_of_suites) *
513                100.0 : 100.0), \rrunner->total_of_suites,
514              runner->total_of_successeded_suites);
515     \r\rif (runner->total_of_failed_suites > 0)
516       \rprintf(", %d failed", runner->total_of_failed_suites);
517     \r\rif (runner->total_of_interrupted_suites > 0)
518       \rprintf(", %d interrupted)", runner->total_of_interrupted_suites);
519     \r\rprintf(")\n");
520     \r\rprintf("         Unit(s):  %.0f%% ok (%d unit(s): %d ok", \r
521              (runner->
522               total_of_units ? (1 -
523                                 ((double) runner->total_of_failed_units +
524                                  (double) runner->
525                                  total_of_interrupted_units) /
526                                 (double) runner->total_of_units) *
527               100.0 : 100.0), \rrunner->total_of_units,
528              runner->total_of_successeded_units);
529     \r\rif (runner->total_of_failed_units > 0)
530       \rprintf(", %d failed", runner->total_of_failed_units);
531     \r\rif (runner->total_of_interrupted_units > 0)
532       \rprintf(", %d interrupted)", runner->total_of_interrupted_units);
533     \r\rprintf(")\n");
534     \r\rprintf("         Test(s):  %.0f%% ok (%d test(s): %d ok", \r
535              (runner->
536               total_of_tests ? (1 -
537                                 ((double) runner->total_of_failed_tests +
538                                  (double) runner->
539                                  total_of_interrupted_tests) /
540                                 (double) runner->total_of_tests) *
541               100.0 : 100.0), \rrunner->total_of_tests,
542              runner->total_of_successeded_tests);
543     \r\rif (runner->total_of_failed_tests > 0)
544       \rprintf(", %d failed", runner->total_of_failed_tests);
545     \r\rif (runner->total_of_interrupted_tests > 0)
546       \rprintf(", %d interrupted)", runner->total_of_interrupted_tests);
547     \r\rprintf(")\n\n");
548     \r\r
549 #ifndef _XBT_WIN32\r
550         if (!getrusage(RUSAGE_SELF, &r_usage))
551       \r {
552       \r\rprintf
553           ("         Total tesh user time used:       %ld second(s) %ld microsecond(s)\n",
554            r_usage.ru_utime.tv_sec, r_usage.ru_utime.tv_usec);
555       \rprintf
556           ("         Total tesh system time used:     %ld second(s) %ld microsecond(s)\n\n",
557            r_usage.ru_stime.tv_sec, r_usage.ru_stime.tv_usec);
558       \r\rif (!getrusage(RUSAGE_CHILDREN, &r_usage))
559         \r {
560         \rprintf
561             ("         Total children user time used:   %ld second(s) %ld microsecond(s)\n",
562              r_usage.ru_utime.tv_sec, r_usage.ru_utime.tv_usec);
563         \rprintf
564             ("         Total children system time used: %ld second(s) %ld microsecond(s)\n\n",
565              r_usage.ru_stime.tv_sec, r_usage.ru_stime.tv_usec);
566         \r\r}
567       \r}
568     \r
569 #else   /* \r */
570         \rif (GetProcessTimes
571              (GetCurrentProcess(), &start_time, &exit_time, &kernel_time,
572               &user_time))
573       \r {
574       \rFileTimeToSystemTime(&user_time, &si);
575       \r\rprintf
576           (" User time used:   %2u Hour(s) %2u Minute(s) %2u Second(s) %3u Millisecond(s)\n",
577            si.wHour, si.wMinute, si.wSecond, si.wMilliseconds);
578       \r\rFileTimeToSystemTime(&kernel_time, &si);
579       \r\rprintf
580           (" Kernel time used: %2u Hour(s) %2u Minute(s) %2u Second(s) %3u Millisecond(s)\n",
581            si.wHour, si.wMinute, si.wSecond, si.wMilliseconds);
582       \r}
583     \r\r\r\r
584 #endif  /* \r */
585     }
586   \r
587   else
588     \r {
589     \rif (exit_code)
590       \rERROR0("Syntax NOK");
591     \r
592     else if (!exit_code)
593       \rINFO0("Syntax 0K");
594     \r}
595 \r}
596
597 \r\rint \r runner_is_timedout(void) \r
598 {
599   \rreturn runner->timeouted;
600 \r}
601
602 \r\r