Browse Source

change how child processes work

feature/new-parser
Martin Dørum 3 years ago
parent
commit
8eaee6e85c
8 changed files with 82 additions and 94 deletions
  1. 1
    1
      Makefile
  2. 1
    1
      build.bx
  3. 4
    2
      cmd/main.cc
  4. 3
    1
      lib/CompileStep.cc
  5. 3
    1
      lib/LinkStep.cc
  6. 51
    82
      lib/sys.cc
  7. 7
    3
      lib/sys.h
  8. 12
    3
      lib/toolchain.cc

+ 1
- 1
Makefile View File

lib/toolchain.h lib/bufio.h lib/toolchain.h lib/bufio.h
BUILD = build BUILD = build
OBJS = $(patsubst %,$(BUILD)/%.o,$(SRCS)) OBJS = $(patsubst %,$(BUILD)/%.o,$(SRCS))
CFLAGS = -std=c++14 -Wall -Wextra -Wno-unused-parameter -Ilib -O3 -g
CFLAGS = -std=c++14 -Wall -Wextra -Wpedantic -Wno-unused-parameter -Ilib -O3 -g
LDLIBS = -lpthread LDLIBS = -lpthread


$(BUILD)/%.cc.o: %.cc $(HDRS) $(BUILD)/%.cc.o: %.cc $(HDRS)

+ 1
- 1
build.bx View File

target := box target := box
files := lib cmd files := lib cmd
includes := lib includes := lib
warnings := all extra no-unused-parameter
warnings := all extra pedantic no-unused-parameter
std := c++14 std := c++14
optimize := 3 optimize := 3
cxxflags := -g cxxflags := -g

+ 4
- 2
cmd/main.cc View File

for (const auto &arg: conf.args2) { for (const auto &arg: conf.args2) {
argv.push_back(std::move(arg)); argv.push_back(std::move(arg));
} }

try { try {
sys::ignoreCtrlC();
sys::execute(argv, true);
sys::ProcConf conf;
conf.forwardSignals = true;
sys::execute(argv, conf);
} catch (std::exception &ex) { } catch (std::exception &ex) {
logger::log(ex.what()); logger::log(ex.what());
} }

+ 3
- 1
lib/CompileStep.cc View File

BXWriter writer(f); BXWriter writer(f);
writer.write(newCachedVars); writer.write(newCachedVars);


sys::execute(command, nullptr, verboseCommand);
sys::ProcConf conf;
conf.print = verboseCommand;
sys::execute(command, conf);
} }


void CompileStep::doWriteCompDB(const std::string &outDir, compdb::Writer &w) { void CompileStep::doWriteCompDB(const std::string &outDir, compdb::Writer &w) {

+ 3
- 1
lib/LinkStep.cc View File

writer.write(newCachedVars); writer.write(newCachedVars);


sys::mkdirp(dirPath); sys::mkdirp(dirPath);
sys::execute(command, nullptr, global::verbose >= 1);
sys::ProcConf conf;
conf.print = global::verbose >= 1;
sys::execute(command, conf);
} }


