Stroika Library 3.0d25
 
Loading...
Searching...
No Matches
ProcessRunner.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Execution_ProcessRunner_h_
5#define _Stroika_Foundation_Execution_ProcessRunner_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <filesystem>
10#include <optional>
11
14#include "Stroika/Foundation/Common/Common.h"
15#include "Stroika/Foundation/Containers/Mapping.h"
16#include "Stroika/Foundation/Containers/Sequence.h"
18#include "Stroika/Foundation/Execution/CommandLine.h"
19#include "Stroika/Foundation/Execution/Process.h"
20#include "Stroika/Foundation/Execution/Signals.h"
24
25// DEPRECATED - only while we have deprecated apis for use of progressmontior in this class
26#include "Stroika/Foundation/Execution/ProgressMonitor.h"
27
28/**
29 * TODO:
30 * @todo After we lose DEPRECATED APIS (STREAM STUFF) - Run and RunInBackground can become const methods
31 *
32 * @todo Redo POSIX impl using vfork () or http://linux.die.net/man/3/posix_spawn
33 *
34 * @todo Fix POSIX version to use vfork() instead of fork () - but carefully! Must setup data just so.
35 *
36 * @todo Fix POSIX version to properly handle reading and writing streams at the same time to avoid deadlock
37 * in finite kernel buffer sizes.
38 *
39 * @todo Fix POSIX version to use pipe2 and close appropriate open file descriptors (and other 'clean invoke' stuff.
40 *
41 * @todo Redo DWORD waitResult = ::WaitForMultipleObjects()... logic to wait on thread and each read/write socket
42 * with select() AND somehow maybe eventually wait on streams (so we don't have to pre-read it all)
43 *
44 * @todo Make sure it handles well without blocking
45 * (tricks I had todo in HF - forcing extra reads so writes wouldn't block).
46 * Currently structured to work off a single runnable, which implies works off a single thread. That implies
47 * it must use select() - probably a good idea anyhow - on each socket used for operations (windows and POSIX).
48 *
49 * So data pusher/buffer loop does select on external streams to see if data available.
50 *
51 * This implies I must also be able to do the moral equivalent of selects on my BinaryInput/Output streams? Maybe,
52 * unless I do all the buffering... But at least for the stdin stream - I need to be able to check if/when there
53 * is new data available!!! TRICKY
54 *
55 * @todo Decide on/document semantics if there is a change in setting STDIN/SETDOUT etc while a runner exists?
56 * If error - always detectable?
57 *
58 * And related - what if we create a runner, and then destroy the object? How to assure runner fully
59 * destroyed? Blocking/waiting or error or detached state?
60 *
61 * @todo Add optional hook to be run (at least for POSIX) inside the FORKED process, before the exec.
62 * Can be used to reset signals, and/or close file descriptors. Maybe have optional
63 * flag to auto-do this stuff and or have a preset value hook proc do do most standard things.
64 *
65 * Design Goals:
66 * o Be able to run simple processes and capture output with little overhead, and very easy to do
67 * (like perl backticks).
68 *
69 * o Be able to support pipes between processes (either within the shell, or between Stroika threads)
70 *
71 * o Support large data and blocking issues properly - automating avoidance of pipe full bugs
72 * which block processes
73 *
74 * o Efficient/Low performance overhead
75 *
76 * o For POSIX - simple to cleanly cleanup open sockets/resources (not needed on windows)
77 *
78 * o Separate threading implementation from API, so easy to externally specify the thread
79 * stuff runs on (e.g. so you can use thread pools to run the processes).
80 *
81 * o Work with stroika streams so its easy to have user-defined producers and consumers, and
82 * easy to hook together TextStreams (wrappers) - for format conversion/piping.
83 *
84 * \em Design Overview
85 * o
86 *
87 */
88
90
91 using Characters::String;
92 using Containers::Mapping;
93 using Containers::Sequence;
94
95 /**
96 * \brief Run an external command, with stdin/stdout/stderr as strings or as streams - like perl backticks
97 *
98 * There are two ways to run, and the difference is all you really need to know:
99 *
100 * o Run () is synchronous. It returns the output, and THROWS on any failure - including the
101 * process merely exiting non-zero. Nothing to check; if it returns, it worked.
102 * o RunInBackground () hands back a BackgroundProcess you wait on and interrogate - exit status,
103 * signal, child pid - so you can treat a failed run as data instead of as an exception.
104 *
105 * Run () behaves as if it were RunInBackground (), then waiting, then
106 * ProcessResultType::ThrowIfFailed ().
107 *
108 * \note ProcessRunner searches the PATH for the given executable: it need not be a full or even relative to
109 * cwd path.
110 *
111 * \par Example Usage - Run (), the simple case
112 * \code
113 * String name = get<0> (ProcessRunner{"uname"}.Run (String {})).Trim ();
114 *
115 * ProcessRunner pr{"echo hi mom"};
116 * auto [stdOutStr, stdErrStr] = pr.Run (""); // throws if echo fails or exits non-zero
117 * EXPECT_EQ (stdOutStr.Trim (), "hi mom");
118 * \endcode
119 *
120 * \par Example Usage - RunInBackground (), when the exit status is data rather than an error
121 * \code
122 * ProcessRunner::BackgroundProcess bp = ProcessRunner{"grep pattern somefile"}.RunInBackground ();
123 * bp.WaitForDone ();
124 * // grep exits 1 for 'no match', which is an answer and not a failure
125 * optional<ProcessRunner::ProcessResultType> r = bp.GetProcessResult ();
126 * bool matched = r and r->fExitStatus == 0;
127 * \endcode
128 *
129 * \note Historical note: the idea came from KDJ - do something like python/perl subprocess handling,
130 * as a simple portable wrapper.
131 */
133 public:
134 static constexpr CommandLine::WrapInShell kDefaultShell =
135#if qStroika_Platform_Windows
136 CommandLine::WrapInShell::eWindowsCMD
137#else
138 CommandLine::WrapInShell::eBash
139#endif
140 ;
141
142 public:
143 /**
144 */
145 struct Options {
146 /**
147 * \brief pwd/cwd of the created process
148 * defaults to 'missing'. If missing, then WellKnownDirectories::GetTemporary () is
149 * used (since this is a generally safe place to run an executable); use filesystem::current_path () if that is the intention.
150 */
151 optional<filesystem::path> fWorkingDirectory;
152
153 /**
154 * If provided, child executed with this replacing its 'environment'; Variant 'Sequence<path>' means just the PATH part replaced.
155 * If Mapping<String,...> converted to SDKString codepage, and if SDKString provided, used as-is.
156 */
157 optional<variant<Sequence<filesystem::path>, Mapping<String, String>, Mapping<Characters::SDKString, Characters::SDKString>>> fEnvironment;
158
159 /**
160 * If true, then any nullptr input / output pipes are replaced with /dev/null (or equivalent)
161 * And any 'terminal' associated with the calling process is eliminated from the child
162 * process.
163 *
164 * Case POSIX:
165 * This also detaches from the terminal driver, to avoid spurious SIGHUP
166 * and SIGTTIN and SIGTTOU (setsid);
167 *
168 * Case Windoze:
169 * From: https://learn.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
170 * DETACHED_PROCESS - the new process does not inherit its parent's console
171 * This flag is ignored if the application is not a console application, or if it is used with either CREATE_NEW_CONSOLE or DETACHED_PROCESS
172 *
173 * \note replaces the Stroika v2.1 DetachedProcessRunner API
174 *
175 * \note as of Stroika v3.0d23, Run () API is not compatible with fDetached=true - use RunInBackground () API instead.
176 * This restriction may be lifted in a future release (if I can figure out what it means cleanly).
177 */
178 bool fDetached{false};
179
180#if qStroika_Platform_POSIX
181 /**
182 * \brief set umask of child process
183 *
184 * mostly harmless, not clearly needed, but suggested in http://codingfreak.blogspot.com/2012/03/daemon-izing-process-in-linux.html
185 */
186 optional<mode_t> fChildUMask{027};
187#endif
188
189#if qStroika_Platform_Windows
190 /**
191 * From: https://learn.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
192 * CONSOLE handle from this app not passed to child process. Obviates fDetachConsole.
193 */
194 bool fCreateNoWindow : 1 {true};
195
196#endif
197 };
198
199 public:
200 ProcessRunner () = delete;
201 ProcessRunner (const ProcessRunner&) = delete;
202 /**
203 * \brief Construct ProcessRunner with a CommandLine to run (doesn't actually RUN til you call Run or RunInBackground).
204 *
205 * \note overload with executable allows specifying an alternate executable to run, even though args[0] will be what is reported
206 * to that application (a somewhat common trick in unix-land).
207 *
208 * \note overload with String commandLine:
209 * Simple commands are run directly, and strings with apparent shell-isms, like pipes and quotes etc, are run through kDefaultShell.
210 * This overload is handy, but easy to explicitly control shell used with CommandLine argument instead.
211 */
212#if qCompilerAndStdLib_default_member_initializer_needed_within_enclosing_class_Buggy
213 ProcessRunner (const filesystem::path& executable, const CommandLine& args, const Options& o);
214 ProcessRunner (const CommandLine& args, const Options& o); ///< \brief Run args, whose args[0] is the executable
215 ProcessRunner (const String& commandLine, const Options& o); ///< \brief Run directly if simple, else through kDefaultShell
216 ProcessRunner (const filesystem::path& executable, const CommandLine& args); ///< \brief Same, with Options{}
217 ProcessRunner (const CommandLine& args); ///< \brief Same, with Options{}
218 ProcessRunner (const String& commandLine); ///< \brief Same, with Options{}
219#else
220 ProcessRunner (const filesystem::path& executable, const CommandLine& args, const Options& o = {});
221 ProcessRunner (const CommandLine& args, const Options& o = {}); ///< \brief Run args, whose args[0] is the executable
222 ProcessRunner (const String& commandLine, const Options& o = {}); ///< \brief Run directly if simple, else through kDefaultShell
223#endif
224
225 public:
226 nonvirtual ProcessRunner& operator= (const ProcessRunner&) = delete;
227
228 public:
229#if qStroika_Platform_POSIX
230 using ExitStatusType = uint8_t;
231#elif qStroika_Platform_Windows
232 using ExitStatusType = DWORD;
233#else
234 using ExitStatusType = int;
235#endif
236
237 public:
238 class Exception;
239
240 public:
241 /**
242 */
243 nonvirtual CommandLine GetCommandLine () const;
244 nonvirtual void SetCommandLine (const CommandLine& args);
245
246 public:
247 /**
248 */
249 nonvirtual Options GetOptions () const;
250 nonvirtual void SetOptions (const Options& o);
251
252 public:
253 /**
254 * Zero means success. Run() returns optional<ProcessResultType> by reference, and that
255 * value is only provided if the child process exited. If exited, we return the exit
256 * status and signal number (if any) - see waitpid - http://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html
257 */
258 struct [[nodiscard]] ProcessResultType {
259 optional<ExitStatusType> fExitStatus;
260 optional<SignalID> fTerminatedByUncaughtSignalNumber;
261
262 nonvirtual void ThrowIfFailed ();
263
264 /**
265 * Purely for debugging / diagnostic purposes. Don't count on this format.
266 */
267 nonvirtual String ToString () const;
268 };
269
270 public:
271 /**
272 * \brief Run () options for mapping Strings - what code page converters to use.
273 *
274 * \note defaults now are UTF-8, but don't count on this if you care about the encoding used (subject to change).
275 */
277 /**
278 * Input refers to the input of the sub-process being run. So this conversion is applied before sending the data to
279 * that process.
280 */
281 optional<Characters::CodeCvt<>> fInputCodeCvt;
282
283 /**
284 * Output refers to the output of the sub-process being run. So this conversion is applied to the data retrieved
285 * from that process.
286 */
287 optional<Characters::CodeCvt<>> fOutputCodeCvt;
288 };
289
290 public:
291 /**
292 * \brief Run the command synchronously, returning its output, and THROW on any failure
293 *
294 * o STRING overload: pass stdin as a string, get back {stdout, stderr}. Run () with no
295 * argument means Run (""). The simplest form.
296 * o STREAMS overload: pass binary streams instead. Any of the three left nullptr is
297 * redirected to /dev/null.
298 *
299 * \note Exceptions - failure is ONLY reported by throwing ProcessRunner::Exception, whether that is
300 * something going wrong before the process starts, a non-zero exit (Exception::fExitStatus),
301 * or death by an uncaught signal (Exception::fTermSignal). The string overload also captures
302 * the child's stderr into Exception::fStderrFragment, usually the only thing that says WHY.
303 * To read an exit status instead of catching it, use RunInBackground ().
304 *
305 * \note if this is called with a timeout, and it times out, the child is killed immediately upon timeout.
306 * To avoid this behavior, use RunInBackground
307 *
308 * \par Example Usage (using strings in/out)
309 * \code
310 * String name = get<0> (ProcessRunner{"uname"}.Run (String {})).Trim ();
311 * \endcode
312 *
313 * \par Example Usage (using binary streams)
314 * \code
315 * ProcessRunner pr{"cat"};
316 * Memory::BLOB kData_{ Memory::BLOB::FromRaw ("this is a test") };
317 * Streams::MemoryStream::Ptr<byte> processStdIn = Streams::MemoryStream::New<byte> (kData_);
318 * Streams::MemoryStream::Ptr<byte> processStdOut = Streams::MemoryStream::New<byte> ();
319 * pr.Run (processStdIn, processStdOut);
320 * EXPECT_EQ (processStdOut.ReadAll (), kData_);
321 * \endcode
322 *
323 * @see RunInBackground
324 */
325 nonvirtual void Run (const Streams::InputStream::Ptr<byte>& in, const Streams::OutputStream::Ptr<byte>& out = nullptr,
326 const Streams::OutputStream::Ptr<byte>& error = nullptr, Time::DurationSeconds timeout = Time::kInfinity);
327 nonvirtual tuple<Characters::String, Characters::String> Run (const Characters::String& cmdStdInValue = ""sv,
328 const StringOptions& stringOpts = {},
329 Time::DurationSeconds timeout = Time::kInfinity);
330
331 public:
332 class BackgroundProcess;
333
334 public:
335 /**
336 * \brief Run the given external command/process (set by constructor) - with the given arguments in the background,
337 * and return a handle to the results.
338 *
339 * This function is generally quick, and non-blocking - just creates a thread todo the work.
340 *
341 * \note it is perfectly legal to launch a subprocess, and not track it in any way, just ignoring (not saving)
342 * the BackgroundProcess object.
343 *
344 * \note if options.fDetached is true, as of Stroika v3.0d23, then we REQUIRE (in==nullptr, out==nullptr, and err==nullptr)
345 * and this means no data is written to the detached process, and no data is read from it.
346 *
347 * @see Run
348 */
350 const Streams::OutputStream::Ptr<byte>& out = nullptr,
351 const Streams::OutputStream::Ptr<byte>& error = nullptr);
352
353 private:
354 /**
355 * @brief like CreateDetailedRunnable_, but doesnt track pid or result - just creates runnable to execute
356 */
357 nonvirtual function<void ()> CreateSimpleRunnable_ ();
358
359 private:
360 /**
361 * Capture the process results and running PID. NOTE - this uses Synchronized, since its generally looked at and set from
362 * two different threads.
363 */
364 struct DetailedRunnableRep_ {
366 Synchronized<optional<pid_t>> fRunningPID;
367 };
368
369 private:
370 /**
371 * @brief DOESNT run anything - but creates a function object that when run will do the work of running the process, and returns a shared DetailedRunnableRep_ to track the progress of the runnable when run
372 *
373 * Note that 'in' will be sent to the stdin of the subprocess, 'out' will be read from the
374 * stdout of the subprocess and error will be read from the stderr of the subprocess.
375 *
376 * Each of these CAN be null, and will if so, that will be interpreted as an empty stream
377 * (for in/stdin), and for out/error, just means the results will be redirected to /dev/null.
378 *
379 * Note the runnable holds onto shared_ptr<DetailedRunnableRep_> so it doesn't NEED to be by the caller - just hold
380 * onto it if you want to see the results.
381 */
382 nonvirtual tuple<function<void ()>, shared_ptr<DetailedRunnableRep_>> CreateDetailedRunnable_ ();
383
384 private:
385#if qStroika_Platform_POSIX
386 static void Process_Runner_POSIX_ (const shared_ptr<DetailedRunnableRep_>& runneeDetails,
387 [[maybe_unused]] const optional<filesystem::path>& executable, const CommandLine& cmdLine,
388 const ProcessRunner::Options& options, const Streams::InputStream::Ptr<byte>& in,
390#elif qStroika_Platform_Windows
391 static void Process_Runner_Windows_ (const shared_ptr<DetailedRunnableRep_>& runneeDetails,
392 const optional<filesystem::path>& executable, const CommandLine& cmdLine,
393 const ProcessRunner::Options& options, const Streams::InputStream::Ptr<byte>& in,
395#endif
396
397 private:
398 optional<filesystem::path> fExecutable_; // if omitted, derived from fArgs[0]
399 CommandLine fArgs_;
400 Options fOptions_;
401 Streams::InputStream::Ptr<byte> fStdIn_; // just while we support deprecated API
405
406 public:
407 [[deprecated ("Since Stroika v3.0d12 - pass stdin/stdout/stderr to ProcessRunner Run() method (if needed)")]] ProcessRunner (
408 const filesystem::path& executable, const CommandLine& args, const Streams::InputStream::Ptr<byte>& in,
409 const Streams::OutputStream::Ptr<byte>& out = nullptr, const Streams::OutputStream::Ptr<byte>& error = nullptr);
410 [[deprecated ("Since Stroika v3.0d12 - pass stdin/stdout/stderr to ProcessRunner Run() method (if needed)")]] ProcessRunner (
411 const CommandLine& args, const Streams::InputStream::Ptr<byte>& in, const Streams::OutputStream::Ptr<byte>& out = nullptr,
412 const Streams::OutputStream::Ptr<byte>& error = nullptr);
413 [[deprecated ("Since Stroika v3.0d12 - pass stdin/stdout/stderr to ProcessRunner Run() method (if needed)")]] ProcessRunner (
414 const String& commandLine, const Streams::InputStream::Ptr<byte>& in, const Streams::OutputStream::Ptr<byte>& out = nullptr,
415 const Streams::OutputStream::Ptr<byte>& error = nullptr)
416 : ProcessRunner{commandLine}
417 {
418 this->fStdIn_ = in;
419 this->fStdOut_ = out;
420 this->fStdErr_ = error;
421 }
422
423 [[deprecated ("Since Stroika v3.0d12 - use other overloads for ProcessRunner")]] ProcessRunner (
424 const filesystem::path& executable, const Containers::Sequence<String>& args, const Streams::InputStream::Ptr<byte>& in = nullptr,
425 const Streams::OutputStream::Ptr<byte>& out = nullptr, const Streams::OutputStream::Ptr<byte>& error = nullptr)
426 : ProcessRunner{executable, CommandLine{args}}
427 {
428 this->fStdIn_ = in;
429 this->fStdOut_ = out;
430 this->fStdErr_ = error;
431 }
432
433 [[deprecated ("Since Stroika v3.0d12 - pass in/out/error streams(can be nullptr) to Run method instead of CTOR")]] void
434 Run (optional<ProcessResultType>* processResult, ProgressMonitor::Updater progress = nullptr, Time::DurationSeconds timeout = Time::kInfinity);
435
436 [[deprecated ("Since Stroika v3.0d12 pass in/out/error(can be nullptr) in RunInbackground() method")]] BackgroundProcess
437 RunInBackground (ProgressMonitor::Updater progress);
438
439 [[deprecated ("Since Stroika v3.0d23d")]] BackgroundProcess RunInBackground (const Streams::InputStream::Ptr<byte>& in,
442 [[maybe_unused]] ProgressMonitor::Updater progress);
443
444 public:
445 //DEPRECATED
446 [[deprecated ("Since Stroika v3.0d23d")]] void Run (const Streams::InputStream::Ptr<byte>& in, const Streams::OutputStream::Ptr<byte>& out,
447 const Streams::OutputStream::Ptr<byte>& error, ProgressMonitor::Updater progress,
448 Time::DurationSeconds timeout = Time::kInfinity);
449 [[deprecated ("Since Stroika v3.0d23d")]] tuple<Characters::String, Characters::String>
450 Run (const Characters::String& cmdStdInValue, const StringOptions& stringOpts, ProgressMonitor::Updater progress,
451 Time::DurationSeconds timeout = Time::kInfinity);
452
453 public:
454 /**
455 */
456 [[deprecated ("Since Stroika v3.0d12 - use GetOptions().fWorkingDirectory")]] optional<filesystem::path> GetWorkingDirectory () const;
457 [[deprecated ("Since Stroika v3.0d12 - use SetOptions({.fWorkingDirectory})")]] void SetWorkingDirectory (const optional<filesystem::path>& d);
458
459 public:
460 /**
461 * If empty, stdin will not be empty (redirected from /dev/null).
462 *
463 * Otherwise, the stream will be 'read' by the ProcessRunner and 'fed' downstream to
464 * the running subprocess.
465 */
466 [[deprecated ("Since Stroika v3.0d12 - pass in/out/error streams(can be nullptr) to Run method instead of CTOR")]] Streams::InputStream::Ptr<byte>
467 GetStdIn () const;
468 [[deprecated ("Since Stroika v3.0d12 - pass in/out/error streams(can be nullptr) to Run method instead of CTOR")]] void
469 SetStdIn (const Streams::InputStream::Ptr<byte>& in);
470
471 public:
472 /**
473 * If empty, stdout will not be captured (redirected to /dev/null)
474 */
475 [[deprecated ("Since Stroika v3.0d12 - pass in/out/error streams(can be nullptr) to Run method instead of CTOR")]] Streams::OutputStream::Ptr<byte>
476 GetStdOut () const;
477 [[deprecated ("Since Stroika v3.0d12 - pass in/out/error streams(can be nullptr) to Run method instead of CTOR")]] void
478 SetStdOut (const Streams::OutputStream::Ptr<byte>& out);
479
480 public:
481 /**
482 * If empty, stderr will not be captured (redirected to /dev/null)
483 */
484 [[deprecated ("Since Stroika v3.0d12 - pass in/out/error streams(can be nullptr) to Run method instead of CTOR")]] Streams::OutputStream::Ptr<byte>
485 GetStdErr () const;
486 [[deprecated ("Since Stroika v3.0d12 - pass in/out/error streams(can be nullptr) to Run method instead of CTOR")]] void
487 SetStdErr (const Streams::OutputStream::Ptr<byte>& err);
488 };
489
490 /**
491 * Exceptions generated by ProcessRunner are typically of this sort.
492 */
493 class ProcessRunner::Exception : public Execution::Exception<runtime_error> {
494 private:
496
497 public:
498 /**
499 */
502
503 public:
504 /**
505 * High level summary - not including stuff like exit status, stderr results etc
506 */
508
509 public:
510 const optional<String> fStderrFragment;
511
512 public:
513 const optional<ExitStatusType> fExitStatus;
514
515 public:
516 const optional<SignalID> fTermSignal;
517
518 private:
521 };
522
523 /**
524 * Support more controlled running of sub-process, where wait timeouts don't necessarily kill the child process.
525 *
526 * \note it is perfectly legal to launch a subprocess, and not track it in any way, just ignoring (not saving)
527 * the BackgroundProcess object.
528 */
530 private:
532
533 public:
534 BackgroundProcess (const BackgroundProcess&) = default;
535
536 public:
537 /**
538 * Return missing if process still running, and if completed, return the results.
539 */
540 nonvirtual optional<ProcessResultType> GetProcessResult () const;
541
542 public:
543 /**
544 * \brief maybe missing if process not yet (or ever successfully) launched. Child process may have
545 * already exited by the time this is returned.
546 */
547 optional<pid_t> GetChildProcessID () const;
548
549 public:
550 /**
551 * \brief wait until GetChildProcessID () returns a valid answer, or until the process failed to start
552 * (in which case calls PropagateIfException).
553 */
554 nonvirtual void WaitForStarted (Time::DurationSeconds timeout = Time::kInfinity) const;
555
556 public:
557 /**
558 *
559 * @see Join ()
560 * @see JoinUntil ()
561 */
562 nonvirtual void WaitForDone (Time::DurationSeconds timeout = Time::kInfinity) const;
563
564 public:
565 /**
566 * \brief Join () does WaitForDone () and throw exception if there was any error (see PropagateIfException).
567 *
568 * \note Aliases - this used to be called WaitForDoneAndPropagateErrors; but used the name Join () to mimic the name used with Threads - NOT
569 * because that's used in the implementation, but because its essentially logically the same thing.
570 *
571 * @see JoinUntil ()
572 * @see WaitForDone ()
573 */
574 nonvirtual void Join (Time::DurationSeconds timeout = Time::kInfinity) const;
575
576 public:
577 /**
578 * \brief WaitForDoneUntil () and throw exception if there was any error (see PropagateIfException).
579 *
580 * @see Join ()
581 * @see WaitForDone ()
582 */
583 nonvirtual void JoinUntil (Time::TimePointSeconds timeoutAt) const;
584
585 public:
586 /**
587 * If the process has completed with an error, throw exception reflecting that failure.
588 *
589 * \note if the process has not completed, this likely does nothing.
590 */
591 nonvirtual void PropagateIfException () const;
592
593 public:
594 /**
595 * If the process is still running, terminate it.
596 */
597 nonvirtual void Terminate ();
598
599 public:
600 /**
601 * Purely for debugging / diagnostic purposes. Don't count on this format.
602 */
603 nonvirtual String ToString () const;
604
605 private:
606 struct Rep_ {
607 virtual ~Rep_ () = default;
608 Thread::CleanupPtr fProcessRunner{Thread::CleanupPtr::eAbortBeforeWaiting};
609 shared_ptr<DetailedRunnableRep_> fDetailedRunnableRep_;
610 };
611 shared_ptr<Rep_> fRep_;
613
614 private:
615 friend class ProcessRunner;
616 };
617
618}
619
620/*
621 ********************************************************************************
622 ***************************** Implementation Details ***************************
623 ********************************************************************************
624 */
625#include "ProcessRunner.inl"
626
627#endif /*_Stroika_Foundation_Execution_ProcessRunner_h_*/
time_point< RealtimeClock, DurationSeconds > TimePointSeconds
TimePointSeconds is a simpler approach to chrono::time_point, which doesn't require using templates e...
Definition Realtime.h:82
chrono::duration< double > DurationSeconds
chrono::duration<double> - a time span (length of time) measured in seconds, but high precision.
Definition Realtime.h:57
#define Stroika_ATTRIBUTE_NO_UNIQUE_ADDRESS_VCFORCE
[[msvc::no_unique_address]] isn't always broken in MSVC. Annotate with this on things where its not b...
Definition StdCompat.h:481
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
A Mapping uniquely associates two elements: a key and a value (use Assocation to allow multiple value...
A generalization of a vector: a container whose elements are keyed by the natural numbers.
NOT a real mutex - just a debugging infrastructure support tool so in debug builds can be assured thr...
Exception<> is a replacement (subclass) for any std c++ exception class (e.g. the default 'std::excep...
Definition Exceptions.h:219
Exception()=delete
construct with just a message - BASE_EXCEPTION gets whatever it minimally needs.
nonvirtual void WaitForStarted(Time::DurationSeconds timeout=Time::kInfinity) const
wait until GetChildProcessID () returns a valid answer, or until the process failed to start (in whic...
nonvirtual optional< ProcessResultType > GetProcessResult() const
nonvirtual void WaitForDone(Time::DurationSeconds timeout=Time::kInfinity) const
nonvirtual void Join(Time::DurationSeconds timeout=Time::kInfinity) const
Join () does WaitForDone () and throw exception if there was any error (see PropagateIfException).
nonvirtual void JoinUntil(Time::TimePointSeconds timeoutAt) const
WaitForDoneUntil () and throw exception if there was any error (see PropagateIfException).
optional< pid_t > GetChildProcessID() const
maybe missing if process not yet (or ever successfully) launched. Child process may have already exit...
Run an external command, with stdin/stdout/stderr as strings or as streams - like perl backticks.
Streams::InputStream::Ptr< byte > GetStdIn() const
Streams::OutputStream::Ptr< byte > GetStdOut() const
nonvirtual void Run(const Streams::InputStream::Ptr< byte > &in, const Streams::OutputStream::Ptr< byte > &out=nullptr, const Streams::OutputStream::Ptr< byte > &error=nullptr, Time::DurationSeconds timeout=Time::kInfinity)
Run the command synchronously, returning its output, and THROW on any failure.
nonvirtual BackgroundProcess RunInBackground(const Streams::InputStream::Ptr< byte > &in=nullptr, const Streams::OutputStream::Ptr< byte > &out=nullptr, const Streams::OutputStream::Ptr< byte > &error=nullptr)
Run the given external command/process (set by constructor) - with the given arguments in the backgro...
Streams::OutputStream::Ptr< byte > GetStdErr() const
ProcessRunner(const String &commandLine, const Options &o={})
Run directly if simple, else through kDefaultShell.
Wrap any object with Synchronized<> and it can be used similarly to the base type,...
InputStream<>::Ptr is Smart pointer (with abstract Rep) class defining the interface to reading from ...
OutputStream<>::Ptr is Smart pointer to a stream-based sink of data.
EXPECTED::value_type ThrowIfFailed(const EXPECTED &e)
Definition Throw.inl:190
Run () options for mapping Strings - what code page converters to use.