OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::GUI::ProcessRunner Class Reference

#include </home/runner/work/OrcaSlicer/OrcaSlicer/src/slic3r/GUI/ProcessRunner.hpp>

Inheritance diagram for Slic3r::GUI::ProcessRunner:
Collaboration diagram for Slic3r::GUI::ProcessRunner:

Classes

struct  OutputLine
struct  SyncResult

Public Types

using OutputCallback = std::function<void(const std::vector<OutputLine>& lines)>
using DoneCallback = std::function<void(int exit_code)>

Public Member Functions

 ProcessRunner ()
 ~ProcessRunner () override
bool run_command_line_async (const std::string &command_line, OutputCallback on_output, DoneCallback on_done)
void write_stdin (const std::string &data)
bool is_running () const
void terminate ()

Static Public Member Functions

static SyncResult run_sync (const std::string &executable, const std::vector< std::string > &args)

Private Member Functions

void on_timer (wxTimerEvent &event)
void finish_process (int exit_code)
void start_reader_threads ()
void join_reader_threads ()
void enqueue_output (std::string line, bool is_stderr)
std::vector< OutputLine > drain_output_queue ()
void join_launch_thread ()

Private Attributes

wxTimer m_poll_timer
std::atomic_bool m_launching {false}
std::atomic_bool m_launch_failed {false}
std::thread m_launch_thread
std::thread m_stdout_thread
std::thread m_stderr_thread
std::mutex m_output_mutex
std::vector< OutputLine > m_output_queue
std::unique_ptr< boost::process::child > m_process
std::unique_ptr< boost::process::ipstream > m_stdout_pipe
std::unique_ptr< boost::process::ipstream > m_stderr_pipe
std::unique_ptr< boost::process::opstream > m_stdin_pipe
OutputCallback m_on_output
DoneCallback m_on_done

Detailed Description


Class Documentation

◆ Slic3r::GUI::ProcessRunner::OutputLine

struct Slic3r::GUI::ProcessRunner::OutputLine
Collaboration diagram for Slic3r::GUI::ProcessRunner::OutputLine:
Class Members
bool is_stderr
string text

◆ Slic3r::GUI::ProcessRunner::SyncResult

struct Slic3r::GUI::ProcessRunner::SyncResult
Collaboration diagram for Slic3r::GUI::ProcessRunner::SyncResult:
Class Members
int exit_code = -1
string stderr_output
string stdout_output

Member Typedef Documentation

◆ DoneCallback

using Slic3r::GUI::ProcessRunner::DoneCallback = std::function<void(int exit_code)>

◆ OutputCallback

using Slic3r::GUI::ProcessRunner::OutputCallback = std::function<void(const std::vector<OutputLine>& lines)>

Constructor & Destructor Documentation

◆ ProcessRunner()

Slic3r::GUI::ProcessRunner::ProcessRunner ( )
17 : m_poll_timer(this, wxID_ANY)
18{
19 Bind(wxEVT_TIMER, &ProcessRunner::on_timer, this);
20}
void on_timer(wxTimerEvent &event)
Definition ProcessRunner.cpp:174
wxTimer m_poll_timer
Definition ProcessRunner.hpp:70

References m_poll_timer, and on_timer().

Here is the call graph for this function:

◆ ~ProcessRunner()

Slic3r::GUI::ProcessRunner::~ProcessRunner ( )
override
23{
24 terminate();
25}
void terminate()
Definition ProcessRunner.cpp:99

References terminate().

Here is the call graph for this function:

Member Function Documentation

◆ drain_output_queue()

std::vector< ProcessRunner::OutputLine > Slic3r::GUI::ProcessRunner::drain_output_queue ( )
private
69{
70 std::lock_guard<std::mutex> lock(m_output_mutex);
71 std::vector<OutputLine> batch;
72 batch.swap(m_output_queue);
73 return batch;
74}
std::mutex m_output_mutex
Definition ProcessRunner.hpp:78
std::vector< OutputLine > m_output_queue
Definition ProcessRunner.hpp:79
@ lock
Definition GLGizmoEmboss.cpp:209

