# procspawn
This crate provides the ability to spawn processes with a function similar
to `thread::spawn`.
Unlike `thread::spawn` data cannot be passed by the use of closures. Instead
if must be explicitly passed as serializable object (specifically it must be
[`serde`](https://serde.rs/) serializable). The return value from the
spawned closure also must be serializable and can then be retrieved from
the returned join handle.
If the spawned functiom causes a panic it will also be serialized across
the process boundaries.
## Example
First for all of this to work you need to invoke `procspawn::init` at a
point early in your program (somewhere at the beginning of the main function).
Whatever happens before that point also happens in your spawned functions.
Subprocesses are by default invoked with the same arguments and environment
variables as the parent process.
```rust
procspawn::init();
```
Now you can start spawning functions:
```rust
let data = vec![1, 2, 3, 4];
data.into_iter().sum::<i64>()
});
let result = handle.join().unwrap();
```
Because `procspawn` will invoke a subprocess and there is currently no
reliable way to intercept `main` in Rust it's necessary for you to call
[`procspawn::init`](https://docs.rs/procspawn/latest/procspawn/fn.init.html) explicitly an early time in the program.
Alternatively you can use the [`ProcConfig`](https://docs.rs/procspawn/latest/procspawn/struct.ProcConfig.html)
builder object to initialize the process which gives you some extra
abilities to customize the processes spawned. This for instance lets you
disable the default panic handling.
[`spawn`](https://docs.rs/procspawn/latest/procspawn/fn.spawn.html) can pass arbitrary serializable data, including
IPC senders and receivers from the [`ipc-channel`](https://crates.io/crates/ipc-channel)
crate, down to the new process.
## Pools
The default way to spawn processes will start and stop processes constantly.
For more uses it's a better idea to spawn a [`Pool`](https://docs.rs/procspawn/latest/procspawn/struct.Pool.html)
which will keep processes around for reuse. Between calls the processes
will stay around which also means the can keep state between calls if
needed.
## Panics
By default panics are captured and serialized across process boundaries.
This requires that the `backtrace` crate is used with serialization support.
If you do not need this feature you can disable the `backtrace` crate and
disable panic handling through the [`ProcConfig`](https://docs.rs/procspawn/latest/procspawn/struct.ProcConfig.html)
object.
## Feature Flags
The following feature flags exist:
* `safe-shared-libraries`: this feature is enabled by default. When this
feature is disable then no validation about shared library load status
is performed around IPC calls. This is highly unsafe if shared libraries
are being used and a function from a shared library is spawned.
* `backtrace`: this feature is enabled by default. When in use then
backtraces are captured with the `backtrace-rs` crate and serialized
across process boundaries.
* `test-support`: when this feature is enabled procspawn can be used
with rusttest. See [`testing`](https://docs.rs/procspawn/latest/procspawn/#testing) for more information.
* `json`: enables optional JSON serialization. For more information see
[Bincode Limitations](https://docs.rs/procspawn/latest/procspawn/#bincode-limitations).
## Bincode Limitations
This crate uses [`bincode`](https://github.com/servo/bincode) internally
for inter process communication. Bincode currently has some limitations
which make some serde features incompatible with it. Most notably if you
use `#[serde(flatten)]` data cannot be sent across the processes. To
work around this you can enable the `json` feature and wrap affected objects
in the [`Json`](serde/struct.Json.html) wrapper to force JSON serialization.
## Testing
Due to limitations of the rusttest testing system there are some
restrictions to how this crate operates. First of all you need to enable
the `test-support` feature for `procspawn` to work with rusttest at all.
Secondly your tests need to invoke the
[`enable_test_support!`](https://docs.rs/procspawn/latest/procspawn/macro.enable_test_support.html) macro once
top-level.
With this done the following behavior applies:
* Tests behave as if `procspawn::init` was called (that means with the
default arguments). Other configuration is not supported.
* procspawn will register a dummy test (named `procspawn_test_helper`)
which doesn't do anything when called directly, but acts as the spawning
helper for all `spawn` calls.
* stdout is silenced by default unless `--show-output` or `--nocapture`
is passed to tests.
* when trying to spawn with intercepted `stdout` be aware that there is
extra noise that will be emitted by rusttest.
```rust
procspawn::enable_test_support!();
#[test]
fn test_basic() {
let handle = procspawn::spawn((1, 2), |(a, b)| a + b);
let value = handle.join().unwrap();
assert_eq!(value, 3);
}
```
## Shared Libraries
`procspawn` uses the [`findshlibs`](https://github.com/gimli-rs/findshlibs)
crate to determine where a function is located in memory in both processes.
If a shared library is not loaded in the subprocess (because for instance it
is loaded at runtime) then the call will fail. Because this adds quite
some overhead over every call you can also disable the `safe-shared-libraries`
feature (which is on by default) in which case you are not allowed to
invoke functions from shared libraries and no validation is performed.
This in normal circumstances should be okay but you need to validate this.
Spawning processes will be disabled if the feature is not enabled until
you call the [`assert_spawn_is_safe`](https://docs.rs/procspawn/latest/procspawn/fn.assert_spawn_is_safe.html) function.
## Macros
Alternatively the [`spawn!`](https://docs.rs/procspawn/latest/procspawn/macro.spawn.html) macro can be used which can
make passing more than one argument easier:
```rust
let a = 42u32;
let b = 23u32;
let c = 1;