OpenBSD でデーモンを書いてて気づいたんですが、kqueue のファイルデスクリプタはプロセス間で共有できない、つまり、fork(2) で子プロセスに継承されたり SCM_RIGHTS で投げつけたりすることはできないんですね。

OpenBSD 5.2 の kqueue(2) man ページには

kqueue() creates a new kernel event queue and returns a descriptor. The queue is not inherited by a child created with fork(2). Similarly, kqueues cannot be passed across UNIX-domain sockets.

とあります。イベントがもらえてもファイルデスクリプタテーブルは別なので kqueue のファイルデスクリプタだけ持っててもしょうがないですね。

kqueue を直接使うのではなく libevent 経由で使っていたのですが、libevent が kqueue を使う環境で daemon(3) を呼ぶ前に event_base_new() を呼ぶとこの制限に引っかかって期待した動作をしなくなります。

FreeBSD ではどうかというと、OpenBSD と基本的には同じですが、rfork(2) という「fork() するけど子プロセスといくつかのリソースを共有する」システムコールがあって、それでファイルデスクリプタテーブルを共有するようにした場合は kqueue も共有されるようです。実際に挙動を確かめてはいません。

Linux には似た機構として epoll(2) がありますが、こっちは epoll のファイルデスクリプタ自体は共有することができるようです。ただし、「意味がない」と書かれています。

Q5
Can I send an epoll file descriptor over a Unix domain socket to another process?
A5
Yes, but it does not make sense to do this, since the receiving process would not have copies of the file descriptors in the epoll set.

というわけで、event_base_new() は daemon(3) の後に呼ぶ必要があるわけですが、プログラム内でいろいろと依存関係がありまして、さてどうしようかな。

# select や poll を使うように設定するというのはナシで

Trackback

no comment untill now

Add your comment now