References m_output_mutex, and m_output_queue.

Referenced by finish_process(), on_timer(), and run_command_line_async().

Here is the caller graph for this function:

◆ enqueue_output()

void Slic3r::GUI::ProcessRunner::enqueue_output ( std::string line,
bool is_stderr )
private
63{
64 std::lock_guard<std::mutex> lock(m_output_mutex);
65 m_output_queue.push_back({std::move(line), is_stderr});
66}

References m_output_mutex, and m_output_queue.

Referenced by start_reader_threads().

Here is the caller graph for this function:

◆ finish_process()

void Slic3r::GUI::ProcessRunner::finish_process ( int exit_code)
private
78{
81
82 std::vector<OutputLine> final_batch = drain_output_queue();
83 if (!final_batch.empty() && m_on_output)
84 m_on_output(final_batch);
85
86 m_process.reset();
87 m_stdout_pipe.reset();
88 m_stderr_pipe.reset();
89 m_stdin_pipe.reset();
90
91 if (m_on_done) {
92 auto cb = std::move(m_on_done);
93 m_on_done = nullptr;
94 cb(exit_code);
95 }
96}
std::unique_ptr< boost::process::ipstream > m_stderr_pipe
Definition ProcessRunner.hpp:83
void join_launch_thread()
Definition ProcessRunner.cpp:27
void join_reader_threads()
Definition ProcessRunner.cpp:54
std::vector< OutputLine > drain_output_queue()
Definition ProcessRunner.cpp:68
std::unique_ptr< boost::process::ipstream > m_stdout_pipe
Definition ProcessRunner.hpp:82
std::unique_ptr< boost::process::opstream > m_stdin_pipe
Definition ProcessRunner.hpp:84
std::unique_ptr< boost::process::child > m_process
Definition ProcessRunner.hpp:81
DoneCallback m_on_done
Definition ProcessRunner.hpp:87
OutputCallback m_on_output
Definition ProcessRunner.hpp:86

References drain_output_queue(), join_launch_thread(), join_reader_threads(), m_on_done, m_on_output, m_process, m_stderr_pipe, m_stdin_pipe, and m_stdout_pipe.

Referenced by on_timer(), and terminate().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_running()

bool Slic3r::GUI::ProcessRunner::is_running ( ) const
215{
216 return m_launching.load() || (m_process && m_process->running());
217}
std::atomic_bool m_launching
Definition ProcessRunner.hpp:73

References m_launching, and m_process.

Referenced by run_command_line_async().

Here is the caller graph for this function:

◆ join_launch_thread()

void Slic3r::GUI::ProcessRunner::join_launch_thread ( )
private
28{
29 if (m_launch_thread.joinable())
30 m_launch_thread.join();
31}
std::thread m_launch_thread
Definition ProcessRunner.hpp:75

References m_launch_thread.

Referenced by finish_process(), on_timer(), run_command_line_async(), and terminate().

Here is the caller graph for this function:

◆ join_reader_threads()

void Slic3r::GUI::ProcessRunner::join_reader_threads ( )
private
55{
56 if (m_stdout_thread.joinable())
57 m_stdout_thread.join();
58 if (m_stderr_thread.joinable())
59 m_stderr_thread.join();
60}
std::thread m_stderr_thread
Definition ProcessRunner.hpp:77
std::thread m_stdout_thread
Definition ProcessRunner.hpp:76

References m_stderr_thread, and m_stdout_thread.

Referenced by finish_process(), and start_reader_threads().

Here is the caller graph for this function:

◆ on_timer()

void Slic3r::GUI::ProcessRunner::on_timer ( wxTimerEvent & event)
private
175{
176 if (m_launching.load())
177 return;
178
180
181 if (m_launch_failed.exchange(false)) {
182 m_poll_timer.Stop();
183 finish_process(-1);
184 return;
185 }
186
187 if (!m_process) {
188 m_poll_timer.Stop();
189 return;
190 }
191
192 std::vector<OutputLine> batch = drain_output_queue();
193 if (!batch.empty() && m_on_output)
194 m_on_output(batch);
195
196 // Check if process exited
197 if (!m_process->running()) {
198 m_poll_timer.Stop();
199 m_process->wait();
200 const int exit_code = m_process->exit_code();
201 finish_process(exit_code);
202 }
203}
std::atomic_bool m_launch_failed
Definition ProcessRunner.hpp:74
void finish_process(int exit_code)
Definition ProcessRunner.cpp:77