std::vector<std::string> &LinkStep::linkCommand(const std::string &outDir) { std::vector<std::string> &LinkStep::linkCommand(const std::string &outDir) {

+ 51
- 82
lib/sys.cc View File

#include <stdexcept> #include <stdexcept>
#include <system_error> #include <system_error>
#include <unordered_set> #include <unordered_set>
#include <atomic>


#include "logger.h" #include "logger.h"
#include "globals.h" #include "globals.h"


static thread_local std::unordered_set<std::string> mkdirp_set; static thread_local std::unordered_set<std::string> mkdirp_set;


static std::atomic<int> signalCounter(0);

struct SigCtx {
SigCtx(bool enabled): enabled(enabled) {
if (enabled && signalCounter++ == 0) {
signal(SIGINT, SIG_IGN);
}
}

~SigCtx() {
if (enabled && --signalCounter == 0) {
signal(SIGINT, SIG_DFL);
}
}

bool enabled;
};

std::string sanitizePath(const std::string &path) { std::string sanitizePath(const std::string &path) {
std::string npath; std::string npath;
size_t idx = 0; size_t idx = 0;
argv.push_back("-p"); argv.push_back("-p");
argv.push_back("--"); argv.push_back("--");
argv.push_back(path); argv.push_back(path);
execute(argv, nullptr, global::verbose >= 2);
ProcConf conf;
conf.print = global::verbose >= 2;
execute(argv, conf);
} }


void rmrf(const std::string &path) { void rmrf(const std::string &path) {
argv.push_back("-rf"); argv.push_back("-rf");
argv.push_back("--"); argv.push_back("--");
argv.push_back(path); argv.push_back(path);
execute(argv, nullptr, global::verbose >= 2);
ProcConf conf;
conf.print = global::verbose >= 2;
execute(argv, conf);
} }


void execute(const std::vector<std::string> &args, std::string *output, bool print) {
if (print) {
void execute(const std::vector<std::string> &args, const ProcConf &conf) {
if (conf.print) {
std::string str; std::string str;
for (size_t i = 0; i < args.size(); ++i) { for (size_t i = 0; i < args.size(); ++i) {
if (i != 0) { if (i != 0) {
for (size_t i = 1; i < args.size(); ++i) { for (size_t i = 1; i < args.size(); ++i) {
argv.push_back(args[i].c_str()); argv.push_back(args[i].c_str());
} }

argv.push_back(nullptr); argv.push_back(nullptr);


int fds[2];
if (pipe(fds) < 0) {
throw std::runtime_error(std::string("fork: ") + strerror(errno));
int stdoutPipe[2];
if (conf.output == nullptr) {
stdoutPipe[1] = STDOUT_FILENO;
} else {
if (pipe(stdoutPipe) < 0) {
throw std::runtime_error(std::string("pipe: ") + strerror(errno));
}
} }


SigCtx sigCtx(conf.forwardSignals);
pid_t child = fork(); pid_t child = fork();
if (child == 0) { if (child == 0) {
close(fds[0]);
dup2(fds[1], 1);
signal(SIGINT, SIG_DFL);
if (conf.output != nullptr) {
close(stdoutPipe[0]);
dup2(stdoutPipe[1], 1);
}


// So, from what I've read, execvp should never modify its argv; so this should be fine? // So, from what I've read, execvp should never modify its argv; so this should be fine?
if (execvp(argv[0], (char *const *)argv.data()) < 0) { if (execvp(argv[0], (char *const *)argv.data()) < 0) {
} }


// This shouldn't happen // This shouldn't happen
exit(0);
abort();
} else if (child < 0) { } else if (child < 0) {
throw std::runtime_error(std::string("fork: ") + strerror(errno)); throw std::runtime_error(std::string("fork: ") + strerror(errno));
} }


close(fds[1]);

if (output == nullptr) {
close(fds[0]);
} else {
if (conf.output != nullptr) {
close(stdoutPipe[1]);
char buf[1025]; char buf[1025];
while (true) { while (true) {
ssize_t num = read(fds[0], buf, sizeof(buf) - 1);
ssize_t num = read(stdoutPipe[0], buf, sizeof(buf) - 1);
if (num < 0 && errno != EAGAIN) { if (num < 0 && errno != EAGAIN) {
close(fds[0]);
close(stdoutPipe[0]);
throw std::runtime_error( throw std::runtime_error(
std::string("read: ") + strerror(errno) + std::string("read: ") + strerror(errno) +
" (fd: " + std::to_string(fds[0]) + ")");
" (fd: " + std::to_string(stdoutPipe[0]) + ")");
} else if (num < 0) { } else if (num < 0) {
continue; continue;
} }


if (num == 0) { if (num == 0) {
close(fds[0]);
close(stdoutPipe[0]);
break; break;
} }


buf[num] = '\0'; buf[num] = '\0';
*output += buf;
*conf.output += buf;
} }
} }


" terminated due to " + strsignal(WTERMSIG(wstatus))); " terminated due to " + strsignal(WTERMSIG(wstatus)));
} }


if (output != nullptr && output->back() == '\n') {
output->pop_back();
}
}

void execute(const std::vector<std::string> &args, bool print) {
if (print) {
std::string str;
for (size_t i = 0; i < args.size(); ++i) {
if (i != 0) {
str += " ";
}
str += args[i];
}
logger::log(str);
}

// argv[0] should be interpreted as a shell command, because being able to run
// CC='gcc --sysroot=/blah' is used by some systems.
std::string command = std::string(args[0]) + " \"$@\"";
static thread_local std::vector<const char *> argv;
argv.clear();
argv.push_back("/bin/sh"); // TODO: Use $SHELL?
argv.push_back("-c");
argv.push_back(command.c_str());
argv.push_back("--");
for (size_t i = 1; i < args.size(); ++i) {
argv.push_back(args[i].c_str());
}

argv.push_back(nullptr);

pid_t child = fork();
if (child == 0) {
// So, from what I've read, execvp should never modify its argv; so this should be fine?
if (execvp(argv[0], (char *const *)argv.data()) < 0) {
perror(argv[0]);
abort();
}

// This shouldn't happen
exit(0);
} else if (child < 0) {
throw std::runtime_error(std::string("fork: ") + strerror(errno));
}

int wstatus;
waitpid(child, &wstatus, 0);
if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) != 0) {
throw std::runtime_error(std::string(args[0]) +
" exited with code " + std::to_string(WEXITSTATUS(wstatus)));
}

if (WTERMSIG(wstatus)) {
throw std::runtime_error(std::string(args[0]) +
" terminated due to " + strsignal(WTERMSIG(wstatus)));
if (conf.output != nullptr && conf.output->back() == '\n') {
conf.output->pop_back();
} }
} }


argv.push_back("--"); argv.push_back("--");
argv.push_back(from); argv.push_back(from);
argv.push_back(to); argv.push_back(to);
sys::execute(argv, nullptr, global::verbose > 2);
sys::execute(argv, ProcConf{});
} }


