-/*\r
- * src/runner.c - type representing the runner.\r
- *\r
- * Copyright 2008,2009 Martin Quinson, Malek Cherier All right reserved. \r
- *\r
- * This program is free software; you can redistribute it and/or modify it \r
- * under the terms of the license (GNU LGPL) which comes with this package.\r
- *\r
- * Purpose:\r
- * This file contains all the definitions of the functions related with\r
- * the tesh runner type.\r
- *\r
- */\r
- \r
-#include <runner.h>\r
-#include <units.h>\r
-#include <unit.h>\r
-#include <xerrno.h>\r
-#include <variable.h>\r
-\r
-#include <errno.h> /* for error code */\r
-#include <stdlib.h> /* for calloc() */\r
-#include <stdio.h>\r
-\r
-#ifndef WIN32\r
-#include <sys/resource.h>\r
-#endif\r
-\r
-#define _RUNNER_HASHCODE 0xFEFEAAAA \r
-\r
-XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh);\r
-\r
-#ifndef WIN32\r
-extern char**\r
-environ;\r
-#endif\r
-\r
-/* the unique tesh runner */\r
-static runner_t\r
-runner = NULL;\r
-\r
-/* wait for the tesh runner terminaison */\r
-static void\r
-runner_wait(void);\r
-\r
-static void*\r
-runner_start_routine(void* p);\r
-\r
-\r
-/* check the syntax of the tesh files if \r
- * the check_syntax_flag is specified. Returns\r
- * 0 if the syntax is clean.\r
- */\r
-static void\r
-check_syntax(void);\r
-\r
-#ifdef WIN32\r
-\r
-static HANDLE \r
-timer_handle = NULL;\r
-\r
-static void*\r
-runner_start_routine(void* p)\r
-{\r
- \r
- LARGE_INTEGER li;\r
-\r
- li.QuadPart=- runner->timeout * 10000000; /* 10000000 = 10 000 000 * 100 nanoseconds = 1 second */\r
-\r
- /* create the waitable timer */\r
- timer_handle = CreateWaitableTimer(NULL, TRUE, NULL);\r
-\r
- /* set a timer to wait for timeout seconds */\r
- SetWaitableTimer(timer_handle, &li, 0, NULL, NULL, 0);\r
- \r
- /* wait for the timer */\r
- WaitForSingleObject(timer_handle, INFINITE);\r
- \r
- if(runner->waiting)\r
- {\r
- exit_code = ELEADTIME;\r
- runner->timeouted = 1;\r
- xbt_os_sem_release(units_sem);\r
- }\r
-\r
- return NULL;\r
-}\r
-\r
-#else\r
-static void*\r
-runner_start_routine(void* p)\r
-{\r
- struct timespec ts;\r
-\r
- ts.tv_sec = runner->timeout;\r
- ts.tv_nsec = 0L;\r
-\r
- do\r
- {\r
- nanosleep(&ts, &ts);\r
- }while(EINTR == errno);\r
- \r
- if(errno)\r
- {\r
- /* TODO process the error */\r
- }\r
- else\r
- {\r
- if(runner->waiting)\r
- {\r
- exit_code = ELEADTIME;\r
- runner->timeouted = 1;\r
- xbt_os_sem_release(units_sem);\r
- }\r
- }\r
- \r
- return NULL;\r
-}\r
-#endif\r
-\r
-\r
-int\r
-runner_init(int check_syntax_flag, int timeout, fstreams_t fstreams)\r
-{\r
- \r
- int i;\r
- char* val;\r
- char buffer[PATH_MAX + 1] = {0};\r
- int code;\r
- const char* cstr;\r
- variable_t variable;\r
- \r
- if(runner)\r
- return EALREADY;\r
- \r
- runner = xbt_new0(s_runner_t, 1);\r
- \r
- if(!(runner->units = units_new(runner, fstreams)))\r
- {\r
- free(runner);\r
- runner = NULL;\r
- return -1;\r
- }\r
-\r
- runner->timeout = timeout;\r
- runner->timeouted = 0;\r
- runner->interrupted = 0;\r
- runner->number_of_ended_units = 0;\r
- runner->number_of_runned_units = 0;\r
- runner->waiting = 0;\r
- \r
- runner->total_of_tests = 0;\r
- runner->total_of_successeded_tests = 0;\r
- runner->total_of_failed_tests = 0;\r
- runner->total_of_interrupted_tests = 0;\r
- \r
- runner->total_of_units = 0;\r
- runner->total_of_successeded_units = 0;\r
- runner->total_of_failed_units = 0;\r
- runner->total_of_interrupted_units = 0;\r
- \r
- runner->total_of_suites = 0;\r
- runner->total_of_successeded_suites = 0;\r
- runner->total_of_failed_suites = 0;\r
- runner->total_of_interrupted_suites = 0;\r
- \r
- /* initialize the vector of variables */\r
- runner->variables = xbt_dynar_new(sizeof(variable_t), (void_f_pvoid_t)variable_free);\r
- \r
- /* add the environment variables in the vector */\r
- for(i = 0; environ[i] != NULL; i++)\r
- {\r
- val = strchr(environ[i], '=');\r
- \r
- if(val)\r
- {\r
- val++;\r
- \r
- if(val[0] != '\0')\r
- strncpy(buffer, environ[i], (val - environ[i] -1));\r
- \r
- if(!strcmp("TESH_PPID", buffer))\r
- is_tesh_root = 0;\r
- \r
- variable = variable_new(buffer, val);\r
- variable->env = 1;\r
- xbt_dynar_push(runner->variables, &variable);\r
- }\r
- }\r
- \r
- if(is_tesh_root)\r
- {\r
- sprintf(buffer,"%d",getpid());\r
- \r
- #ifndef WIN32\r
- setenv("TESH_PPID", buffer, 0);\r
- #else\r
- SetEnvironmentVariable("TESH_PPID", buffer);\r
- #endif\r
- \r
- variable = variable_new("TESH_PPID", buffer);\r
- variable->env = 1;\r
- \r
- xbt_dynar_push(runner->variables, &variable);\r
- }\r
- \r
- i = 0;\r
- \r
- /* add the errors variables */\r
- while((cstr = error_get_at(i++, &code)))\r
- {\r
- sprintf(buffer,"%d",code);\r
- variable = variable_new(cstr, buffer);\r
- variable->err = 1;\r
- xbt_dynar_push(runner->variables, &variable);\r
- }\r
- \r
- /* if the user want check the syntax, check it */\r
- if(check_syntax_flag)\r
- check_syntax();\r
- \r
- return exit_code ? -1 : 0;\r
- \r
-}\r
-\r
-void\r
-runner_destroy(void)\r
-{\r
- units_free((void**)(&(runner->units)));\r
-\r
- xbt_dynar_free(&runner->variables);\r
- \r
- #ifdef WIN32\r
- CloseHandle(timer_handle);\r
- #endif\r
-\r
- if(runner->thread)\r
- xbt_os_thread_join(runner->thread, NULL);\r
-\r
- free(runner);\r
- \r
-\r
- runner = NULL;\r
-}\r
-\r
-void\r
-runner_run(void)\r
-{\r
- /* allocate the mutex used by the units to asynchronously access \r
- * to the properties of the runner.\r
- */\r
- xbt_os_mutex_t mutex = xbt_os_mutex_init();\r
- \r
- /* run all the units */\r
- units_run_all(runner->units, mutex);\r
- \r
- if(!interrupted)\r
- runner_wait();\r
- \r
- /* if the runner is timeouted or receive a interruption request\r
- * , interrupt all the active units.\r
- */\r
- if(runner->timeouted || interrupted)\r
- runner_interrupt();\r
- \r
- /* joins all the units */\r
- units_join_all(runner->units);\r
- \r
- /* release the mutex resource */\r
- xbt_os_mutex_destroy(mutex);\r
-\r
-}\r
-\r
-static void\r
-runner_wait(void)\r
-{\r
- if(runner->timeout > 0)\r
- runner->thread = xbt_os_thread_create("", runner_start_routine, NULL);\r
- \r
- /* signal that the runner is waiting */\r
- runner->waiting = 1;\r
- \r
- /* wait for the end of all the units */\r
- xbt_os_sem_acquire(units_sem);\r
- \r
- runner->waiting = 0;\r
-}\r
-\r
-\r
-\r
-/*\r
- * interrupt all the active units.\r
- * this function is called when the lead time of the execution is reached\r
- * or when a failed unit requests an interruption of the execution.\r
- */\r
-void\r
-runner_interrupt(void)\r
-{\r
- units_interrupt_all(runner->units);\r
-}\r
-\r
-void\r
-runner_summarize(void)\r
-{\r
- \r
- if(!dry_run_flag)\r
- {\r
- #ifndef WIN32\r
- struct rusage r_usage;\r
- #else\r
- FILETIME start_time;\r
- FILETIME exit_time;\r
- FILETIME kernel_time;\r
- FILETIME user_time;\r
- SYSTEMTIME si;\r
- #endif\r
- \r
- printf("\n TEst SHell utility - mini shell specialized in running test units.\n");\r
- printf(" =============================================================================\n");\r
- \r
- units_summuarize(runner->units);\r
- \r
- printf(" =====================================================================%s\n",\r
- runner->total_of_failed_tests ? "== FAILED": (runner->total_of_interrupted_tests || runner->total_of_interrupted_units) ? "==== INTR" : "====== OK");\r
- \r
- printf(" TOTAL : Suite(s): %.0f%% ok (%d suite(s): %d ok",\r
- (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
- runner->total_of_suites, runner->total_of_successeded_suites);\r
- \r
- if(runner->total_of_failed_suites > 0)\r
- printf(", %d failed", runner->total_of_failed_suites);\r
- \r
- if(runner->total_of_interrupted_suites > 0)\r
- printf(", %d interrupted)", runner->total_of_interrupted_suites);\r
- \r
- printf(")\n"); \r
- \r
- printf(" Unit(s): %.0f%% ok (%d unit(s): %d ok",\r
- (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
- runner->total_of_units, runner->total_of_successeded_units);\r
- \r
- if(runner->total_of_failed_units > 0)\r
- printf(", %d failed", runner->total_of_failed_units);\r
- \r
- if(runner->total_of_interrupted_units > 0)\r
- printf(", %d interrupted)", runner->total_of_interrupted_units);\r
- \r
- printf(")\n");\r
- \r
- printf(" Test(s): %.0f%% ok (%d test(s): %d ok",\r
- (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
- runner->total_of_tests, runner->total_of_successeded_tests); \r
- \r
- if(runner->total_of_failed_tests > 0)\r
- printf(", %d failed", runner->total_of_failed_tests);\r
- \r
- if(runner->total_of_interrupted_tests > 0)\r
- printf(", %d interrupted)", runner->total_of_interrupted_tests);\r
- \r
- printf(")\n\n");\r
- \r
- #ifndef WIN32\r
- if(!getrusage(RUSAGE_SELF, &r_usage))\r
- {\r
- \r
- 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
- 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
- \r
- if(!getrusage(RUSAGE_CHILDREN, &r_usage))\r
- {\r
- 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
- 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
- \r
- } \r
- }\r
- #else\r
- \r
- if(GetProcessTimes(GetCurrentProcess(), &start_time, &exit_time, &kernel_time, &user_time))\r
- {\r
- FileTimeToSystemTime(&user_time, &si);\r
- \r
- printf(" Total tesh user time used: %uhour(s) %uminute(s) %usecond(s) %millisecond(s)\n", si.wHour, si.wMinute, si.wSecond, si.wMilliseconds );\r
- \r
- FileTimeToSystemTime(&kernel_time, &si);\r
- \r
- printf(" Total tesh kernel time used: %uhour(s) %uminute(s) %usecond(s) %millisecond(s)\n", si.wHour, si.wMinute, si.wSecond, si.wMilliseconds );\r
- }\r
-\r
-\r
-\r
- #endif\r
- }\r
- else\r
- {\r
- if(exit_code)\r
- ERROR0("Syntax error detected");\r
- else if(!exit_code)\r
- INFO0("Syntax 0K");\r
- }\r
-}\r
-\r
-static void\r
-check_syntax(void)\r
-{\r
- if(!dry_run_flag)\r
- {\r
- dry_run_flag = 1;\r
- \r
- runner_run();\r
- \r
- dry_run_flag = 0;\r
- \r
- if(!exit_code)\r
- {\r
- if(!silent_flag)\r
- INFO0("syntax checked (OK)");\r
- \r
- units_reset_all(runner->units);\r
- \r
- }\r
- else\r
- errno = exit_code;\r
- \r
- }\r
- else\r
- {\r
- WARN0("mismatch in the syntax : --just-check-syntax and --check-syntax options at same time");\r
- }\r
-\r
-}\r
+/*
+ * src/runner.c - type representing the runner.
+ *
+ * Copyright 2008,2009 Martin Quinson, Malek Cherier All right reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package.
+ *
+ * Purpose:
+ * This file contains all the definitions of the functions related with
+ * the tesh runner type.
+ *
+ */
+#include <runner.h>
+#include <units.h>
+#include <unit.h>
+#include <xerrno.h>
+#include <variable.h>
+
+#include <errno.h> /* for error code */
+#include <stdlib.h> /* for calloc() */
+#include <stdio.h>
+
+#include <readline.h>
+
+#ifndef WIN32
+#include <sys/resource.h>
+#include <explode.h>
+#endif
+
+#define _RUNNER_HASHCODE 0xFEFEAAAA
+
+XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh);
+
+#if (!defined(__BUILTIN) && defined(__CHKCMD))
+static const char* builtin[] =
+{
+ "alias",
+ "bind",
+ "builtin",
+ "caller",
+ "cd",
+ "command",
+ "compgen",
+ "complete",
+ "declare",
+ "disown",
+ "echo",
+ "enable",
+ "eval",
+ "exec",
+ "export",
+ "false",
+ "fc",
+ "function",
+ "getopts",
+ "hash",
+ "history",
+ "jobs",
+ "let",
+ "logout",
+ "printf",
+ "pwd",
+ "readonly",
+ "shift",
+ "shopt",
+ "source",
+ "suspend",
+ "test",
+ "time",
+ "times",
+ "trap",
+ "true",
+ "type",
+ "typeset",
+ "ulimit",
+ "umask",
+ "unalias",
+ "unset",
+ NULL
+};
+
+#define __BUILTIN_MAX ((size_t)42)
+#endif
+
+#ifndef WIN32
+extern char**
+environ;
+#endif
+
+/* the unique tesh runner */
+static runner_t
+runner = NULL;
+
+/* wait for the tesh runner terminaison */
+static void
+runner_wait(void);
+
+static void*
+runner_start_routine(void* p);
+
+
+/* check the syntax of the tesh files if
+ * the check_syntax_flag is specified. Returns
+ * 0 if the syntax is clean.
+ */
+/*static void
+check_syntax(void);*/
+
+#ifdef WIN32
+
+static HANDLE
+timer_handle = NULL;
+
+
+static void*
+runner_start_routine(void* p)
+{
+
+ LARGE_INTEGER li;
+
+ li.QuadPart=- runner->timeout * 10000000; /* 10000000 = 10 000 000 * 100 nanoseconds = 1 second */
+
+ /* create the waitable timer */
+ timer_handle = CreateWaitableTimer(NULL, TRUE, NULL);
+
+ /* set a timer to wait for timeout seconds */
+ SetWaitableTimer(timer_handle, &li, 0, NULL, NULL, 0);
+
+ /* wait for the timer */
+ WaitForSingleObject(timer_handle, INFINITE);
+
+ if(runner->waiting)
+ {
+ exit_code = ELEADTIME;
+ err_kind = 1;
+ runner->timeouted = 1;
+ xbt_os_sem_release(units_sem);
+ }
+
+ return NULL;
+}
+
+#else
+static void*
+runner_start_routine(void* p)
+{
+ struct timespec ts;
+ int timeout = runner->timeout;
+
+
+ while(timeout-- && runner->waiting)
+ {
+ ts.tv_sec = 1;
+ ts.tv_nsec = 0L;
+
+ do
+ {
+ nanosleep(&ts, &ts);
+ }while(EINTR == errno);
+ }
+
+ if(errno)
+ {
+ /* TODO process the error */
+ }
+ else
+ {
+ if(runner->waiting)
+ {
+ exit_code = ELEADTIME;
+ err_kind = 1;
+ runner->timeouted = 1;
+ xbt_os_sem_release(units_sem);
+ }
+ }
+
+ return NULL;
+}
+#endif
+
+
+int
+runner_init(/*int check_syntax_flag, */int timeout, fstreams_t fstreams)
+{
+
+ int i;
+ char* val;
+ char buffer[PATH_MAX + 1] = {0};
+ int code;
+ const char* cstr;
+ variable_t variable;
+
+ #if (defined(__CHKCMD) && defined(__BUILTIN))
+ FILE* s;
+ int n = 0;
+ size_t len;
+ char* line = NULL;
+ int is_blank;
+ #endif
+
+
+ if(runner)
+ {
+ ERROR0("The runner is already initialized");
+ return -1;
+ }
+
+ runner = xbt_new0(s_runner_t, 1);
+
+ runner->path = NULL;
+ runner->builtin = NULL;
+
+ if(!(runner->units = units_new(runner, fstreams)))
+ {
+ free(runner);
+ runner = NULL;
+ return -1;
+ }
+
+ runner->timeout = timeout;
+ runner->timeouted = 0;
+ runner->interrupted = 0;
+ runner->number_of_ended_units = 0;
+ runner->number_of_runned_units = 0;
+ runner->waiting = 0;
+
+ runner->total_of_tests = 0;
+ runner->total_of_successeded_tests = 0;
+ runner->total_of_failed_tests = 0;
+ runner->total_of_interrupted_tests = 0;
+
+ runner->total_of_units = 0;
+ runner->total_of_successeded_units = 0;
+ runner->total_of_failed_units = 0;
+ runner->total_of_interrupted_units = 0;
+
+ runner->total_of_suites = 0;
+ runner->total_of_successeded_suites = 0;
+ runner->total_of_failed_suites = 0;
+ runner->total_of_interrupted_suites = 0;
+
+ /* initialize the vector of variables */
+ runner->variables = xbt_dynar_new(sizeof(variable_t), (void_f_pvoid_t)variable_free);
+
+ /* add the environment variables in the vector */
+ for(i = 0; environ[i] != NULL; i++)
+ {
+
+ val = strchr(environ[i], '=');
+
+ if(val)
+ {
+
+
+ val++;
+
+ if(val[0] != '\0')
+ strncpy(buffer, environ[i], (val - environ[i] -1));
+
+ if(!strcmp("TESH_PPID", buffer))
+ is_tesh_root = 0;
+
+ variable = variable_new(buffer, val);
+ variable->env = 1;
+ xbt_dynar_push(runner->variables, &variable);
+
+ #ifndef WIN32
+ if(!strcmp("PATH", buffer))
+ {
+ char* p;
+ int j,k, len;
+
+ /* get the list of paths */
+ runner->path = explode(':', val);
+
+ /* remove spaces and backslahes at the end of the path */
+ for (k = 0; runner->path[k] != NULL; k++)
+ {
+ p = runner->path[k];
+
+ len = strlen(p);
+
+ for(j = len - 1; p[j] == '/' || p[j] == ' '; j--)
+ p[j] = '\0';
+ }
+ }
+ #endif
+
+ memset(buffer, 0, PATH_MAX + 1);
+ }
+ }
+
+ if(is_tesh_root)
+ {
+ char* tesh_dir = getcwd(NULL, 0);
+
+ sprintf(buffer,"%d",getpid());
+
+ #ifndef WIN32
+ setenv("TESH_PPID", buffer, 0);
+ setenv("TESH_DIR", tesh_dir, 0);
+ #else
+ SetEnvironmentVariable("TESH_PPID", buffer);
+ SetEnvironmentVariable("TESH_DIR", tesh_dir);
+ #endif
+
+ variable = variable_new("TESH_PPID", buffer);
+ variable->err = 1;
+
+ xbt_dynar_push(runner->variables, &variable);
+
+ free(tesh_dir);
+ }
+
+ variable = variable_new("EXIT_SUCCESS", "0");
+ variable->err = 1;
+
+ xbt_dynar_push(runner->variables, &variable);
+
+ variable = variable_new("EXIT_FAILURE", "1");
+ variable->err = 1;
+
+ xbt_dynar_push(runner->variables, &variable);
+
+ variable = variable_new("TRUE", "0");
+ variable->err = 1;
+
+ xbt_dynar_push(runner->variables, &variable);
+
+ variable = variable_new("FALSE", "1");
+ variable->err = 1;
+
+ xbt_dynar_push(runner->variables, &variable);
+
+
+ i = 0;
+
+ /* add the errors variables */
+ while((cstr = error_get_at(i++, &code)))
+ {
+ sprintf(buffer,"%d",code);
+ variable = variable_new(cstr, buffer);
+ variable->err = 1;
+ xbt_dynar_push(runner->variables, &variable);
+ }
+
+ /* if the user want check the syntax, check it */
+ /*if(check_syntax_flag)
+ check_syntax();
+ */
+
+
+ #if defined(__CHKCMD)
+ #if defined(__BUILTIN)
+ if(!is_tesh_root)
+ {
+ /* compute the full path the builtin.def file */
+ #ifndef WIN32
+ sprintf(buffer,"%s/builtin.def",getenv("TESH_DIR"));
+ #else
+ GetEnvironmentVariable("TESH_DIR",buffer,PATH_MAX + 1);
+ #endif
+
+ s = fopen(buffer, "r");
+
+ }
+ else
+ {
+ s = fopen("builtin.def", "r");
+ }
+
+ if(s)
+ {
+ fpos_t begin;
+
+ fgetpos(s, &begin);
+
+ while(readline(s, &line, &len) != -1)
+ {
+ i = 0;
+ is_blank = 1;
+
+
+ while(line[i] != '\0')
+ {
+ if (line[i] != ' ' && line[i] != '\t' && line[i]!='\n' && line[i]!='\r')
+ {
+ is_blank = 0;
+ break;
+ }
+
+ i++;
+ }
+
+ if(!is_blank)
+ n++;
+
+
+ }
+
+ fsetpos(s, &begin);
+ free(line);
+ line = NULL;
+
+ if(n)
+ {
+ char* l;
+
+ runner->builtin = xbt_new0(char*, n + 1); /* (char**) calloc(n + 1, sizeof(char*));*/
+
+ n = 0;
+
+ while(readline(s, &line, &len) != -1)
+ {
+ i = 0;
+ is_blank = 1;
+
+ while(line[i] != '\0')
+ {
+ if (line[i] != ' ' && line[i] != '\t' && line[i]!='\n' && line[i]!='\r')
+ {
+ is_blank = 0;
+ break;
+ }
+
+ i++;
+ }
+
+ if(!is_blank)
+ {
+ l = strdup(line);
+
+ l[strlen(l) - 1] = '\0';
+
+ (runner->builtin)[n++] = l;
+
+ }
+ }
+
+ }
+ else
+ {
+ WARN0("The file `(builtin.def)' is empty");
+ free(runner->builtin);
+ runner->builtin = NULL;
+ }
+
+
+ fclose(s);
+
+ if(line)
+ free(line);
+
+ }
+ else
+ {
+ ERROR0("File `(builtin.def)' not found");
+ return -1;
+ }
+ #else
+
+ runner->builtin = xbt_new0(char*, __BUILTIN_MAX + 1); /* (char**) calloc(__BUILTIN_MAX + 1, sizeof(char*));*/
+
+ for(i = 0; i < __BUILTIN_MAX; i++)
+ runner->builtin[i] = strdup(builtin[i]);
+ #endif
+ #endif
+
+ return exit_code ? -1 : 0;
+}
+
+void
+runner_destroy(void)
+{
+ int i;
+
+ if(runner->units)
+ units_free((void**)(&(runner->units)));
+
+ if(runner->variables)
+ xbt_dynar_free(&runner->variables);
+
+ #ifdef WIN32
+ CloseHandle(timer_handle);
+ #endif
+
+ if(runner->thread)
+ xbt_os_thread_join(runner->thread, NULL);
+
+ if(runner->path)
+ {
+ for (i = 0; runner->path[i] != NULL; i++)
+ free(runner->path[i]);
+
+ free(runner->path);
+ }
+
+ if(runner->builtin)
+ {
+ for (i = 0; runner->builtin[i] != NULL; i++)
+ free(runner->builtin[i]);
+
+ free(runner->builtin);
+ }
+
+ free(runner);
+
+
+ runner = NULL;
+}
+
+void
+runner_run(void)
+{
+ /* allocate the mutex used by the units to asynchronously access
+ * to the properties of the runner.
+ */
+ xbt_os_mutex_t mutex = xbt_os_mutex_init();
+
+ /* run all the units */
+ units_run_all(runner->units, mutex);
+
+ if(!interrupted)
+ runner_wait();
+
+ /* if the runner is timeouted or receive a interruption request
+ * , interrupt all the active units.
+ */
+ if(runner->timeouted || interrupted)
+ runner_interrupt();
+
+ /* joins all the units */
+ units_join_all(runner->units);
+
+ /* release the mutex resource */
+ xbt_os_mutex_destroy(mutex);
+
+}
+
+static void
+runner_wait(void)
+{
+ if(runner->timeout > 0)
+ runner->thread = xbt_os_thread_create("", runner_start_routine, NULL);
+
+ /* signal that the runner is waiting */
+ runner->waiting = 1;
+
+ /* wait for the end of all the units */
+ xbt_os_sem_acquire(units_sem);
+
+ runner->waiting = 0;
+}
+
+
+
+/*
+ * interrupt all the active units.
+ * this function is called when the lead time of the execution is reached
+ * or when a failed unit requests an interruption of the execution.
+ */
+void
+runner_interrupt(void)
+{
+ units_interrupt_all(runner->units);
+}
+
+void
+runner_summarize(void)
+{
+
+ if(!dry_run_flag)
+ {
+ #ifndef WIN32
+ struct rusage r_usage;
+ #else
+ FILETIME start_time;
+ FILETIME exit_time;
+ FILETIME kernel_time;
+ FILETIME user_time;
+ SYSTEMTIME si;
+ #endif
+
+ printf("\n TEst SHell utility - mini shell specialized in running test units.\n");
+ printf(" =============================================================================\n");
+
+ units_summuarize(runner->units);
+
+ printf(" =====================================================================%s\n",
+ runner->total_of_failed_tests ? "== FAILED": (runner->total_of_interrupted_tests || runner->total_of_interrupted_units) ? "==== INTR" : "====== OK");
+
+ printf(" TOTAL : Suite(s): %.0f%% ok (%d suite(s): %d ok",
+ (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),
+ runner->total_of_suites, runner->total_of_successeded_suites);
+
+ if(runner->total_of_failed_suites > 0)
+ printf(", %d failed", runner->total_of_failed_suites);
+
+ if(runner->total_of_interrupted_suites > 0)
+ printf(", %d interrupted)", runner->total_of_interrupted_suites);
+
+ printf(")\n");
+
+ printf(" Unit(s): %.0f%% ok (%d unit(s): %d ok",
+ (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),
+ runner->total_of_units, runner->total_of_successeded_units);
+
+ if(runner->total_of_failed_units > 0)
+ printf(", %d failed", runner->total_of_failed_units);
+
+ if(runner->total_of_interrupted_units > 0)
+ printf(", %d interrupted)", runner->total_of_interrupted_units);
+
+ printf(")\n");
+
+ printf(" Test(s): %.0f%% ok (%d test(s): %d ok",
+ (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),
+ runner->total_of_tests, runner->total_of_successeded_tests);
+
+ if(runner->total_of_failed_tests > 0)
+ printf(", %d failed", runner->total_of_failed_tests);
+
+ if(runner->total_of_interrupted_tests > 0)
+ printf(", %d interrupted)", runner->total_of_interrupted_tests);
+
+ printf(")\n\n");
+
+ #ifndef WIN32
+ if(!getrusage(RUSAGE_SELF, &r_usage))
+ {
+
+ 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);
+ 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);
+
+ if(!getrusage(RUSAGE_CHILDREN, &r_usage))
+ {
+ 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);
+ 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);
+
+ }
+ }
+ #else
+
+ if(GetProcessTimes(GetCurrentProcess(), &start_time, &exit_time, &kernel_time, &user_time))
+ {
+ FileTimeToSystemTime(&user_time, &si);
+
+ printf(" Total tesh user time used: %uhour(s) %uminute(s) %usecond(s) %millisecond(s)\n", si.wHour, si.wMinute, si.wSecond, si.wMilliseconds );
+
+ FileTimeToSystemTime(&kernel_time, &si);
+
+ printf(" Total tesh kernel time used: %uhour(s) %uminute(s) %usecond(s) %millisecond(s)\n", si.wHour, si.wMinute, si.wSecond, si.wMilliseconds );
+ }
+
+
+
+ #endif
+ }
+ else
+ {
+ if(exit_code)
+ ERROR0("Syntax NOK");
+ else if(!exit_code)
+ INFO0("Syntax 0K");
+ }
+}
+
+int
+runner_is_timedout(void)
+{
+ return runner->timeouted;
+}
+