@@ -27,55 +27,70 @@ namespace linuxdeploy {
2727 subprocess_result subprocess::run () const {
2828 process proc{args_, env_};
2929
30+ class PipeState {
31+ public:
32+ pipe_reader reader;
33+ subprocess_result_buffer_t buffer;
34+ bool eof = false ;
35+
36+ explicit PipeState (int fd) : reader(fd) {}
37+ };
38+
3039 // create pipe readers and empty buffers for both stdout and stderr
3140 // we manage them in this (admittedly, kind of complex-looking) array so we can later easily perform the
3241 // operations in a loop
33- std::array<std::pair<pipe_reader, subprocess_result_buffer_t >, 2 > buffers{
34- std::make_pair ( pipe_reader ( proc.stdout_fd ()), subprocess_result_buffer_t {} ),
35- std::make_pair ( pipe_reader ( proc.stderr_fd ()), subprocess_result_buffer_t {}),
42+ std::array<PipeState, 2 > buffers = {
43+ PipeState ( proc.stdout_fd ()),
44+ PipeState ( proc.stderr_fd ())
3645 };
3746
3847 for (;;) {
39- for (auto & pair : buffers) {
40- // make code more readable
41- auto & reader = pair.first ;
42- auto & buffer = pair.second ;
43-
48+ for (auto & pipe_state : buffers) {
4449 // read some bytes into smaller intermediate buffer to prevent either of the pipes to overflow
4550 // the results are immediately appended to the main buffer
4651 subprocess_result_buffer_t intermediate_buffer (4096 );
4752
4853 // (try to) read all available data from pipe
4954 for (;;) {
50- const auto bytes_read = reader.read (intermediate_buffer);
55+ if (pipe_state.eof ) {
56+ break ;
57+ }
58+
59+ const auto bytes_read = pipe_state.reader .read (intermediate_buffer);
5160
61+ // 0 means EOF
5262 if (bytes_read == 0 ) {
63+ pipe_state.eof = true ;
5364 break ;
5465 }
5566
5667 // append to main buffer
57- buffer.reserve (buffer.size () + bytes_read);
68+ pipe_state. buffer .reserve (pipe_state. buffer .size () + bytes_read);
5869 std::copy (intermediate_buffer.begin (), (intermediate_buffer.begin () + bytes_read),
59- std::back_inserter (buffer));
70+ std::back_inserter (pipe_state. buffer ));
6071 }
6172 }
6273
63- // do-while might be a little more elegant, but we can save this one unnecessary sleep, so...
6474 if (proc.is_running ()) {
65- // reduce load on CPU
75+ // reduce load on CPU until EOF
6676 std::this_thread::sleep_for (std::chrono::milliseconds (50 ));
67- } else {
77+ }
78+
79+ // once all buffers are EOF, we can stop reading
80+ if (std::all_of (buffers.begin (), buffers.end (), [](const PipeState& pipe_state) {
81+ return pipe_state.eof ;
82+ })) {
6883 break ;
6984 }
7085 }
7186
7287 // make sure contents are null-terminated
73- buffers[0 ].second .emplace_back (' \0 ' );
74- buffers[1 ].second .emplace_back (' \0 ' );
88+ buffers[0 ].buffer .emplace_back (' \0 ' );
89+ buffers[1 ].buffer .emplace_back (' \0 ' );
7590
7691 auto exit_code = proc.close ();
7792
78- return subprocess_result{exit_code, buffers[0 ].second , buffers[1 ].second };
93+ return subprocess_result{exit_code, buffers[0 ].buffer , buffers[1 ].buffer };
7994 }
8095
8196 std::string subprocess::check_output () const {
0 commit comments