124 lines
3.5 KiB
Plaintext
124 lines
3.5 KiB
Plaintext
|
[section:quickstart Quickstart]
|
||
|
|
||
|
A process needs four things to be launched:
|
||
|
|
||
|
* an asio execution_context / executor
|
||
|
* a path to an executable
|
||
|
* a list of arguments
|
||
|
* a variadic set of initializers
|
||
|
|
||
|
```
|
||
|
// process(asio::any_io_executor, filesystem::path, range<string> args, AdditionalInitializers...)
|
||
|
asio::io_context ctx;
|
||
|
process proc(ctx, "/usr/bin/cp", {"source.txt", "target.txt"});
|
||
|
```
|
||
|
|
||
|
|
||
|
The started process can then be awaited or terminated.
|
||
|
|
||
|
[section:lifetime Lifetime]
|
||
|
|
||
|
If the process handle goes out of scope, it will terminate the subprocess.
|
||
|
You can prevent this, by calling `proc.detach()`; do however note that this
|
||
|
can lead to zombie processes.
|
||
|
|
||
|
A process that completed will deliver an exit-code,
|
||
|
which can be obtained by calling `.exit_code` on the exited process and which is
|
||
|
also returned from `.wait()`.
|
||
|
|
||
|
```
|
||
|
process proc("/bin/ls", {});
|
||
|
assert(proc.wait() == 0);
|
||
|
```
|
||
|
|
||
|
The normal exit-code is what the subprocess returned from `main`;
|
||
|
posix will however add additional information about the process.
|
||
|
This is called the `native_exit_code`.
|
||
|
|
||
|
|
||
|
The `.running()` function can be used to detect if the process is still active.
|
||
|
|
||
|
[endsect]
|
||
|
|
||
|
[section:signal Signalling the subprocess]
|
||
|
|
||
|
The parent process can signal the subprocess demanding certain actions.
|
||
|
|
||
|
`.terminate` will cause the subprocess to exit immediately (`SIGKILL` on posix).
|
||
|
This is the only reliable & portable way to end a subprocess.
|
||
|
|
||
|
```
|
||
|
process proc("/bin/totally-not-a-virus", {});
|
||
|
proc.terminate();
|
||
|
```
|
||
|
|
||
|
`.request_exit` will ask the subprocess to shutdown (`SIGTERM` on posix),
|
||
|
which the subprocess might ignore.
|
||
|
|
||
|
```
|
||
|
process proc("/bin/bash", {});
|
||
|
proc.request_exit();
|
||
|
proc.wait();
|
||
|
```
|
||
|
|
||
|
`.interrupt` will send an SIGINT to the subprocess, which a subprocess might
|
||
|
interpret as a signal to shutdown.
|
||
|
|
||
|
[warning interrupt requires the initializer `windows::create_new_process_group` to be set]
|
||
|
|
||
|
```
|
||
|
process proc("/usr/bin/addr2line", {});
|
||
|
proc.request_exit();
|
||
|
proc.wait();
|
||
|
```
|
||
|
|
||
|
[endsect]
|
||
|
|
||
|
[section:execute Execute functions]
|
||
|
|
||
|
Process v2 provides `execute` and `async_execute` functions that can be used for managed executions.
|
||
|
|
||
|
```
|
||
|
assert(execute(process("/bin/ls", {}) == 0));
|
||
|
```
|
||
|
|
||
|
The async version supports cancellation and will forward cancellation types as follows:
|
||
|
|
||
|
- asio::cancellation_type::total -> interrupt
|
||
|
- asio::cancellation_type::partial -> request_exit
|
||
|
- asio::cancellation_type::terminal -> terminate
|
||
|
|
||
|
```
|
||
|
asio::io_context ctx;
|
||
|
asio::steady_timer timeout{ctx, std::chrono::seconds(10)};
|
||
|
|
||
|
asio::cancellation_signal sig;
|
||
|
async_execute(process("/usr/bin/g++", {"hello_world.cpp"}),
|
||
|
asio::bind_cancellation_slot(sig.slot(),
|
||
|
[&](error_code ec, int exit_code)
|
||
|
{
|
||
|
timeout.cancel(); // we're done earlier
|
||
|
}));
|
||
|
|
||
|
timeout.async_wait(
|
||
|
[&](error_code ec)
|
||
|
{
|
||
|
if (ec) // we were cancelled, do nothing
|
||
|
return ;
|
||
|
sig.emit(asio::cancellation_type::partial);
|
||
|
// request exit first, but terminate after another 10 sec
|
||
|
timeout.expires_after(std::chrono::seconds(10));
|
||
|
timeout.async_wait(
|
||
|
[&](error_code ec)
|
||
|
{
|
||
|
if (!ec)
|
||
|
sig.emit(asio::cancellation_type::terminal);
|
||
|
});
|
||
|
);
|
||
|
});
|
||
|
|
||
|
```
|
||
|
|
||
|
[endsect]
|
||
|
|
||
|
[endsect]
|