ディスクリプタ値はなぜ1からにしてくれなかったのだろう・・・
UNIX系OSでは、ファイル・ソケットなどを扱う際に、ディスクリプタという識別子を使います。open()、socket()、accept()などの戻り値はディスクリプタです。これらのシステムコールはエラーの場合に-1を戻します。ディスクリプタはゼロ以上の値を使います。ちなみに、ゼロのディスクリプタ値は標準入力がデフォルトで割り当てられています。
ポインタを返すような関数は、大抵エラーの場合にNULLポインターを返します。NULLポインターは値としてはゼロです。
この違いがプログラミングをしていると結構微妙で、NULLの特性を活かして、大抵の場合、初期値は全てゼロクリアーしておくと便利な場合が多いのですが、ディスクリプタはゼロはディスクリプタとして正常な値のため、ゼロクリアーでは判断できないのです。
昨晩から、ディスクリプタにゼロが登場する問題で頭を悩ませていました。ゼロの時になぜか動きがおかしくなることが多いのです。原因は・・・別スレッドの処理で、ファイルをオープンしていないときにゼロの値で初期化している場所があり、ゼロをclose()してしまっていたのでした。初回は標準入力がクローズされ、ゼロが空くので、他のディスクリプタを得る処理でゼロが使われるのですが、それをclose()する処理が別スレッドで定期的に動いていたのでした。
他のデータと一緒にディスクリプタを保持している構造体を、まとめてmemset()でゼロクリアーしていたのが原因だったのですが、こういう問題は気がつくのが難しいものです。さらに、このプログラムはスレッド数が2万個を超えるので、デバッグも大変だったのでした。
どうにも原因がわからなかったので、open(),close()などを全てラッピングし、ゼロならセグメンテーションフォルトを発生させて異常終了するようにして、いつおかしくなるのかを調べてようやくわかったのでした。
しまいには、「OSがバグっている!」とか考えたりしたのですが、結局は自分のソースが問題だったという感じでした。。
ディスクリプタ値はなぜ1からにしなかったのですかねぇ・・・。ポインタと同じようにゼロは特殊な状態にしれくれればまとめて初期化とかがしやすかったのに。。