5#include "../Foundation/Compiler.h"
6#ifndef SC_EXPORT_LIBRARY_PROCESS
7#define SC_EXPORT_LIBRARY_PROCESS 0
9#define SC_PROCESS_EXPORT SC_COMPILER_LIBRARY_EXPORT(SC_EXPORT_LIBRARY_PROCESS)
11#include "../File/File.h"
12#include "../Foundation/AlignedStorage.h"
13#include "../Foundation/Internal/IGrowableBuffer.h"
14#include "../Foundation/StringPath.h"
18struct SC_PROCESS_EXPORT ProcessChain;
22 using Handle = detail::FileDescriptorDefinition::Handle;
23 static constexpr auto Invalid = detail::FileDescriptorDefinition::Invalid;
79 static constexpr size_t InlineCommandStorageCapacity = StringPath::MaxPath + 1024;
92 growableBuffer = &destination;
93 operation = Operation::GrowableBuffer;
99 operation = Operation::FileDescriptor;
100 (void)file.content.get(fileDescriptor, Result::Error(
"Invalid redirection file descriptor"));
101 file.content.detach();
104 StdStream(GrowableBuffer<PipeDescriptor>& pipe)
106 operation = Operation::ExternalPipe;
107 pipeDescriptor = &pipe.content;
110 StdStream(
const StdStream&) =
delete;
111 StdStream(StdStream&&) =
delete;
112 StdStream& operator=(
const StdStream&) =
delete;
113 StdStream& operator=(StdStream&&) =
delete;
135 Operation operation = Operation::Inherit;
140 IGrowableBuffer* growableBuffer =
nullptr;
142 FileDescriptor::Handle fileDescriptor;
155 StdOut(GrowableBuffer<StdOut::Ignore>) { operation = Operation::Ignore; }
158 StdOut(GrowableBuffer<StdOut::Inherit>) { operation = Operation::Inherit; }
159 StdOut(GrowableBuffer<StdOut>) { operation = Operation::Inherit; }
160 StdOut() { operation = Operation::Inherit; }
163 StdOut(GrowableBuffer<
Span<char>>& span) { operation = Operation::WritableSpan; writableSpan = &span.content; span.setContentInDestructor =
false; }
165 using StdStream::StdStream;
170 using StdErr = StdOut;
178 StdIn(GrowableBuffer<Inherit>) { operation = Operation::Inherit; }
179 StdIn(GrowableBuffer<StdIn>) { operation = Operation::Inherit; }
180 StdIn() { operation = Operation::Inherit; }
183 template <
int N>
StdIn(GrowableBuffer<
const char [N]>& item) { operation = Operation::ReadableSpan; readableSpan = {item.content, N - 1}; }
186 StdIn(GrowableBuffer<StringSpan>
string) { operation = Operation::ReadableSpan; readableSpan =
string.content.toCharSpan();}
191 using StdStream::StdStream;
199 ProcessDescriptor::Handle handle = ProcessDescriptor::Invalid;
211 template <
typename Out = StdOut,
typename In = StdIn,
typename Err = StdErr>
214 SC_TRY(formatArguments(cmd));
215 GrowableBuffer<typename TypeTraits::RemoveReference<Out>::type> gbOut = {stdOut};
216 GrowableBuffer<typename TypeTraits::RemoveReference<In>::type> gbIn = {stdIn};
217 GrowableBuffer<typename TypeTraits::RemoveReference<Err>::type> gbErr = {stdErr};
228 template <
typename Out = StdOut,
typename In = StdIn,
typename Err = StdErr>
231 SC_TRY(launch(cmd, stdOut, stdIn, stdErr));
232 return waitForExitSync();
260 : command({commandMemory}), environment({environmentMemory})
262 if (commandMemory.empty())
263 command = {commandStorage};
264 if (environmentMemory.empty())
265 environment = {environmentStorage};
269 ProcessExitStatus exitStatus;
271 FileDescriptor stdInFd;
272 FileDescriptor stdOutFd;
273 FileDescriptor stdErrFd;
275 Result launch(
const StdOut& stdOutput,
const StdIn& stdInput,
const StdErr& stdError);
277 Result formatArguments(Span<const StringSpan> cmd);
279 StringPath currentDirectory;
286 StringSpan::NativeWritable command;
287#if !SC_PLATFORM_WINDOWS
288 static constexpr size_t MAX_NUM_ARGUMENTS = 64;
289 size_t commandArgumentsByteOffset[MAX_NUM_ARGUMENTS];
290 size_t commandArgumentsNumber = 0;
294 StringSpan::NativeWritable environment;
296 static constexpr size_t MAX_NUM_ENVIRONMENT = 256;
298 size_t environmentByteOffset[MAX_NUM_ENVIRONMENT];
299 size_t environmentNumber = 0;
301 bool inheritEnv =
true;
303 friend struct ProcessChain;
304 ProcessChain* parent =
nullptr;
306 Process* next =
nullptr;
307 Process* prev =
nullptr;
310 friend struct ProcessFork;
311 Result launchImplementation();
312 Result launchForkChild(PipeDescriptor& pipe);
313 Result launchForkParent(PipeDescriptor& pipe,
const void* previousSignals);
344 template <
typename Out = Process::StdOut,
typename In = Process::StdIn,
typename Err = Process::StdErr>
345 Result launch(Out&& stdOut = Out(), In&& stdIn = In(), Err&& stdErr = Err())
347 GrowableBuffer<typename TypeTraits::RemoveReference<Out>::type> gbOut = {stdOut};
348 GrowableBuffer<typename TypeTraits::RemoveReference<In>::type> gbIn = {stdIn};
349 GrowableBuffer<typename TypeTraits::RemoveReference<Err>::type> gbErr = {stdErr};
350 return internalLaunch(gbOut, gbIn, gbErr);
359 template <
typename Out = Process::StdOut,
typename In = Process::StdIn,
typename Err = Process::StdErr>
360 Result exec(Out&& stdOut = Out(), In&& stdIn = In(), Err&& stdErr = Err())
362 SC_TRY(launch(stdOut, stdIn, stdErr));
363 return waitForExitSync();
369 struct ProcessLinkedList
374 [[nodiscard]]
bool isEmpty()
const {
return front ==
nullptr; }
377 void queueBack(Process& process);
379 ProcessLinkedList processes;
397 [[nodiscard]]
size_t size()
const {
return numberOfEnvironment; }
418 size_t numberOfEnvironment = 0;
419#if SC_PLATFORM_WINDOWS
420 static constexpr size_t MAX_ENVIRONMENTS = 256;
423 wchar_t* environment =
nullptr;
425 char** environment =
nullptr;
495 Side side = ForkParent;
496#if SC_PLATFORM_WINDOWS
497 ProcessDescriptor::Handle processHandle = ProcessDescriptor::Invalid;
498 ProcessDescriptor::Handle threadHandle = ProcessDescriptor::Invalid;
int int32_t
Platform independent (4) bytes signed int.
Definition PrimitiveTypes.h:37
char native_char_t
The native char for the platform (wchar_t (4 bytes) on Windows, char (1 byte) everywhere else )
Definition PrimitiveTypes.h:25
#define SC_TRY(expression)
Checks the value of the given expression and if failed, returns this value to caller.
Definition Result.h:49
[UniqueHandleDeclaration2Snippet]
Definition File.h:128
Read / Write pipe (Process stdin/stdout and IPC communication)
Definition File.h:300
Execute multiple child processes chaining input / output between them.
Definition Process.h:333
Result launch(Out &&stdOut=Out(), In &&stdIn=In(), Err &&stdErr=Err())
Launch the entire chain of processes.
Definition Process.h:345
Result pipe(Process &process, const Span< const StringSpan > cmd)
Add a process to the chain, with given arguments.
Result exec(Out &&stdOut=Out(), In &&stdIn=In(), Err &&stdErr=Err())
Launch the entire chain of processes and waits for the results (calling ProcessChain::waitForExitSync...
Definition Process.h:360
Result waitForExitSync()
Waits (blocking) for entire process chain to exit.
Reads current process environment variables.
Definition Process.h:387
bool get(size_t index, StringSpan &name, StringSpan &value) const
Get the environment variable at given index, returning its name and value.
bool get(StringSpan variableName, StringSpan &value) const
Gets the value of an environment variable from current process.
size_t size() const
Returns the total number of environment variables for current process.
Definition Process.h:397
bool contains(StringSpan variableName, size_t *index=nullptr) const
Checks if an environment variable exists in current process.
Wraps the code returned by a process that has exited.
Definition Process.h:28
Forks current process exiting child at end of process A fork duplicates a parent process execution st...
Definition Process.h:455
Result waitForChild()
Waits for child fork to finish execution.
State
Definition Process.h:471
@ Suspended
Start the forked process suspended (resume it with ProcessFork::resumeChildFork)
Definition Process.h:472
@ Immediate
Start the forked process immediately.
Definition Process.h:473
Side getSide() const
Obtain process parent / fork side.
Definition Process.h:468
FileDescriptor & getWritePipe()
Gets the descriptor to "write" something to the other side.
Side
Definition Process.h:462
@ ForkParent
Parent side of the fork.
Definition Process.h:463
@ ForkChild
Child side of the fork.
Definition Process.h:464
Result resumeChildFork()
Sends 1 byte on parentToFork to resume State::Paused child fork.
FileDescriptor & getReadPipe()
Gets the descriptor to "read" something from the other side.
Result fork(State state)
Forks current process (use ForkProcess::getType to know the side)
int32_t getExitStatus() const
Gets the return code from the exited child fork.
Definition Process.h:486
Native os handle to a process identifier.
Definition Process.h:40
bool windowsHide
[Windows] Hides child process window (default == Process::isWindowsConsoleSubsystem)
Definition Process.h:83
StdIn(GrowableBuffer< Span< const char > > span)
Fills standard input with content of a Span.
Definition Process.h:189
StdIn(GrowableBuffer< Inherit >)
Inherits child process Input from parent process.
Definition Process.h:178
StdIn(GrowableBuffer< const char[N]> &item)
Fills standard input with content of a C-String.
Definition Process.h:183
StdIn(GrowableBuffer< StringSpan > string)
Fills standard input with content of a StringSpan.
Definition Process.h:186
StdOut(GrowableBuffer< Span< char > > &span)
Read the process standard output/error into the given Span.
Definition Process.h:163
StdOut(GrowableBuffer< StdOut::Inherit >)
Inherits child process standard output/error (child process will print into parent process console)
Definition Process.h:158
StdOut(GrowableBuffer< StdOut::Ignore >)
Ignores child process standard output/error (child process output will be silenced)
Definition Process.h:155
StdStream(GrowableBuffer< FileDescriptor > &file)
Redirects child process standard output/error to a given file descriptor.
Definition Process.h:97
StdStream(IGrowableBuffer &destination)
Read the process standard output/error into the given String / Buffer.
Definition Process.h:90
Execute a child process with standard file descriptors redirection.
Definition Process.h:78
int32_t getExitStatus() const
gets the return code from the exited child process (valid only after exec or waitForExitSync)
Definition Process.h:236
Result exec(Span< const StringSpan > cmd, Out &&stdOut=Out(), In &&stdIn=In(), Err &&stdErr=Err())
Executes a child process with the given arguments, waiting (blocking) until it's fully finished.
Definition Process.h:229
Result setEnvironment(StringSpan environmentVariable, StringSpan value)
Sets the environment variable for the newly spawned child process.
Process(Span< native_char_t > commandMemory={}, Span< native_char_t > environmentMemory={})
Constructs a Process object passing (optional) memory storage for command and environment variables.
Definition Process.h:259
Options options
Options for the child process (hide console window etc.)
Definition Process.h:197
static bool isWindowsEmulatedProcess()
Returns true if we're emulating x64 on ARM64 or the inverse on Windows.
void inheritParentEnvironmentVariables(bool inherit)
Controls if the newly spawned child process will inherit parent process environment variables.
Definition Process.h:242
ProcessID processID
ID of the process (can be the same as handle on Posix)
Definition Process.h:196
static bool isWindowsConsoleSubsystem()
Returns true only under Windows if executable is compiled with /SUBSYSTEM:Console
Result launch(Span< const StringSpan > cmd, Out &&stdOut=Out(), In &&stdIn=In(), Err &&stdErr=Err())
Launch child process with the given arguments.
Definition Process.h:212
static size_t getNumberOfProcessors()
Returns number of (virtual) processors available.
Result setWorkingDirectory(StringSpan processWorkingDirectory)
Sets the starting working directory of the process that will be launched / executed.
Result waitForExitSync()
Waits (blocking) for process to exit after launch. It can only be called if Process::launch succeeded...
An ascii string used as boolean result. SC_TRY macro forwards errors to caller.
Definition Result.h:13
View over a contiguous sequence of items (pointer + size in elements).
Definition Span.h:29
An read-only view over a string (to avoid including Strings library when parsing is not needed).
Definition StringSpan.h:37