Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Add the new integrated files version (use xbt data structures instead my own data...
[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  \r
15 #include <runner.h>\r
16 #include <units.h>\r
17 #include <unit.h>\r
18 #include <xerrno.h>\r
19 #include <variable.h>\r
20 \r
21 #include <errno.h>      /* for error code       */\r
22 #include <stdlib.h>     /* for calloc()         */\r
23 #include <stdio.h>\r
24 \r
25 #ifndef WIN32\r
26 #include <sys/resource.h>\r
27 #endif\r
28 \r
29 #define _RUNNER_HASHCODE                0xFEFEAAAA      \r
30 \r
31 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh);\r
32 \r
33 #ifndef WIN32\r
34 extern char**\r
35 environ;\r
36 #endif\r
37 \r
38 /* the unique tesh runner */\r
39 static runner_t\r
40 runner = NULL;\r
41 \r
42 /* wait for the tesh runner terminaison */\r
43 static void\r
44 runner_wait(void);\r
45 \r
46 static void*\r
47 runner_start_routine(void* p);\r
48 \r
49 \r
50 /* check the syntax of the tesh files if \r
51  * the check_syntax_flag is specified. Returns\r
52  * 0 if the syntax is clean.\r
53  */\r
54 static void\r
55 check_syntax(void);\r
56 \r
57 #ifdef WIN32\r
58 \r
59 static HANDLE \r
60 timer_handle = NULL;\r
61 \r
62 static void*\r
63 runner_start_routine(void* p)\r
64 {\r
65         \r
66     LARGE_INTEGER li;\r
67 \r
68     li.QuadPart=- runner->timeout * 10000000;   /* 10000000 = 10 000 000 * 100 nanoseconds = 1 second */\r
69 \r
70     /* create the waitable timer */\r
71     timer_handle = CreateWaitableTimer(NULL, TRUE, NULL);\r
72 \r
73     /* set a timer to wait for timeout seconds */\r
74     SetWaitableTimer(timer_handle, &li, 0, NULL, NULL, 0);\r
75     \r
76     /* wait for the timer */\r
77     WaitForSingleObject(timer_handle, INFINITE);\r
78         \r
79         if(runner->waiting)\r
80         {\r
81                 exit_code = ELEADTIME;\r
82                 runner->timeouted = 1;\r
83                 xbt_os_sem_release(units_sem);\r
84         }\r
85 \r
86         return NULL;\r
87 }\r
88 \r
89 #else\r
90 static void*\r
91 runner_start_routine(void* p)\r
92 {\r
93         struct timespec ts;\r
94 \r
95         ts.tv_sec = runner->timeout;\r
96         ts.tv_nsec = 0L;\r
97 \r
98         do\r
99         {\r
100                 nanosleep(&ts, &ts);\r
101         }while(EINTR == errno);\r
102         \r
103         if(errno)\r
104         {\r
105                 /* TODO process the error */\r
106         }\r
107         else\r
108         {\r
109                 if(runner->waiting)\r
110                 {\r
111                         exit_code = ELEADTIME;\r
112                         runner->timeouted = 1;\r
113                         xbt_os_sem_release(units_sem);\r
114                 }\r
115         }\r
116         \r
117         return NULL;\r
118 }\r
119 #endif\r
120 \r
121 \r
122 int\r
123 runner_init(int check_syntax_flag, int timeout, fstreams_t fstreams)\r
124 {\r
125         \r
126         int i;\r
127         char* val;\r
128         char buffer[PATH_MAX + 1] = {0};\r
129         int code;\r
130         const char* cstr;\r
131         variable_t variable;\r
132         \r
133         if(runner)\r
134                 return EALREADY;\r
135                 \r
136         runner = xbt_new0(s_runner_t, 1);\r
137         \r
138         if(!(runner->units = units_new(runner, fstreams)))\r
139         {\r
140                 free(runner);\r
141                 runner = NULL;\r
142                 return -1;\r
143         }\r
144 \r
145         runner->timeout = timeout;\r
146         runner->timeouted = 0;\r
147         runner->interrupted = 0;\r
148         runner->number_of_ended_units = 0;\r
149         runner->number_of_runned_units = 0;\r
150         runner->waiting = 0;\r
151         \r
152         runner->total_of_tests = 0;\r
153         runner->total_of_successeded_tests = 0;\r
154         runner->total_of_failed_tests = 0;\r
155         runner->total_of_interrupted_tests = 0;\r
156         \r
157         runner->total_of_units = 0;\r
158         runner->total_of_successeded_units = 0;\r
159         runner->total_of_failed_units = 0;\r
160         runner->total_of_interrupted_units = 0;\r
161         \r
162         runner->total_of_suites = 0;\r
163         runner->total_of_successeded_suites = 0;\r
164         runner->total_of_failed_suites = 0;\r
165         runner->total_of_interrupted_suites = 0;\r
166         \r
167         /* initialize the vector of variables */\r
168         runner->variables = xbt_dynar_new(sizeof(variable_t), (void_f_pvoid_t)variable_free);\r
169         \r
170         /* add the environment variables in the vector */\r
171         for(i = 0; environ[i] != NULL; i++)\r
172         {\r
173                 val = strchr(environ[i], '=');\r
174                 \r
175                 if(val)\r
176                 {\r
177                         val++;\r
178                                 \r
179                         if(val[0] != '\0')\r
180                                 strncpy(buffer, environ[i], (val - environ[i] -1));\r
181                                 \r
182                         if(!strcmp("TESH_PPID", buffer))\r
183                                 is_tesh_root = 0;\r
184                         \r
185                         variable = variable_new(buffer, val);\r
186                         variable->env = 1;\r
187                         xbt_dynar_push(runner->variables, &variable);\r
188                 }\r
189         }\r
190         \r
191         if(is_tesh_root)\r
192         {\r
193                 sprintf(buffer,"%d",getpid());\r
194                 \r
195                 #ifndef WIN32\r
196                 setenv("TESH_PPID", buffer, 0);\r
197                 #else\r
198                 SetEnvironmentVariable("TESH_PPID", buffer);\r
199                 #endif\r
200                 \r
201                 variable = variable_new("TESH_PPID", buffer);\r
202                 variable->env = 1;\r
203                         \r
204                 xbt_dynar_push(runner->variables, &variable);\r
205         }\r
206         \r
207         i = 0;\r
208         \r
209         /* add the errors variables */\r
210         while((cstr = error_get_at(i++, &code)))\r
211         {\r
212                 sprintf(buffer,"%d",code);\r
213                 variable = variable_new(cstr, buffer);\r
214                 variable->err = 1;\r
215                 xbt_dynar_push(runner->variables, &variable);\r
216         }\r
217         \r
218         /* if the user want check the syntax, check it */\r
219         if(check_syntax_flag)\r
220                 check_syntax();\r
221                 \r
222         return exit_code ? -1 : 0;\r
223                 \r
224 }\r
225 \r
226 void\r
227 runner_destroy(void)\r
228 {\r
229         units_free((void**)(&(runner->units)));\r
230 \r
231         xbt_dynar_free(&runner->variables);\r
232         \r
233         #ifdef WIN32\r
234         CloseHandle(timer_handle);\r
235         #endif\r
236 \r
237         if(runner->thread)\r
238                 xbt_os_thread_join(runner->thread, NULL);\r
239 \r
240         free(runner);\r
241         \r
242 \r
243         runner = NULL;\r
244 }\r
245 \r
246 void\r
247 runner_run(void)\r
248 {\r
249         /* allocate the mutex used by the units to asynchronously access \r
250          * to the properties of the runner.\r
251          */\r
252         xbt_os_mutex_t mutex = xbt_os_mutex_init();\r
253         \r
254         /* run all the units */\r
255         units_run_all(runner->units, mutex);\r
256         \r
257         if(!interrupted)\r
258                 runner_wait();\r
259         \r
260         /* if the runner is timeouted or receive a interruption request\r
261          * , interrupt all the active units.\r
262          */\r
263         if(runner->timeouted || interrupted)\r
264                 runner_interrupt();\r
265         \r
266         /* joins all the units */\r
267         units_join_all(runner->units);\r
268         \r
269         /* release the mutex resource */\r
270         xbt_os_mutex_destroy(mutex);\r
271 \r
272 }\r
273 \r
274 static void\r
275 runner_wait(void)\r
276 {\r
277         if(runner->timeout > 0)\r
278                 runner->thread = xbt_os_thread_create("", runner_start_routine, NULL);\r
279         \r
280         /* signal that the runner is waiting */\r
281         runner->waiting = 1;\r
282         \r
283         /* wait for the end of all the units */\r
284         xbt_os_sem_acquire(units_sem);\r
285         \r
286         runner->waiting = 0;\r
287 }\r
288 \r
289 \r
290 \r
291 /*\r
292  * interrupt all the active units.\r
293  * this function is called when the lead time of the execution is reached\r
294  * or when a failed unit requests an interruption of the execution.\r
295  */\r
296 void\r
297 runner_interrupt(void)\r
298 {\r
299         units_interrupt_all(runner->units);\r
300 }\r
301 \r
302 void\r
303 runner_summarize(void)\r
304 {\r
305         \r
306         if(!dry_run_flag)\r
307         {\r
308                 #ifndef WIN32\r
309                 struct rusage r_usage;\r
310                 #else\r
311                 FILETIME start_time;\r
312                 FILETIME exit_time;\r
313                 FILETIME kernel_time;\r
314                 FILETIME user_time;\r
315                 SYSTEMTIME si;\r
316                 #endif\r
317                 \r
318                 printf("\n  TEst SHell utility - mini shell specialized in running test units.\n");\r
319                 printf(" =============================================================================\n");\r
320                 \r
321                 units_summuarize(runner->units);\r
322                 \r
323                 printf(" =====================================================================%s\n",\r
324                 runner->total_of_failed_tests ? "== FAILED": (runner->total_of_interrupted_tests || runner->total_of_interrupted_units) ? "==== INTR" : "====== OK");\r
325                 \r
326                 printf(" TOTAL : Suite(s): %.0f%% ok (%d suite(s): %d ok",\r
327                 (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
328                 runner->total_of_suites, runner->total_of_successeded_suites);\r
329                 \r
330                 if(runner->total_of_failed_suites > 0)\r
331                         printf(", %d failed", runner->total_of_failed_suites);\r
332                 \r
333                 if(runner->total_of_interrupted_suites > 0)\r
334                         printf(", %d interrupted)", runner->total_of_interrupted_suites);\r
335                 \r
336                 printf(")\n");  \r
337                 \r
338                 printf("         Unit(s):  %.0f%% ok (%d unit(s): %d ok",\r
339                 (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
340                 runner->total_of_units, runner->total_of_successeded_units);\r
341                 \r
342                 if(runner->total_of_failed_units > 0)\r
343                         printf(", %d failed", runner->total_of_failed_units);\r
344                 \r
345                 if(runner->total_of_interrupted_units > 0)\r
346                         printf(", %d interrupted)", runner->total_of_interrupted_units);\r
347                 \r
348                 printf(")\n");\r
349                 \r
350                 printf("         Test(s):  %.0f%% ok (%d test(s): %d ok",\r
351                 (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
352                 runner->total_of_tests, runner->total_of_successeded_tests); \r
353                 \r
354                 if(runner->total_of_failed_tests > 0)\r
355                         printf(", %d failed", runner->total_of_failed_tests);\r
356                 \r
357                 if(runner->total_of_interrupted_tests > 0)\r
358                         printf(", %d interrupted)", runner->total_of_interrupted_tests);\r
359                 \r
360                 printf(")\n\n");\r
361                 \r
362                 #ifndef WIN32\r
363                 if(!getrusage(RUSAGE_SELF, &r_usage))\r
364                 {\r
365                 \r
366                         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
367                         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
368                 \r
369                         if(!getrusage(RUSAGE_CHILDREN, &r_usage))\r
370                         {\r
371                                 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
372                                 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
373                 \r
374                         }       \r
375                 }\r
376                 #else\r
377         \r
378                 if(GetProcessTimes(GetCurrentProcess(), &start_time, &exit_time, &kernel_time, &user_time))\r
379                 {\r
380                         FileTimeToSystemTime(&user_time, &si);\r
381                         \r
382                         printf("         Total tesh user time used:       %uhour(s) %uminute(s) %usecond(s) %millisecond(s)\n", si.wHour, si.wMinute, si.wSecond, si.wMilliseconds );\r
383                         \r
384                         FileTimeToSystemTime(&kernel_time, &si);\r
385                         \r
386                         printf("         Total tesh kernel time used:     %uhour(s) %uminute(s) %usecond(s) %millisecond(s)\n", si.wHour, si.wMinute, si.wSecond, si.wMilliseconds );\r
387                 }\r
388 \r
389 \r
390 \r
391                 #endif\r
392         }\r
393         else\r
394         {\r
395                 if(exit_code)\r
396                         ERROR0("Syntax error detected");\r
397                 else if(!exit_code)\r
398                         INFO0("Syntax 0K");\r
399         }\r
400 }\r
401 \r
402 static void\r
403 check_syntax(void)\r
404 {\r
405         if(!dry_run_flag)\r
406         {\r
407                 dry_run_flag = 1;\r
408                 \r
409                 runner_run();\r
410         \r
411                 dry_run_flag = 0;\r
412                 \r
413                 if(!exit_code)\r
414                 {\r
415                         if(!silent_flag)\r
416                                 INFO0("syntax checked (OK)");\r
417                         \r
418                         units_reset_all(runner->units);\r
419                 \r
420                 }\r
421                 else\r
422                         errno = exit_code;\r
423                 \r
424         }\r
425         else\r
426         {\r
427                 WARN0("mismatch in the syntax : --just-check-syntax and --check-syntax options at same time");\r
428         }\r
429 \r
430 }\r