この記事はRustその2 Advent Calendar 2017 17日目の記事です。
本記事ではUnix系システムプログラミングを行うのに便利なnix crateについて簡単にご紹介できればと思います。
nix crateとは
nix crateはいわゆるラッパーです。
RustにはC言語の型を定義したlibc crateがあり、このcrateを利用すればfork、execv、cloneなどのC言語でおなじみの関数を扱えます。
しかしこのlibc crateの関数の多くはunsafeとなっており、コンパイル時に安全であることを保証できないコードを書けるようになる為、取り扱いには注意が必要となってしまいます。
nix crateはこのlibc crateのunsafeな部分をラップしたunsafeでないAPIを提供しているので、libc crateの機能をより安全に利用できます。
使用例
nix crateを使用してcloneを実行する例は下記のようになります。
まずCargo.tomlに依存関係を記述します。
[dependencies]
nix = "0.9.0"
次にソース上でnix crateを利用することを宣言し、cloneが実装されているschedモジュールをインポートします。
(下記ではschedモジュールの中身をすべてインポートしています。)
extern crate nix;
use nix::sched::*;
後は、インポートしたschedモジュールを利用してcloneを実行する記述を書くだけです。
(プロセスの情報を出力させるのにpentry crateを利用しています。)
extern crate nix;
extern crate pentry;
use nix::sched::*;
// プロセス情報出力処理
fn print_process_info() {
if let Ok(ps) = pentry::current() {
println!("{:?}", ps);
}
}
// cloneしたプロセスで実行する処理
fn child() -> isize {
// プロセス情報出力
print_process_info();
// 成功時は0を返す
0
}
fn main() {
// プロセス情報出力
print_process_info();
// stackのサイズ
const STACK_SIZE: usize = 1024 * 1024;
let ref mut stack: [u8; STACK_SIZE] = [0; STACK_SIZE];
// cloneで実行する処理
let cb = Box::new(|| child());
// clone時に指定するフラグ(今回はフラグは指定しない)
let clone_flags = CloneFlags::empty();
// clone
let p = clone(cb, stack, clone_flags, None);
let p = match p {
Ok(p) => p,
Err(err) => panic!(err),
}
}
Process { pid: 2163, ppid: 1992, name: "clone", path: Some("/home/ubuntu/Rust/sample/target/debug/sample") }
Process { pid: 2180, ppid: 2163, name: "clone", path: Some("/home/ubuntu/Rust/sample/target/debug/sample") }
実行すると環境により出力結果は異なりますが、cloneした子プロセスの親プロセスIDppidが、親のプロセスIDpidとなっているはずです。
まとめ
nix crateを利用してlibc crateの関数を利用することができました。
unsafeでない分nix crateを利用するとより安全になるのかと思います。