References drain_output_queue(), finish_process(), join_launch_thread(), m_launch_failed, m_launching, m_on_output, m_poll_timer, and m_process.

Referenced by ProcessRunner().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ run_command_line_async()

bool Slic3r::GUI::ProcessRunner::run_command_line_async ( const std::string & command_line,
OutputCallback on_output,
DoneCallback on_done )
121{
122 if (!m_launching.load())
124
125 if (is_running())
126 return false;
127
128 m_on_output = std::move(on_output);
129 m_on_done = std::move(on_done);
131 m_launch_failed.store(false);
132 m_launching.store(true);
133
134 m_launch_thread = std::thread([this, command_line]() {
135 namespace bp = boost::process;
136
137 try {
138 auto stdout_pipe = std::make_unique<bp::ipstream>();
139 auto stderr_pipe = std::make_unique<bp::ipstream>();
140 auto stdin_pipe = std::make_unique<bp::opstream>();
141
142 auto process = std::make_unique<bp::child>(
143 bp::cmd = command_line,
144 bp::env["PYTHONUNBUFFERED"] = "1",
145 bp::env["PYTHONIOENCODING"] = "utf-8",
146 bp::env["PYTHONUTF8"] = "1",
147#ifdef _WIN32
148 bp::windows::create_no_window,
149#endif
150 bp::std_in < *stdin_pipe,
151 bp::std_out > *stdout_pipe,
152 bp::std_err > *stderr_pipe);
153
154 m_stdout_pipe = std::move(stdout_pipe);
155 m_stderr_pipe = std::move(stderr_pipe);
156 m_stdin_pipe = std::move(stdin_pipe);
157 m_process = std::move(process);
159 } catch (const std::exception&) {
160 m_stdout_pipe.reset();
161 m_stderr_pipe.reset();
162 m_stdin_pipe.reset();
163 m_process.reset();
164 m_launch_failed.store(true);
165 }
166
167 m_launching.store(false);
168 });
169
170 m_poll_timer.Start(50);
171 return true;
172}
bool is_running() const
Definition ProcessRunner.cpp:214
void start_reader_threads()
Definition ProcessRunner.cpp:33
bool process(std::exception_ptr &eptr)
Definition EmbossJob.cpp:1427

References drain_output_queue(), is_running(), join_launch_thread(), m_launch_failed, m_launch_thread, m_launching, m_on_done, m_on_output, m_poll_timer, m_process, m_stderr_pipe, m_stdin_pipe, m_stdout_pipe, and start_reader_threads().

Here is the call graph for this function:

◆ run_sync()

ProcessRunner::SyncResult Slic3r::GUI::ProcessRunner::run_sync ( const std::string & executable,
const std::vector< std::string > & args )
static
221{
222 SyncResult result;
223
224 try {
225 namespace bp = boost::process;
226
227 bp::ipstream std_out;
228 bp::ipstream std_err;
229
230 bp::child child(executable, bp::args(args),
231 bp::std_out > std_out,
232 bp::std_err > std_err);
233
234 // Read both streams on separate threads while the process runs
235 std::thread stdout_reader([&]() {
236 std::string line;
237 while (std::getline(std_out, line))
238 result.stdout_output += line + '\n';
239 });
240
241 std::thread stderr_reader([&]() {
242 std::string line;
243 while (std::getline(std_err, line))
244 result.stderr_output += line + '\n';
245 });
246
247 child.wait();
248 stdout_reader.join();
249 stderr_reader.join();
250
251 result.exit_code = child.exit_code();
252 } catch (const std::exception&) {
253 result.exit_code = -1;
254 }
255
256 return result;
257}
Definition ProcessRunner.hpp:40

