simplify childProcess

This commit is contained in:
vrd
2025-06-06 18:00:38 +03:00
parent 1dfaa83dbe
commit 9923192ec9
7 changed files with 140 additions and 148 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
set -e
# Test cppipe functions
OKs=$(cppipe test/functions_test.cppipe 2>/dev/null | grep OK | wc -l)
OKs=$(test/functions_test.cppipe 2>/dev/null | grep OK | wc -l)
if ! [ $OKs = 13 ]
then
echo "Functions test failed: EXPECTED 13 OKs, got $OKs"
+69 -119
View File
@@ -53,141 +53,91 @@ inline std::optional<DeadProc> check_exited(Proc p)
namespace _cppipe
{
/* Create a proccess */
inline Proc create(const char* const argv[], fd_t in, fd_t out, fd_t err)
inline void redirect(fd_t new_fd, fd_t old_fd)
{
Proc proc;
proc.in = in;
proc.out = out;
proc.err = err;
proc.pid = fork();
if(proc.pid == 0) /* child */
{
if(in != STDIN_FILENO)
dup2(in, STDIN_FILENO);
if(out != STDOUT_FILENO)
dup2(out, STDOUT_FILENO);
if(err != STDERR_FILENO)
dup2(err, STDERR_FILENO);
exec_or_die(argv);
}
return proc;
}
/* Create a process taking input from pipe childIn */
inline Proc createInRedirected(const char* const argv[], const fd_t childIn[2])
{
Proc childproc;
childproc.in = childIn[1];
childproc.out = STDOUT_FILENO;
childproc.err = STDERR_FILENO;
childproc.pid = fork();
if(childproc.pid == 0) /* child */
{
close(childIn[1]);
dup2(childIn[0], STDIN_FILENO);
exec_or_die(argv);
}
return childproc;
}
/* Like createInRedirected but redirect output to a new pipe */
inline Proc createInOutRedirected(const char* const argv[], const fd_t childIn[2])
{
fd_t childOut[2]; /* todo: add error #include "processTypes.hpp"*/
pipe(childOut);
Proc childproc;
childproc.in = childIn[1];
childproc.out = childOut[0];
childproc.err = STDERR_FILENO;
childproc.pid = fork();
if(childproc.pid != 0) /* parent */
{
close(childOut[1]);
}
else
{
close(childIn[1]);
dup2(childIn[0], STDIN_FILENO);
dup2(childOut[1], STDOUT_FILENO);
exec_or_die(argv);
}
return childproc;
}
inline Proc createCapProcess(const char* const argv[], fd_t in, fd_t err)
{
fd_t childOut[2];
pipe(childOut);
Proc proc;
proc.in = in;
proc.out = childOut[0];
proc.err = err;
proc.pid = fork();
if(proc.pid == 0) /* child */
{
if(in != STDIN_FILENO)
dup2(in, STDIN_FILENO);
dup2(childOut[1], STDOUT_FILENO);
if(err != STDERR_FILENO)
dup2(err, STDERR_FILENO);
exec_or_die(argv);
}
else /* parent */
{
close(childOut[1]); /* close write side */
}
return proc;
if(new_fd != old_fd)
dup2(new_fd, old_fd);
}
}
inline Proc createProcess(const char* const argv[], fd_t in, fd_t out, fd_t err)
{
Proc proc;
using _cppipe::redirect;
if(in == PIPE)
bool in_redir = in == PIPE;
bool out_redir = out == PIPE;
bool err_redir = err == PIPE;
Proc p;
fd_t childIn[2], childOut[2], childErr[2];
if(in_redir)
{
fd_t childIn[2];
pipe(childIn);
if(out == PIPE)
proc = _cppipe::createInOutRedirected(argv, childIn);
else
proc = _cppipe::createInRedirected(argv, childIn);
close(childIn[0]); // parent closes read side
p.in = childIn[1];
}
else if(out == PIPE)
proc = _cppipe::createCapProcess(argv, in, err);
else /* todo: err == PIPE */
proc = _cppipe::create(argv, in, out, err);
else
p.in = in;
return proc;
if(out_redir)
{
pipe(childOut);
p.out = childOut[0];
}
else
p.out = out;
if(err_redir)
{
pipe(childErr);
p.err = childErr[0];
}
else
p.err = err;
p.pid = fork();
if(p.pid == 0) /* child */
{
/* Close write side */
if(in_redir)
close(childIn[1]);
/* Close read side */
if(out_redir)
close(childOut[0]);
if(err_redir)
close(childErr[0]);
/* Take pipe as standart in, out, err */
redirect(in_redir ? childIn[0] : in, STDIN_FILENO);
redirect(out_redir ? childOut[1] : out, STDOUT_FILENO);
redirect(err_redir ? childErr[1] : err, STDERR_FILENO);
exec_or_die(argv);
}
else /* parent */
{
/* Close read side */
if(in_redir)
close(childIn[0]);
/* Close write side */
if(out_redir)
close(childOut[1]);
if(err_redir)
close(childErr[1]);
}
return p;
}
inline void exec_or_die(const char* const argv[])
{
execvp(argv[0], (char* const *)argv);
std::cerr << "Can't execute: " << argv[0] << ' ' << strerror(errno) << std::endl;
std::cerr << "Can't execute command: " << argv[0] << ' ' << strerror(errno) << '\n';
/* for(const char* const * arg = argv; *arg != nullptr; ++arg) */
/* std::cerr << *arg << '\n'; */
_exit(1); // _exit since we are a child
}
+4
View File
@@ -66,6 +66,7 @@ private:
bool execed_;
friend Proc detach(const PendingCmd&);
friend Proc detachRedirIn(const PendingCmd&);
friend Proc detachRedirOut(const PendingCmd&);
friend Proc detachRedirInOut(const PendingCmd&);
};
@@ -82,6 +83,9 @@ DeadProc run(const PendingCmd&);
becomes: cmd.detach() */
Proc detach(const PendingCmd&);
/* Detach but redirect input to a new pipe
* Which can then be read to using write(Proc.in, ...) */
Proc detachRedirIn(const PendingCmd&);
/* Detach but redirect output to a new pipe */
Proc detachRedirOut(const PendingCmd&);
/* Also rediredct input */
+10
View File
@@ -146,6 +146,16 @@ inline Proc detach(const PendingCmd& ccmd)
return createProcess(c.cmd.argv.data(), c.in, c.out, c.err);
}
inline Proc detachRedirIn(const PendingCmd& ccmd)
{
auto& c = const_cast<PendingCmd&>(ccmd);
assert(c.in==0 && "Capturing redirected output");
c.in = PIPE;
return detach(c);
}
inline Proc detachRedirOut(const PendingCmd& ccmd)
{
auto& c = const_cast<PendingCmd&>(ccmd);
+52 -28
View File
@@ -43,12 +43,12 @@ fs::path find_path_to_src(string_view src_file);
// find the path of the cache for the given src_file path
fs::path get_cache_dir_path(const fs::path& src_file);
// map file in memory with write persmissions
// map file in memory with write permissions
MappedFile mapfile_for_writing(const fs::path& file);
// preprocess the src file, compare and overwrite the result to the previous version
// return the path of the preprocessed file if it's different
optional<fs::path> preprocess_and_compare();
// return whether there was a difference
bool preprocess_and_compare();
// only recompile if changes are present
void compile_src_file();
@@ -64,11 +64,12 @@ fs::path HOME;
fs::path src_file;
SrcType src_type;
fs::path cache_dir;
fs::path preprocessed_file;
fs::path bin; // cache bins to avoid recompiles
// Options
bool debug = false;
// just compare timestamps of the source and bin, dont preprocess
// just compare timestamps of the source and bin, don't preprocess
bool quick = false;
}
@@ -82,6 +83,10 @@ int main(int argc, char* argv[])
src_file = find_path_to_src( argv[src_arg] );
src_type = find_src_type( argv[src_arg] );
cache_dir = get_cache_dir_path(src_file);
preprocessed_file = cache_dir / (debug ? DEBUG_PREFIX : "") += src_file.stem()
+= (src_type == SrcType::C ? ".i" : ".ii");
bin = cache_dir / (debug ? DEBUG_PREFIX : "") += src_file.filename();
// Compile the src
@@ -178,7 +183,7 @@ fs::path find_path_to_src(string_view src_file)
}
}
// Couln't find the src
// Couldn't find the src
cerr << "File: " << src_file << " doesn't exist\n";
exit(1);
}
@@ -212,7 +217,7 @@ MappedFile mapfile_for_writing(const fs::path& file)
return res;
}
optional<fs::path> preprocess_and_compare()
bool preprocess_and_compare()
{
Cmd preprocess(
src_type == SrcType::C ? CC : CXX,
@@ -233,16 +238,33 @@ optional<fs::path> preprocess_and_compare()
preprocess += "-xc++"; // treat the file as a .cpp
}
// Read source from stdin
preprocess += "-";
if(!debug)
preprocess += "-DNDEBUG";
// Preprocessed file from the previous run
fs::path old_pp_path = cache_dir / (debug ? DEBUG_PREFIX : "") += src_file.stem()
+= (src_type == SrcType::C ? ".i" : ".ii");
// Read source from stdin
preprocess += "-";
// THIS IS THE RIGHT WAY BUT CURRENTLY PRODUCES A GCC WARNING
// File to preprocess
// fd_t src = open(src_file.c_str(), O_RDONLY);
// If it begins with #! skip the first line
// char buf[128];
// int read_count = read(src, &buf, 128);
// if(read_count > 1 && buf[0] == '#' && buf[1] == '!')
// {
// int newline = 0;
// while(buf[newline] != '\n') // out of bounds
// ++newline;
// lseek(src, newline, SEEK_SET);
// }
// else
// lseek(src, 0, SEEK_SET);
// Start preprocessing, give the source FD to gcc
// Proc preprocessing = detachRedirOut(preprocess < src);
// close(preprocessing.in);
Proc preprocessing = detachRedirInOut(preprocess);
@@ -264,36 +286,36 @@ optional<fs::path> preprocess_and_compare()
if( !wait(preprocessing) ) // preprocessing failed
exit(1);
if( fs::exists(old_pp_path) ) // todo: clean up if else blocks
if( fs::exists(preprocessed_file) ) // todo: clean up if else blocks
{
if( fs::file_size(old_pp_path) == new_pp.size() )
if( fs::file_size(preprocessed_file) == new_pp.size() )
{
MappedFile old_pp = mapfile_for_writing(old_pp_path);
if( !memcmp(old_pp.data, &new_pp[0], old_pp.len) ) // unchanged
MappedFile old_pp = mapfile_for_writing(preprocessed_file);
if( !memcmp(old_pp.data, new_pp.data(), old_pp.len) ) // unchanged
{
return nullopt;
return false;
}
else
{
memcpy(old_pp.data, &new_pp[0], old_pp.len);
munmap(old_pp.data, old_pp.len);
return old_pp_path;
return true;
}
// todo
// munmap(data, len);
}
else
{
ofstream pp_file(old_pp_path);
ofstream pp_file(preprocessed_file);
pp_file << new_pp;
return old_pp_path;
return true;
}
}
else
{
ofstream pp_file(old_pp_path);
ofstream pp_file(preprocessed_file);
pp_file << new_pp;
return old_pp_path;
return true;
}
}
@@ -304,20 +326,19 @@ void compile_src_file()
error_code ec;
if(fs::last_write_time(src_file) < fs::last_write_time(bin, ec))
{
// Binary is newer then source, dont recompile
// Binary is newer then source, don't recompile
return;
}
}
optional<fs::path> new_preprocessed = preprocess_and_compare();
bool file_changed = preprocess_and_compare();
// Only compile if the source is newer then the bin
if(new_preprocessed || !fs::exists(bin))
if(file_changed || !fs::exists(bin))
{
Cmd compile(
src_type == SrcType::C ? CC : CXX,
new_preprocessed->c_str(),
preprocessed_file.c_str(),
"-o", bin.c_str()
);
@@ -335,9 +356,12 @@ void compile_src_file()
if( !compile() ) // if failed to compile
{
fs::remove(bin);
exit(1);
}
}
}
void print_usage()
{
Regular → Executable
+1
View File
@@ -1,3 +1,4 @@
#!/usr/local/bin/cppipe
// Test cppipe functions
#include <cppipe/commands.hpp>
+3
View File
@@ -1,3 +1,4 @@
example #!/usr/bin/cppipe
description - advantages over manual compile
man
tips (sigaction SIGCHILD, SIG_IGN, SIG_DFL)
@@ -5,6 +6,7 @@ tips (sigaction SIGCHILD, SIG_IGN, SIG_DFL)
make sure file descriptors are closed when no longer used
cppipe compile options from tft
respect CXXFLAGS LDFLAGS
< PendingCmd store files we need to close
?
optional exec
@@ -20,3 +22,4 @@ uninstall
improve debug (the src file shown is the .ii)
no optimizations option
split
PendingCmd template