Logo AND Algorithmique Numérique Distribuée

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