linux application > signal > SA_RESTARTの使いどころ

[code]

    struct sigaction sa;
    sa.sa_flags = SA_RESTART;
    
[/code]

というように、シグナルのフラグとしてSA_RESTARTというのがあります。

私の理解では、「SA_RESTARTを設定している場合、recv()などの実行文においてシグナルを受けてもrecv()から抜け出さず、受けたシグナルの処理する」という理解です。

実際のソフトを作る場合、SA_RESTARTは設定する/しない、どちらでよく使われるものでしょうか?

SA_RESTARTを設定していると、意図しないrecv()からの抜け出しがなくなりよさそうに思うのですが、そうなのでしょうか？




シグナルがハンドラにより処理された **後** に、recv()などのシステムコールからEINTRで抜けるか、自動的に再試行するかを決めるフラグですね。

使うかどうかは目的によるとしか言えないと思います。使わない場合、システムコールがエラーを返したらerrnoがEINTRかどうかを調べて、そうなら再試行する、というコードを自分で書くことになります。私はある程度の規模ならそのパターンをマクロなどで隠蔽してしまいますが、そのへんはプロジェクトのポリシーに依存するでしょう。

ただ、自動的再試行が起きるかどうかには色々条件があります。どのシステムコールか、またどのデバイスに対して読み書きしているかにも影響されます。詳しくは[signal(7)](http://man7.org/linux/man-
pages/man7/signal.7.html)を参照。  
さらに、既にある程度のデータが読み書きされていた場合はSA_RESTARTがあっても再試行はされずシステムコールは成功を返します。

また、昔ひっかかったことがあるのですが、sleep系コール(sleep, nanosleep,
usleep等)も自動再起動されません。ここで10秒休んでるはず、と思ってるのが頻繁にシグナルを受けてて実は全然休んでいなかった、なんてことがありました。

従って、「確実にnバイト書き込みたい/読み出したい」とか「確実にn秒ウェイトしたい」といった場合はSA_RESTARTを使おうが使うまいが返り値を調べてループすることになるので、使い勝手はそれほど良くない機能だな、というのが個人的な印象です。




シグナルがハンドラにより処理された **後** に、recv()などのシステムコールからEINTRで抜けるか、自動的に再試行するかを決めるフラグですね。

使うかどうかは目的によるとしか言えないと思います。使わない場合、システムコールがエラーを返したらerrnoがEINTRかどうかを調べて、そうなら再試行する、というコードを自分で書くことになります。私はある程度の規模ならそのパターンをマクロなどで隠蔽してしまいますが、そのへんはプロジェクトのポリシーに依存するでしょう。

ただ、自動的再試行が起きるかどうかには色々条件があります。どのシステムコールか、またどのデバイスに対して読み書きしているかにも影響されます。詳しくは[signal(7)](http://man7.org/linux/man-
pages/man7/signal.7.html)を参照。  
さらに、既にある程度のデータが読み書きされていた場合はSA_RESTARTがあっても再試行はされずシステムコールは成功を返します。

また、昔ひっかかったことがあるのですが、sleep系コール(sleep, nanosleep,
usleep等)も自動再起動されません。ここで10秒休んでるはず、と思ってるのが頻繁にシグナルを受けてて実は全然休んでいなかった、なんてことがありました。

従って、「確実にnバイト書き込みたい/読み出したい」とか「確実にn秒ウェイトしたい」といった場合はSA_RESTARTを使おうが使うまいが返り値を調べてループすることになるので、使い勝手はそれほど良くない機能だな、というのが個人的な印象です。

