Python を daemon 化してくれる関数が、標準ライブラリで見つからなかった。
探せばいくらでも有るんだろうけれど、面倒なので Ruby の Process.daemon を真似て作ってみた。
といっても、Ruby 1.9 の lib ディレクトリを見ても、Process.rb というファイルは見つからない。
おそらく C で書かれてコンパイルしていると想像される。
(本当かどうかは知らない)
さすがに Ruby インタープリタのソースを読むのは手間がかかるので、
引数の仕様だけを真似てやってみた。
ちなみに、Python ならではの hack として、
「ライブラリの中で exit したい時は、"sys.exit" ではなく "os._exit" を使う」
という事を最近しったので、ついでにメモしておく。
実は、sys.exit は、実際には例外を投げているだけ。
Python のインタープリタがその例外をキャッチして、各種 buffer の処理などを
よろしくやった上で終了してくれる。
要は、面倒な後処理を Python に任せて安全に(?)終了してくれるのだ。
しかし、ライブラリでこの関数を使用する事は危険だ。
何も知らないプログラマが、上流でこの例外をキャッチしてしまうかもしれない。
sys.exit では本当にプログラムが終了する事は保証できないし、
その他どんな副作用が発生するか予想できない。
そのため、上流行程に関係なく問答無用でプログラムを終了したい場合は
os._exit を使用するらしい。
まあ、ライブラリの中から exit する事なんて多く無いと思うが。
そんな訳で、作成した関数が以下。
いい加減な作りだが、一応動作する。
2011/1/2 Typo 発見。直す
探せばいくらでも有るんだろうけれど、面倒なので Ruby の Process.daemon を真似て作ってみた。
といっても、Ruby 1.9 の lib ディレクトリを見ても、Process.rb というファイルは見つからない。
おそらく C で書かれてコンパイルしていると想像される。
(本当かどうかは知らない)
さすがに Ruby インタープリタのソースを読むのは手間がかかるので、
引数の仕様だけを真似てやってみた。
ちなみに、Python ならではの hack として、
「ライブラリの中で exit したい時は、"sys.exit" ではなく "os._exit" を使う」
という事を最近しったので、ついでにメモしておく。
実は、sys.exit は、実際には例外を投げているだけ。
Python のインタープリタがその例外をキャッチして、各種 buffer の処理などを
よろしくやった上で終了してくれる。
要は、面倒な後処理を Python に任せて安全に(?)終了してくれるのだ。
しかし、ライブラリでこの関数を使用する事は危険だ。
何も知らないプログラマが、上流でこの例外をキャッチしてしまうかもしれない。
sys.exit では本当にプログラムが終了する事は保証できないし、
その他どんな副作用が発生するか予想できない。
そのため、上流行程に関係なく問答無用でプログラムを終了したい場合は
os._exit を使用するらしい。
まあ、ライブラリの中から exit する事なんて多く無いと思うが。
そんな訳で、作成した関数が以下。
いい加減な作りだが、一応動作する。
def daemon(nochdir=False, noclose=False):
r''' Fork twice and become a daemon.
@param nodir
The daemon process does not change the root directory to '/' if True.
The default is False.
@param noclose
Does not close the stdin, stdout, stderr if True.
The default is True.
'''
## 1st fork
pid = os.fork()
if pid != 0:
os.waitpid(pid, os.P_WAIT)
os._exit(0)
## 2nd fork
os.setsid()
pid = os.fork()
if pid != 0:
os._exit(0)
## daemon process
# ch '/'
if not nochdir:
os.chdir('/')
# close stdin, stdout, stderr
if not noclose:
try:
os.close(0)
except OSError:
pass
else:
os.open(os.devnull, os.O_WRONLY)
for fd in [1, 2]:
try:
os.close(fd)
except OSError:
pass
else:
os.open(os.devnull, os.O_RDONLY)
return
2011/1/2 Typo 発見。直す