Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
some new files used to check Tesh
[simgrid.git] / tools / tesh2 / src / runner.c
index d71d459..80b2a5f 100644 (file)
@@ -1,19 +1,92 @@
+/*
+ * 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 <error.h>
+#include <xerrno.h>
 #include <variable.h>
 
 #include <errno.h>     /* for error code       */
 #include <stdlib.h>    /* for calloc()         */
 #include <stdio.h>
 
-#include <sys/resource.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
@@ -28,17 +101,18 @@ runner_start_routine(void* p);
 
 
 /* check the syntax of the tesh files if 
- * the want_check_syntax is specified. Returns
+ * the check_syntax_flag is specified. Returns
  * 0 if the syntax is clean.
  */
-static void
-check_syntax(void);
+/*static void
+check_syntax(void);*/
 
 #ifdef WIN32
 
 static HANDLE 
 timer_handle = NULL;
 
+
 static void*
 runner_start_routine(void* p)
 {
@@ -59,6 +133,7 @@ runner_start_routine(void* p)
        if(runner->waiting)
        {
                exit_code = ELEADTIME;
+               err_kind = 1;
                runner->timeouted = 1;
                xbt_os_sem_release(units_sem);
        }
@@ -71,14 +146,19 @@ static void*
 runner_start_routine(void* p)
 {
        struct timespec ts;
-
-       ts.tv_sec = runner->timeout;
-       ts.tv_nsec = 0L;
-
-       do
+       int timeout = runner->timeout;
+       
+       
+       while(timeout-- && runner->waiting)
        {
-               nanosleep(&ts, &ts);
-       }while(EINTR == errno);
+               ts.tv_sec = 1;
+               ts.tv_nsec = 0L;
+
+               do
+               {
+                       nanosleep(&ts, &ts);
+               }while(EINTR == errno);
+       }
        
        if(errno)
        {
@@ -89,6 +169,7 @@ runner_start_routine(void* p)
                if(runner->waiting)
                {
                        exit_code = ELEADTIME;
+                       err_kind = 1;
                        runner->timeouted = 1;
                        xbt_os_sem_release(units_sem);
                }
@@ -100,25 +181,41 @@ runner_start_routine(void* p)
 
 
 int
-runner_init(int want_check_syntax, int timeout, fstreams_t fstreams)
+runner_init(/*int check_syntax_flag, */int timeout, fstreams_t fstreams)
 {
        
        int i;
        char* val;
-       char buffer[MAX_PATH + 1] = {0};
+       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;
+       }
                
-       if(!(runner = (runner_t)calloc(1, sizeof(s_runner_t))))
-               return errno;
+       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 errno;
+               return -1;
        }
 
        runner->timeout = timeout;
@@ -144,62 +241,271 @@ runner_init(int want_check_syntax, int timeout, fstreams_t fstreams)
        runner->total_of_interrupted_suites = 0;
        
        /* initialize the vector of variables */
-       runner->variables = vector_new(32, (fn_finalize_t)variable_free);
-       
+       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);
                        
-                       /*printf("Add the environment variable %s %s\n", variable->name, variable->val);*/
-                       
-                       vector_push_back(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;
-               vector_push_back(runner->variables, variable);
+               xbt_dynar_push(runner->variables, &variable);
        }
        
-       
-       if(want_check_syntax)
+       /* 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;
+               }
                
-       return exit_code;
+
+               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)
 {
-       units_free((void**)(&(runner->units)));
-       vector_free(&runner->variables);
+       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;
 }
@@ -207,10 +513,12 @@ runner_destroy(void)
 void
 runner_run(void)
 {
-       xbt_os_mutex_t mutex;
-
-       mutex = xbt_os_mutex_init();
+       /* 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)
@@ -222,8 +530,10 @@ runner_run(void)
        if(runner->timeouted || interrupted)
                runner_interrupt();
        
+       /* joins all the units */
        units_join_all(runner->units);
-
+       
+       /* release the mutex resource */
        xbt_os_mutex_destroy(mutex);
 
 }
@@ -233,6 +543,7 @@ 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;
        
@@ -256,21 +567,26 @@ runner_interrupt(void)
 }
 
 void
-runner_display_status(void)
+runner_summarize(void)
 {
        
-       if(!want_dry_run)
+       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("\033[1m");*/
                printf("\n  TEst SHell utility - mini shell specialized in running test units.\n");
                printf(" =============================================================================\n");
-               /*printf("\033[0m");*/
                
-               units_verbose(runner->units);
+               units_summuarize(runner->units);
                
-               /*printf("\033[1m");*/
                printf(" =====================================================================%s\n",
                runner->total_of_failed_tests ? "== FAILED": (runner->total_of_interrupted_tests || runner->total_of_interrupted_units) ? "==== INTR" : "====== OK");
                
@@ -300,7 +616,7 @@ runner_display_status(void)
                
                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); 
+               runner->total_of_tests, runner->total_of_successeded_tests);
                
                if(runner->total_of_failed_tests > 0)
                        printf(", %d failed", runner->total_of_failed_tests);
@@ -310,7 +626,7 @@ runner_display_status(void)
                
                printf(")\n\n");
                
-               
+               #ifndef WIN32
                if(!getrusage(RUSAGE_SELF, &r_usage))
                {
                
@@ -324,42 +640,35 @@ runner_display_status(void)
                
                        }       
                }
-               
-               /*printf("\033[0m");*/
+               #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 error detected");
+                       ERROR0("Syntax NOK");
                else if(!exit_code)
                        INFO0("Syntax 0K");
        }
 }
 
-static void
-check_syntax(void)
+int
+runner_is_timedout(void)
 {
-       if(!want_dry_run)
-       {
-               want_dry_run = 1;
-               
-               runner_run();
-       
-               want_dry_run = 0;
-               
-               if(!exit_code)
-               {
-                       if(!want_silent)
-                               INFO0("syntax checked (OK)");
-                       
-                       units_reset_all(runner->units);
-               
-               }
-               
-       }
-       else
-       {
-               WARN0("mismatch in the syntax : --just-check-syntax and --check-syntax options at same time");
-       }
-
+       return runner->timeouted;
 }
+