SIGPIPE

最近はエントリ毎にDocumentIDを入れている。DocumentIDとは何かという説明は以下のページを参照してもらいたい。
http://cr.yp.to/bib/documentid.html
DocumentIDの生成方法としてこのようなコマンドの組合せが示されている。

head /dev/urandom | md5sum

windowsではこのままコンソールに入力しても使えない。headやmd5sumはwindows版もあるので、それを導入すれば良い。だが、乱数生成器はどうするべきか。無限に乱数を生成する以下のようなコードを書いてみた。

// randstream.c
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
#include <fcntl.h>

void DispRandom()
{
  HCRYPTPROV hProv;
  BYTE buf[100];
  
  setmode(_fileno(stdout), O_BINARY);
  CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0);

  for(;;) {
    CryptGenRandom(hProv, 100, buf);
    for(int i=0; i<100; i++) {
      putc(buf[i], stdout);
    }
  }

  CryptReleaseContext(hProv, 0);
}

int main(void) {
  DispRandom();
}

使ってみよう。

randstream |head |md5sum

簡単に予想できることだが、終了しない。randstreamは無限に乱数を生成し続けるプログラムであるので当然のことではある。しかし、Unix系OSならば出力しようとしたときにパイプの接続先が終了していればSIGPIPEシグナルが投げられる。そしてデフォルトではSIGPIPEを受けとるとそのままプロセス自体が終了する。
WindowsにはSIGPIPEシグナルがない。適当な規約をでっちあげて互いに協調させることもできなくはないが、既存のツールと組み合わせたいときにどうしようもない。できるだけ汎用的な形でSIGPIPEと同等のことが出来ないだろうか?パイプの接続先プロセスのプロセスIDを取得する方法があれば、終了イベントを捕捉できるのだが、その方法がわからない。
実際に使っているプログラムでは単に生成する乱数の数を予め決めてあるので実用上の問題は無い。しかし、解らないままで済ませたくはない類の問題だと思う。
Document ID: 40e1c738ef2011a7f60f69b7f06701ab