procspawn/lib.rs
1//! This crate provides the ability to spawn processes with a function similar
2//! to `thread::spawn`.
3//!
4//! Unlike `thread::spawn` data cannot be passed by the use of closures. Instead
5//! if must be explicitly passed as serializable object (specifically it must be
6//! [`serde`](https://serde.rs/) serializable). The return value from the
7//! spawned closure also must be serializable and can then be retrieved from
8//! the returned join handle.
9//!
10//! If the spawned functiom causes a panic it will also be serialized across
11//! the process boundaries.
12//!
13//! # Example
14//!
15//! First for all of this to work you need to invoke `procspawn::init` at a
16//! point early in your program (somewhere at the beginning of the main function).
17//! Whatever happens before that point also happens in your spawned functions.
18//!
19//! Subprocesses are by default invoked with the same arguments and environment
20//! variables as the parent process.
21//!
22//! ```rust,no_run
23//! procspawn::init();
24//! ```
25//!
26//! Now you can start spawning functions:
27//!
28//! ```rust,no_run
29//! let data = vec![1, 2, 3, 4];
30//! let handle = procspawn::spawn(data, |data| {
31//! println!("Received data {:?}", &data);
32//! data.into_iter().sum::<i64>()
33//! });
34//! let result = handle.join().unwrap();
35//!```
36//!
37//! Because `procspawn` will invoke a subprocess and there is currently no
38//! reliable way to intercept `main` in Rust it's necessary for you to call
39//! [`procspawn::init`](fn.init.html) explicitly an early time in the program.
40//!
41//! Alternatively you can use the [`ProcConfig`](struct.ProcConfig.html)
42//! builder object to initialize the process which gives you some extra
43//! abilities to customize the processes spawned. This for instance lets you
44//! disable the default panic handling.
45//!
46//! [`spawn`](fn.spawn.html) can pass arbitrary serializable data, including
47//! IPC senders and receivers from the [`ipc-channel`](https://crates.io/crates/ipc-channel)
48//! crate, down to the new process.
49//!
50//! # Pools
51//!
52//! The default way to spawn processes will start and stop processes constantly.
53//! For more uses it's a better idea to spawn a [`Pool`](struct.Pool.html)
54//! which will keep processes around for reuse. Between calls the processes
55//! will stay around which also means the can keep state between calls if
56//! needed.
57//!
58//! # Panics
59//!
60//! By default panics are captured and serialized across process boundaries.
61//! This requires that the `backtrace` crate is used with serialization support.
62//! If you do not need this feature you can disable the `backtrace` crate and
63//! disable panic handling through the [`ProcConfig`](struct.ProcConfig.html)
64//! object.
65//!
66//! # Feature Flags
67//!
68//! The following feature flags exist:
69//!
70//! * `safe-shared-libraries`: this feature is enabled by default. When this
71//! feature is disable then no validation about shared library load status
72//! is performed around IPC calls. This is highly unsafe if shared libraries
73//! are being used and a function from a shared library is spawned.
74//! * `backtrace`: this feature is enabled by default. When in use then
75//! backtraces are captured with the `backtrace-rs` crate and serialized
76//! across process boundaries.
77//! * `test-support`: when this feature is enabled procspawn can be used
78//! with rusttest. See [`testing`](#testing) for more information.
79//! * `json`: enables optional JSON serialization. For more information see
80//! [Bincode Limitations](#bincode-limitations).
81//!
82//! # Bincode Limitations
83//!
84//! This crate uses [`bincode`](https://github.com/servo/bincode) internally
85//! for inter process communication. Bincode currently has some limitations
86//! which make some serde features incompatible with it. Most notably if you
87//! use `#[serde(flatten)]` data cannot be sent across the processes. To
88//! work around this you can enable the `json` feature and wrap affected objects
89//! in the [`Json`](serde/struct.Json.html) wrapper to force JSON serialization.
90//!
91//! # Testing
92//!
93//! Due to limitations of the rusttest testing system there are some
94//! restrictions to how this crate operates. First of all you need to enable
95//! the `test-support` feature for `procspawn` to work with rusttest at all.
96//! Secondly your tests need to invoke the
97//! [`enable_test_support!`](macro.enable_test_support.html) macro once
98//! top-level.
99//!
100//! With this done the following behavior applies:
101//!
102//! * Tests behave as if `procspawn::init` was called (that means with the
103//! default arguments). Other configuration is not supported.
104//! * procspawn will register a dummy test (named `procspawn_test_helper`)
105//! which doesn't do anything when called directly, but acts as the spawning
106//! helper for all `spawn` calls.
107//! * stdout is silenced by default unless `--show-output` or `--nocapture`
108//! is passed to tests.
109//! * when trying to spawn with intercepted `stdout` be aware that there is
110//! extra noise that will be emitted by rusttest.
111//!
112//! ```rust,no_run
113//! procspawn::enable_test_support!();
114//!
115//! #[test]
116//! fn test_basic() {
117//! let handle = procspawn::spawn((1, 2), |(a, b)| a + b);
118//! let value = handle.join().unwrap();
119//! assert_eq!(value, 3);
120//! }
121//! ```
122//!
123//! # Shared Libraries
124//!
125//! `procspawn` uses the [`findshlibs`](https://github.com/gimli-rs/findshlibs)
126//! crate to determine where a function is located in memory in both processes.
127//! If a shared library is not loaded in the subprocess (because for instance it
128//! is loaded at runtime) then the call will fail. Because this adds quite
129//! some overhead over every call you can also disable the `safe-shared-libraries`
130//! feature (which is on by default) in which case you are not allowed to
131//! invoke functions from shared libraries and no validation is performed.
132//!
133//! This in normal circumstances should be okay but you need to validate this.
134//! Spawning processes will be disabled if the feature is not enabled until
135//! you call the [`assert_spawn_is_safe`](fn.assert_spawn_is_safe.html) function.
136//!
137//! # Macros
138//!
139//! Alternatively the [`spawn!`](macro.spawn.html) macro can be used which can
140//! make passing more than one argument easier:
141//!
142//! ```rust,no_run
143//! let a = 42u32;
144//! let b = 23u32;
145//! let c = 1;
146//! let handle = procspawn::spawn!((a => base, b, mut c) || -> Result<_, ()> {
147//! c += 1;
148//! Ok(base + b + c)
149//! });
150//! ```
151//!
152//! # Platform Support
153//!
154//! Currently this crate only supports macOS and Linux because ipc-channel
155//! itself does not support Windows yet. Additionally the findshlibs which is
156//! used for the `safe-shared-libraries` feature also does not yet support
157//! Windows.
158//!
159//! # More Examples
160//!
161//! Here are some examples of `procspawn` in action:
162//!
163//! * [simple.rs](https://github.com/mitsuhiko/procspawn/blob/master/examples/simple.rs):
164//! a very simple example showing the basics.
165//! * [args.rs](https://github.com/mitsuhiko/procspawn/blob/master/examples/args.rs):
166//! shows how arguments are available to the subprocess as well.
167//! * [timeout.rs](https://github.com/mitsuhiko/procspawn/blob/master/examples/timeout.rs):
168//! shows how you can wait on a process with timeouts.
169//! * [bad-serialization.rs](https://github.com/mitsuhiko/procspawn/blob/master/examples/bad-serialization.rs):
170//! shows JSON based workarounds for bincode limitations.
171//! * [macro.rs](https://github.com/mitsuhiko/procspawn/blob/master/examples/macro.rs):
172//! demonstrates macro usage.
173//!
174//! More examples can be found in the example folder: [examples](https://github.com/mitsuhiko/procspawn/tree/master/examples)
175
176#[macro_use]
177mod proc;
178
179mod core;
180mod error;
181mod panic;
182mod pool;
183
184#[cfg(feature = "json")]
185mod json;
186
187#[doc(hidden)]
188pub mod testsupport;
189
190pub mod serde;
191
192mod macros;
193
194pub use self::core::{assert_spawn_is_safe, init, ProcConfig};
195pub use self::error::{Location, PanicInfo, SpawnError};
196pub use self::pool::{Pool, PoolBuilder};
197pub use self::proc::{spawn, Builder, JoinHandle};
198
199#[cfg(feature = "async")]
200pub use self::asyncsupport::{spawn_async, AsyncJoinHandle};