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 set -e
# Test cppipe functions # 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 ] if ! [ $OKs = 13 ]
then then
echo "Functions test failed: EXPECTED 13 OKs, got $OKs" 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 namespace _cppipe
{ {
/* Create a proccess */ inline void redirect(fd_t new_fd, fd_t old_fd)
inline Proc create(const char* const argv[], fd_t in, fd_t out, fd_t err)
{ {
Proc proc; if(new_fd != old_fd)
proc.in = in; dup2(new_fd, old_fd);
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;
} }
} }
inline Proc createProcess(const char* const argv[], fd_t in, fd_t out, fd_t err) 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); pipe(childIn);
p.in = childIn[1];
if(out == PIPE)
proc = _cppipe::createInOutRedirected(argv, childIn);
else
proc = _cppipe::createInRedirected(argv, childIn);
close(childIn[0]); // parent closes read side
} }
else if(out == PIPE) else
proc = _cppipe::createCapProcess(argv, in, err); p.in = in;
else /* todo: err == PIPE */
proc = _cppipe::create(argv, in, out, err);
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[]) inline void exec_or_die(const char* const argv[])
{ {
execvp(argv[0], (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 _exit(1); // _exit since we are a child
} }
+4
View File
@@ -66,6 +66,7 @@ private:
bool execed_; bool execed_;
friend Proc detach(const PendingCmd&); friend Proc detach(const PendingCmd&);
friend Proc detachRedirIn(const PendingCmd&);
friend Proc detachRedirOut(const PendingCmd&); friend Proc detachRedirOut(const PendingCmd&);
friend Proc detachRedirInOut(const PendingCmd&); friend Proc detachRedirInOut(const PendingCmd&);
}; };
@@ -82,6 +83,9 @@ DeadProc run(const PendingCmd&);
becomes: cmd.detach() */ becomes: cmd.detach() */
Proc detach(const PendingCmd&); 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 */ /* Detach but redirect output to a new pipe */
Proc detachRedirOut(const PendingCmd&); Proc detachRedirOut(const PendingCmd&);
/* Also rediredct input */ /* 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); 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) inline Proc detachRedirOut(const PendingCmd& ccmd)
{ {
auto& c = const_cast<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 // find the path of the cache for the given src_file path
fs::path get_cache_dir_path(const fs::path& src_file); 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); MappedFile mapfile_for_writing(const fs::path& file);
// preprocess the src file, compare and overwrite the result to the previous version // preprocess the src file, compare and overwrite the result to the previous version
// return the path of the preprocessed file if it's different // return whether there was a difference
optional<fs::path> preprocess_and_compare(); bool preprocess_and_compare();
// only recompile if changes are present // only recompile if changes are present
void compile_src_file(); void compile_src_file();
@@ -64,11 +64,12 @@ fs::path HOME;
fs::path src_file; fs::path src_file;
SrcType src_type; SrcType src_type;
fs::path cache_dir; fs::path cache_dir;
fs::path preprocessed_file;
fs::path bin; // cache bins to avoid recompiles fs::path bin; // cache bins to avoid recompiles
// Options // Options
bool debug = false; 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; bool quick = false;
} }
@@ -82,6 +83,10 @@ int main(int argc, char* argv[])
src_file = find_path_to_src( argv[src_arg] ); src_file = find_path_to_src( argv[src_arg] );
src_type = find_src_type( argv[src_arg] ); src_type = find_src_type( argv[src_arg] );
cache_dir = get_cache_dir_path(src_file); 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(); bin = cache_dir / (debug ? DEBUG_PREFIX : "") += src_file.filename();
// Compile the src // 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"; cerr << "File: " << src_file << " doesn't exist\n";
exit(1); exit(1);
} }
@@ -212,7 +217,7 @@ MappedFile mapfile_for_writing(const fs::path& file)
return res; return res;
} }
optional<fs::path> preprocess_and_compare() bool preprocess_and_compare()
{ {
Cmd preprocess( Cmd preprocess(
src_type == SrcType::C ? CC : CXX, src_type == SrcType::C ? CC : CXX,
@@ -233,16 +238,33 @@ optional<fs::path> preprocess_and_compare()
preprocess += "-xc++"; // treat the file as a .cpp preprocess += "-xc++"; // treat the file as a .cpp
} }
// Read source from stdin
preprocess += "-";
if(!debug) if(!debug)
preprocess += "-DNDEBUG"; preprocess += "-DNDEBUG";
// Preprocessed file from the previous run // Read source from stdin
fs::path old_pp_path = cache_dir / (debug ? DEBUG_PREFIX : "") += src_file.stem() preprocess += "-";
+= (src_type == SrcType::C ? ".i" : ".ii");
// 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); Proc preprocessing = detachRedirInOut(preprocess);
@@ -264,36 +286,36 @@ optional<fs::path> preprocess_and_compare()
if( !wait(preprocessing) ) // preprocessing failed if( !wait(preprocessing) ) // preprocessing failed
exit(1); 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); MappedFile old_pp = mapfile_for_writing(preprocessed_file);
if( !memcmp(old_pp.data, &new_pp[0], old_pp.len) ) // unchanged if( !memcmp(old_pp.data, new_pp.data(), old_pp.len) ) // unchanged
{ {
return nullopt; return false;
} }
else else
{ {
memcpy(old_pp.data, &new_pp[0], old_pp.len); memcpy(old_pp.data, &new_pp[0], old_pp.len);
munmap(old_pp.data, old_pp.len); munmap(old_pp.data, old_pp.len);
return old_pp_path; return true;
} }
// todo // todo
// munmap(data, len); // munmap(data, len);
} }
else else
{ {
ofstream pp_file(old_pp_path); ofstream pp_file(preprocessed_file);
pp_file << new_pp; pp_file << new_pp;
return old_pp_path; return true;
} }
} }
else else
{ {
ofstream pp_file(old_pp_path); ofstream pp_file(preprocessed_file);
pp_file << new_pp; pp_file << new_pp;
return old_pp_path; return true;
} }
} }
@@ -304,20 +326,19 @@ void compile_src_file()
error_code ec; error_code ec;
if(fs::last_write_time(src_file) < fs::last_write_time(bin, 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; 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 // Only compile if the source is newer then the bin
if(new_preprocessed || !fs::exists(bin)) if(file_changed || !fs::exists(bin))
{ {
Cmd compile( Cmd compile(
src_type == SrcType::C ? CC : CXX, src_type == SrcType::C ? CC : CXX,
new_preprocessed->c_str(), preprocessed_file.c_str(),
"-o", bin.c_str() "-o", bin.c_str()
); );
@@ -335,9 +356,12 @@ void compile_src_file()
if( !compile() ) // if failed to compile if( !compile() ) // if failed to compile
{
fs::remove(bin);
exit(1); exit(1);
} }
} }
}
void print_usage() void print_usage()
{ {
Regular → Executable
+1
View File
@@ -1,3 +1,4 @@
#!/usr/local/bin/cppipe
// Test cppipe functions // Test cppipe functions
#include <cppipe/commands.hpp> #include <cppipe/commands.hpp>
+3
View File
@@ -1,3 +1,4 @@
example #!/usr/bin/cppipe
description - advantages over manual compile description - advantages over manual compile
man man
tips (sigaction SIGCHILD, SIG_IGN, SIG_DFL) 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 make sure file descriptors are closed when no longer used
cppipe compile options from tft cppipe compile options from tft
respect CXXFLAGS LDFLAGS respect CXXFLAGS LDFLAGS
< PendingCmd store files we need to close
? ?
optional exec optional exec
@@ -20,3 +22,4 @@ uninstall
improve debug (the src file shown is the .ii) improve debug (the src file shown is the .ii)
no optimizations option no optimizations option
split split
PendingCmd template