]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
make the compile as atomic as possible
authorAndrew Tridgell <tridge@samba.org>
Wed, 27 Mar 2002 00:39:06 +0000 (01:39 +0100)
committerAndrew Tridgell <tridge@samba.org>
Wed, 27 Mar 2002 00:39:06 +0000 (01:39 +0100)
README
ccache.c
ccache.h
execute.c

diff --git a/README b/README
index 64f7dbbd952dba6cac7162464db1fe32c4407cc6..91f0ee5693942bc40c560b43622aa65f5b38f15d 100644 (file)
--- a/README
+++ b/README
@@ -84,6 +84,18 @@ Note however that ccache is a very new piece of code (as of March
 2002) whereas Erik's scripts have had a *lot* more testing. 
 
 
+How it works
+------------
+
+The basic idea is to detect when you are compiling exactly the same
+code a 2nd time and use the previously compiled output. You detect
+that it is the same code by forming a hash of:
+
+  - the pre-processor output from running the compiler with -E
+  - the command line options
+  - the real compilers size and modification time
+  - any stderr output generated by the compiler
+
 ===================
 tridge@samba.org
 March 2002
index ce537f768154c840255789120d712a8312c6443c..87c17a071b62caf38c18a1af2d321c3f772da8ac 100644 (file)
--- a/ccache.c
+++ b/ccache.c
@@ -43,31 +43,52 @@ static void failed(void)
 /* run the real compiler and put the result in cache */
 static void to_cache(ARGS *args)
 {
-       char *path_stdout, *path_status, *path_stderr;
+       char *path_stderr;
+       char *tmp_stdout, *tmp_stderr, *tmp_hashname;
        struct stat st;
+       int status;
 
-       x_asprintf(&path_status, "%s.status", hashname);
-       x_asprintf(&path_stderr, "%s.stderr", hashname);
-       x_asprintf(&path_stdout, "%s.stdout", hashname);
+       x_asprintf(&tmp_stdout, "%s/tmp.stdout.%d", cache_dir, getpid());
+       x_asprintf(&tmp_stderr, "%s/tmp.stderr.%d", cache_dir, getpid());
+       x_asprintf(&tmp_hashname, "%s/tmp.hash.%d", cache_dir, getpid());
 
        args_add(args, "-o");
-       args_add(args, hashname);
+       args_add(args, tmp_hashname);
+       status = execute(args->argv, tmp_stdout, tmp_stderr);
+       args->argc -= 2;
 
-       execute(args->argv, path_stdout, path_stderr, path_status);
+       if (status != 0) {
+               cc_log("compile of %s gave status = %d\n", output_file, status);
+               unlink(tmp_stdout);
+               unlink(tmp_stderr);
+               unlink(tmp_hashname);
+               failed();
+       }
 
-       args->argc -= 2;
+       if (stat(tmp_stdout, &st) != 0 || st.st_size != 0) {
+               cc_log("compiler produced stdout for %s\n", output_file);
+               unlink(tmp_stdout);
+               unlink(tmp_stderr);
+               unlink(tmp_hashname);
+               failed();
+       }
 
-       if (stat(path_stdout, &st) != 0 || st.st_size != 0) {
-               cc_log("compiler produced stdout!\n");
-               unlink(path_stdout);
-               unlink(path_stderr);
-               unlink(path_status);
-               unlink(hashname);
+       unlink(tmp_stdout);
+
+       x_asprintf(&path_stderr, "%s.stderr", hashname);
+
+       if (rename(tmp_hashname, hashname) != 0 ||
+           rename(tmp_stderr, path_stderr) != 0) {
+               cc_log("failed to rename tmp files\n");
                failed();
        }
 
-       unlink(path_stdout);
        cc_log("Placed %s into cache\n", output_file);
+
+       free(tmp_hashname);
+       free(tmp_stderr);
+       free(tmp_stdout);
+       free(path_stderr);
 }
 
 
@@ -117,10 +138,11 @@ static void stabs_hash(const char *fname)
 static void find_hash(ARGS *args)
 {
        int i;
-       char *path_stdout, *path_stderr, *path_status;
+       char *path_stdout, *path_stderr;
        char *hash_dir;
        char *s;
        struct stat st;
+       int status;
 
        hash_start();
 
@@ -141,12 +163,18 @@ static void find_hash(ARGS *args)
        /* now the run */
        x_asprintf(&path_stdout, "%s/tmp.stdout.%d", cache_dir, getpid());
        x_asprintf(&path_stderr, "%s/tmp.stderr.%d", cache_dir, getpid());
-       x_asprintf(&path_status, "%s/tmp.status.%d", cache_dir, getpid());
 
        args_add(args, "-E");
-       execute(args->argv, path_stdout, path_stderr, path_status);
+       status = execute(args->argv, path_stdout, path_stderr);
        args->argc--;
 
+       if (status != 0) {
+               unlink(path_stdout);
+               unlink(path_stderr);
+               cc_log("the preprocessor gave %d\n", status);
+               failed();
+       }
+
        /* if the compilation is with -g then we have to inlcude the whole of the
           preprocessor output, which means we are sensitive to line number
           information. Otherwise we can discard line number info, which makes
@@ -158,14 +186,11 @@ static void find_hash(ARGS *args)
                stabs_hash(path_stdout);
        }
        hash_file(path_stderr);
-       hash_file(path_status);
 
        unlink(path_stdout);
        unlink(path_stderr);
-       unlink(path_status);
        free(path_stdout);
        free(path_stderr);
-       free(path_status);
 
        /* we use a single level subdir for the cache path to reduce the impact
           on filesystems which are slow for large directories
@@ -187,29 +212,15 @@ static void find_hash(ARGS *args)
    otherwise it returns */
 static void from_cache(int first)
 {
-       int fd_status, fd_stderr;
+       int fd_stderr;
        char *s;
-       int ret, status;
-
-       x_asprintf(&s, "%s.status", hashname);
-       fd_status = open(s, O_RDONLY);
-       free(s);
-       if (fd_status == -1) {
-               /* its not cached */
-               return;
-       }
-       if (read(fd_status, &status, sizeof(status)) != sizeof(status)) {
-               cc_log("status file is too short\n");
-               close(fd_status);
-               return;
-       }
-       close(fd_status);
+       int ret;
 
        x_asprintf(&s, "%s.stderr", hashname);
        fd_stderr = open(s, O_RDONLY);
        free(s);
        if (fd_stderr == -1) {
-               cc_log("stderr file not found\n");
+               /* it isn't in cache ... */
                return;
        }
 
@@ -228,21 +239,10 @@ static void from_cache(int first)
 
        /* and exit with the right status code */
        if (first) {
-               cc_log("got cached result for %s with status = %d\n", 
-                      output_file, status);
-       }
-
-       if (status != 0) {
-               /* we delete cached entries with non-zero status as we use them,
-                  which basically means we do them non-cached. This is needed to cope
-                  with someone interrupting a compile
-                  Is there a better way?
-               */
-               x_asprintf(&s, "%s.status", hashname);
-               unlink(s);
+               cc_log("got cached result for %s\n", output_file);
        }
 
-       exit(status);
+       exit(0);
 }
 
 /* find the real compiler. We just search the PATH to find a executable of the 
index 560a7fcb8b3accf378252c337e89f7ecef0696e2..285b2196430f2e6f75e9389587a074167b6f6575 100644 (file)
--- a/ccache.h
+++ b/ccache.h
@@ -39,10 +39,9 @@ void copy_fd(int fd_in, int fd_out);
 
 int create_dir(const char *dir);
 
-void execute(char **argv, 
-            const char *path_stdout,
-            const char *path_stderr,
-            const char *path_status);
+int execute(char **argv, 
+           const char *path_stdout,
+           const char *path_stderr);
 
 typedef struct {
        char **argv;
index b466d227cdd7a6357557bf303c9b1e0a4662f5ca..f3fc5c67fc33e7ac994dafedbb3c9bf5b21a161c 100644 (file)
--- a/execute.c
+++ b/execute.c
   execute a compiler backend, capturing all output to the given paths
   the full path to the compiler to run is in argv[0]
 */
-void execute(char **argv, 
-            const char *path_stdout,
-            const char *path_stderr,
-            const char *path_status)
+int execute(char **argv, 
+           const char *path_stdout,
+           const char *path_stderr)
 {
        pid_t pid;
-       int fd;
-       int s, status;
+       int status;
 
        pid = fork();
        if (pid == -1) fatal("Failed to fork");
        
        if (pid == 0) {
+               int fd;
+
                unlink(path_stdout);
                fd = open(path_stdout, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
                if (fd == -1) {
@@ -58,14 +58,6 @@ void execute(char **argv,
        if (waitpid(pid, &status, 0) != pid) {
                fatal("waitpid failed");
        }
-       
-       fd = open(path_status, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
-       if (fd == -1) {
-               fatal("Failed to create status file");
-       }
-       s = WEXITSTATUS(status);
-       if (write(fd, &s, sizeof(s)) != sizeof(s)) {
-               fatal("failed to write status file");
-       }
-       close(fd);
+
+       return WEXITSTATUS(status);
 }