Logo AND Algorithmique Numérique Distribuée

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