= Haskellでのシグナルハンドリング = System.Posix.Signalsに必要なものがある. unixのシグナル処理apiの単純なラッパのようだ. == シグナルをキャッチして終了処理を行う == すこしハマったのでメモ. Ctrl-CでCursesの終了処理を実行させたかった. http://stackoverflow.com/questions/13441676/how-to-write-ctrl-c-handler-in-haskell installHandlerで登録されたシグナルハンドラは別スレッドで実行される. そんでもってghcではプログラムの終了を行えるのはメインスレッドのみ. というわけで普通に終了処理書いてもうまく動かない. 上のリンクではhandler内部でkillThread関数にメインスレッドのスレッドIDを渡している. こんなコードを書いた {{{ initialize :: IO () initialize = do mainThreadId <- myThreadId installHandler sigINT (Catch (teardown>>killThread mainThreadId)) Nothing installHandler sigTERM (Catch (teardown>>killThread mainThreadId)) Nothing initCurses keypad stdScr True echo False -- noecho teardown :: IO () teardown = endWin main = do initialize handle handler mainloop where handler :: AsyncException -> IO () -- data AsyncException = ThreadKilled | ... handler e = exitSuccess }}} ただこれメインスレッドに例外投げてるだけなので自作の例外か,(もしあるなら)ダミーの何も表さない例外を使うほうがいい気がする. そしてAsyncExceptionのデータコンストラクタにUserInterruptとかいうそのものずばりなのがあった. というわけで書き直した {{{ initialize :: IO () initialize = do initCurses keypad stdScr True echo False -- noecho teardown :: IO () teardown = endWin main = do initialize handle handler mainloop where handler :: AsyncException -> IO () -- data AsyncException = ThreadKilled | UserInterrupt | ... handler e = teardown >> exitSuccess }}} 動いた. シグナルハンドラ自分で設定する必要なかった.