References Slic3r::GUI::ProcessRunner::SyncResult::exit_code, Slic3r::GUI::ProcessRunner::SyncResult::stderr_output, and Slic3r::GUI::ProcessRunner::SyncResult::stdout_output.

◆ start_reader_threads()

void Slic3r::GUI::ProcessRunner::start_reader_threads ( )
private
34{
36
37 if (m_stdout_pipe) {
38 m_stdout_thread = std::thread([this]() {
39 std::string line;
40 while (std::getline(*m_stdout_pipe, line))
41 enqueue_output(std::move(line), false);
42 });
43 }
44
45 if (m_stderr_pipe) {
46 m_stderr_thread = std::thread([this]() {
47 std::string line;
48 while (std::getline(*m_stderr_pipe, line))
49 enqueue_output(std::move(line), true);
50 });
51 }
52}
void enqueue_output(std::string line, bool is_stderr)
Definition ProcessRunner.cpp:62

References enqueue_output(), join_reader_threads(), m_stderr_pipe, m_stderr_thread, m_stdout_pipe, and m_stdout_thread.

Referenced by run_command_line_async().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ terminate()

void Slic3r::GUI::ProcessRunner::terminate ( )
100{
101 m_poll_timer.Stop();
102
104
105 if (m_process && m_process->running()) {
106 std::error_code ec;
107 m_process->terminate(ec);
108 m_process->wait(ec);
109 }
110
111 if (m_process) {
112 finish_process(m_process->exit_code());
113 } else if (m_launch_failed.exchange(false) || m_on_done) {
114 finish_process(-1);
115 }
116}

References finish_process(), join_launch_thread(), m_launch_failed, m_on_done, m_poll_timer, and m_process.

Referenced by ~ProcessRunner().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ write_stdin()

void Slic3r::GUI::ProcessRunner::write_stdin ( const std::string & data)
206{
207 if (m_launching.load() || !m_stdin_pipe || !m_process || !m_process->running())
208 return;
209
210 *m_stdin_pipe << data;
211 m_stdin_pipe->flush();
212}

References m_launching, m_process, and m_stdin_pipe.

Member Data Documentation

◆ m_launch_failed

std::atomic_bool Slic3r::GUI::ProcessRunner::m_launch_failed {false}
private
74{false};

Referenced by on_timer(), run_command_line_async(), and terminate().

◆ m_launch_thread

std::thread Slic3r::GUI::ProcessRunner::m_launch_thread
private

◆ m_launching

std::atomic_bool Slic3r::GUI::ProcessRunner::m_launching {false}
private

◆ m_on_done

DoneCallback Slic3r::GUI::ProcessRunner::m_on_done
private

◆ m_on_output

OutputCallback Slic3r::GUI::ProcessRunner::m_on_output
private

◆ m_output_mutex

std::mutex Slic3r::GUI::ProcessRunner::m_output_mutex
private

◆ m_output_queue

std::vector<OutputLine> Slic3r::GUI::ProcessRunner::m_output_queue
private

◆ m_poll_timer

wxTimer Slic3r::GUI::ProcessRunner::m_poll_timer
private

◆ m_process

std::unique_ptr<boost::process::child> Slic3r::GUI::ProcessRunner::m_process
private

◆ m_stderr_pipe

std::unique_ptr<boost::process::ipstream> Slic3r::GUI::ProcessRunner::m_stderr_pipe
private

◆ m_stderr_thread

std::thread Slic3r::GUI::ProcessRunner::m_stderr_thread
private

◆ m_stdin_pipe

std::unique_ptr<boost::process::opstream> Slic3r::GUI::ProcessRunner::m_stdin_pipe
private

◆ m_stdout_pipe

std::unique_ptr<boost::process::ipstream> Slic3r::GUI::ProcessRunner::m_stdout_pipe
private

◆ m_stdout_thread

std::thread Slic3r::GUI::ProcessRunner::m_stdout_thread
private

The documentation for this class was generated from the following files: