summaryrefslogtreecommitdiffstats
path: root/src/browse.cc
diff options
context:
space:
mode:
authorEvan Martin <martine@danga.com>2011-03-05 23:32:03 (GMT)
committerEvan Martin <martine@danga.com>2011-03-05 23:32:03 (GMT)
commitdcf96a4d9c07d5c49d050ebd055c9e2db6836fc1 (patch)
treef2fac40c4353d47e020efc14f6f09e5524433294 /src/browse.cc
parent80fda9821765d2139a080a527ab66fcb9e272722 (diff)
downloadNinja-dcf96a4d9c07d5c49d050ebd055c9e2db6836fc1.zip
Ninja-dcf96a4d9c07d5c49d050ebd055c9e2db6836fc1.tar.gz
Ninja-dcf96a4d9c07d5c49d050ebd055c9e2db6836fc1.tar.bz2
don't rely on /proc for 'browse' mode
Instead, pass the script code via stdin. We end up with a zombie (the child process that passes the script code) because we can't ignore SIGCHLD in the parent (the Python code relies on being able to wait for children), but the zombie dies with the outer process. This probably could be avoided by double-forking or other approaches, but it doesn't seem worth the effort.
Diffstat (limited to 'src/browse.cc')
-rw-r--r--src/browse.cc54
1 files changed, 38 insertions, 16 deletions
diff --git a/src/browse.cc b/src/browse.cc
index 4507e0d..92b290d 100644
--- a/src/browse.cc
+++ b/src/browse.cc
@@ -15,6 +15,7 @@
#include "browse.h"
#include <stdio.h>
+#include <unistd.h>
#include "ninja.h"
@@ -30,24 +31,45 @@ extern const char browse_data_begin[];
extern const char browse_data_end[];
void RunBrowsePython(State* state, const char* ninja_command) {
- // Create a temporary file, dump the Python code into it, and
- // delete the file, keeping our open handle to it.
- char tmpl[] = "browsepy-XXXXXX";
- int fd = mkstemp(tmpl);
- unlink(tmpl);
- const int browse_data_len = browse_data_end - browse_data_begin;
- int len = write(fd, browse_data_begin, browse_data_len);
- if (len < browse_data_len) {
- perror("write");
+ // Fork off a Python process and have it run our code via its stdin.
+ // (Actually the Python process becomes the parent.)
+ int pipefd[2];
+ if (pipe(pipefd) < 0) {
+ perror("pipe");
return;
}
- // exec Python, telling it to use our script file.
- const char* command[] = {
- "python", "/proc/self/fd/3", ninja_command, NULL
- };
- execvp(command[0], (char**)command);
+ pid_t pid = fork();
+ if (pid < 0) {
+ perror("fork");
+ return;
+ }
+
+ if (pid > 0) { // Parent.
+ close(pipefd[1]);
+ do {
+ if (dup2(pipefd[0], 0) < 0) {
+ perror("dup2");
+ break;
+ }
- // If we get here, the exec failed.
- printf("ERROR: Failed to spawn python for graph browsing, aborting.\n");
+ // exec Python, telling it to run the program from stdin.
+ const char* command[] = {
+ "python", "-", ninja_command, NULL
+ };
+ execvp(command[0], (char**)command);
+ perror("execvp");
+ } while (false);
+ _exit(1);
+ } else { // Child.
+ close(pipefd[0]);
+
+ // Write the script file into the stdin of the Python process.
+ const int browse_data_len = browse_data_end - browse_data_begin;
+ int len = write(pipefd[1], browse_data_begin, browse_data_len);
+ if (len < browse_data_len)
+ perror("write");
+ close(pipefd[1]);
+ exit(0);
+ }
}