std::string dirname(const std::string &path) { std::string dirname(const std::string &path) {
return std::string(dir); return std::string(dir);
} }


void ignoreCtrlC() {
signal(SIGINT, SIG_IGN);
}

} }

+ 7
- 3
lib/sys.h View File

} }
}; };


struct ProcConf {
bool print = false;
bool forwardSignals = false;
std::string *output = nullptr;
};

std::string sanitizePath(const std::string &path); std::string sanitizePath(const std::string &path);
FileInfo fileInfo(const std::string &path); FileInfo fileInfo(const std::string &path);
bool fileExists(const std::string &path); bool fileExists(const std::string &path);
void mkdirp(const std::string &path); void mkdirp(const std::string &path);
void rmrf(const std::string &path); void rmrf(const std::string &path);
void execute(const std::vector<std::string> &args, std::string *output, bool print);
void execute(const std::vector<std::string> &args, bool print);
void execute(const std::vector<std::string> &args, const ProcConf &conf);
void readDir(const std::string &path, std::vector<std::string> &files); void readDir(const std::string &path, std::vector<std::string> &files);
void chdir(const std::string &path); void chdir(const std::string &path);
std::string cwd(); std::string cwd();
void symlink(const std::string &from, const std::string &to); void symlink(const std::string &from, const std::string &to);
std::string dirname(const std::string &path); std::string dirname(const std::string &path);
void ignoreCtrlC();


} }

+ 12
- 3
lib/toolchain.cc View File



// Execute $(PKG_CONFIG) --cflags $(PKGS) // Execute $(PKG_CONFIG) --cflags $(PKGS)
std::string output; std::string output;
sys::execute(argv, &output, global::verbose >= 2);
sys::ProcConf conf;
conf.print = global::verbose >= 2;
conf.output = &output;
sys::execute(argv, conf);
parseWhitespaceSeparated(output, flags); parseWhitespaceSeparated(output, flags);
} }




// Execute $(PKG_CONFIG) --cflags $(PKGS) // Execute $(PKG_CONFIG) --cflags $(PKGS)
std::string output; std::string output;
sys::execute(argv, &output, global::verbose >= 2);
sys::ProcConf conf;
conf.print = global::verbose >= 2;
conf.output = &output;
sys::execute(argv, conf);
parseWhitespaceSeparated(output, flags); parseWhitespaceSeparated(output, flags);
} }




// Execute $(compiler) $(flags) -MM $< // Execute $(compiler) $(flags) -MM $<
std::string output; std::string output;
sys::execute(argv, &output, global::verbose >= 2);
sys::ProcConf conf;
conf.print = global::verbose >= 2;
conf.output = &output;
sys::execute(argv, conf);


std::vector<std::string> deps; std::vector<std::string> deps;
size_t idx = output.find(':'); size_t idx = output.find(':');

Loading…
Cancel
Save