/* File: cachingcompiler.c Written by: Ronny Wichers Schreur At: University of Nijmegen */ #include "Clean.h" #include "cachingcompiler.h" #include #include #include #include #include #if defined(I486) || defined (SOLARIS) || defined (LINUX) # include #endif #include #include #include #include static void log (char *format, ...) { #ifdef DEBUG va_list ap; va_start(ap, format); (void) vfprintf(stderr, format, ap); va_end(ap); fflush (stderr); #endif } static int wait_for_child (pid_t pid, char *child_name, int *status_p) { int result, stat; pid_t return_pid; return_pid = waitpid (pid, &stat, 0); if (return_pid == -1) /* child exited before call to waitpid */ return 0; if (return_pid != pid) { fprintf (stderr, "wait_for_child: unexpected pid result (%d)\n", (int) return_pid); exit (1); } *status_p=stat; result = WEXITSTATUS (stat); if (WIFSIGNALED(stat) != 0) log ("%s signaled (%d)\n",child_name, (int) WTERMSIG(stat)); else if (WIFEXITED (stat)) log ("%s exited normally (%d)\n", child_name, (int) WEXITSTATUS(stat)); else log ("%s exited abnormally (%d)\n",child_name, (int) result); return result; } static void error (char *error_string) { fprintf (stderr,"%s\n",error_string); } static int compiler_initialised=0; static pid_t compiler_pid=0; static char *compiler_commands_name=NULL, *compiler_results_name=NULL; static FILE *compiler_commands, *compiler_results; int stop_caching_compiler (void) { int r,status; log ("stop_caching_compiler\n"); if (compiler_pid != 0) { pid_t pid; pid = compiler_pid; compiler_pid = 0; log ("stop_caching_compiler: compiler running\n"); fputs ("quit\n", compiler_commands); fflush (compiler_commands); r=wait_for_child (pid, "Clean compiler",&status); if (r!=0) { log ("r=%d status=%xd\n", r, status); error ("clm: error after stopping compiler"); exit (1); } } return 0; } static void cleanup_compiler (void) { log ("cleanup_compiler\n"); stop_caching_compiler (); if (compiler_commands_name != NULL) { log ("cleanup_compiler: unlink commands\n"); if (unlink (compiler_commands_name) != 0) perror ("clm: unlink compiler commands pipe"); compiler_commands_name = NULL; } if (compiler_results_name != NULL) { log ("cleanup_compiler: unlink results\n"); if (unlink (compiler_results_name) != 0) perror ("clm: unlink compiler results pipe"); compiler_results_name = NULL; } } static void cleanup_compiler_at_exit (void) { log ("cleanup_compiler_on_exit\n"); cleanup_compiler (); } static void cleanup_compiler_on_signal (int signal_no) { log ("cleanup_compiler_on_signal\n"); cleanup_compiler (); } static void child_died (int signal_no) { log ("child_died\n"); if (compiler_pid != 0) { log ("cocl exited abnormally\n"); compiler_pid=0; } } static void init_caching_compiler(void) { log ("init_caching_compiler\n"); if (atexit (cleanup_compiler_at_exit) != 0) { perror("clm: atexit install cleanup routine"); exit(1); } /* if (signal (SIGCHLD, child_died) == SIG_ERR) { perror("clm: signal install child died routine"); exit(1); } if (signal (SIGINT, cleanup_compiler_on_signal) == SIG_ERR) { perror("clm: signal install cleanup routine"); exit(1); } */ compiler_initialised=1; } int start_caching_compiler (CleanCharArray cocl_path) { log ("start_caching_compiler\n"); if (compiler_pid != 0) return 0; if (!compiler_initialised) init_caching_compiler (); if (compiler_commands_name == NULL) { #if 1 static char compiler_commands_file_name[]="/tmp/comXXXXXX"; int fd; fd=mkstemp (compiler_commands_file_name); if (fd<0){ perror ("clm: mkstemp failed"); } close (fd); unlink (compiler_commands_file_name); compiler_commands_name=compiler_commands_file_name; #else compiler_commands_name=tempnam (NULL, "com"); #endif if (mkfifo(compiler_commands_name, S_IRUSR | S_IWUSR)) { perror("clm: mkfifo compiler commands pipe"); compiler_commands_name=NULL; exit(1); } } if (compiler_results_name == NULL) { #if 1 static char compiler_results_file_name[]="/tmp/resXXXXXX"; int fd; fd=mkstemp (compiler_results_file_name); if (fd<0){ perror ("clm: mkstemp failed"); } close (fd); unlink (compiler_results_file_name); compiler_results_name=compiler_results_file_name; #else compiler_results_name=tempnam (NULL, "res"); #endif if (mkfifo(compiler_results_name, S_IRUSR | S_IWUSR)) { perror("clm: mkfifo compiler results pipe"); compiler_results_name=NULL; exit(1); } } compiler_pid=fork(); if (compiler_pid<0) error ("Fork failed"); if (compiler_pid==0){ execlp ((char *)cocl_path, "cocl", "--pipe", compiler_commands_name, compiler_results_name, (char *) 0); log ("cocl path = %s\n", cocl_path); perror ("clm: can't start the clean compiler"); exit(1); } if ((compiler_commands=fopen(compiler_commands_name, "w")) == NULL) { perror("clm: fopen compiler commands pipe"); exit(1); } if ((compiler_results=fopen(compiler_results_name, "r")) == NULL) { perror("clm: fopen compiler commands pipe"); exit(1); } return (0); } #define RESULT_SIZE (sizeof (int)+2) int call_caching_compiler (CleanCharArray args) { int r; char result_string[RESULT_SIZE], *end; #if defined (LINUX) void (*oldhandler)(int); oldhandler = signal (SIGALRM, SIG_IGN); #endif log ("call_caching_compiler\n"); if (compiler_pid == 0) error ("call_compiler: compiler not running"); fputs ((const char *) args,compiler_commands); fputc ('\n',compiler_commands); fflush (compiler_commands); if (fgets(result_string,RESULT_SIZE,compiler_results) == NULL){ perror ("clm: reading compiler result failed"); /* exit (1); */ #if defined (LINUX) (void) signal (SIGALRM, oldhandler); #endif return 0; } r=(int)strtol (result_string,&end,0); if (*end != '\n'){ perror ("clm: non integer compiler result"); exit (1); } /* FIXME, clm/CleanIDE don't correspond return r>=0; */ #if defined (LINUX) (void) signal (SIGALRM, oldhandler); #endif return r; }