2012-05-23 14 views
8

次のプログラムでは、_XOPEN_SOURCE行のコメントを外すと、C-cになるとプログラムが終了し、同じプログラムが終了しません。その行にコメントしないと、プログラムは終了します。誰でも、どのようにして_XOPEN_SOURCEが信号処理に影響するのか知っていますか?私はgcc(4.6.3)とglibc(2.15)を使ってLinux上にいる。信号処理機能のインストール時にXOPEN_SOURCEと信号処理

/* #define _XOPEN_SOURCE 700 */ 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <signal.h> 

typedef void (*sighandler_t)(int); 

void handle_signal(int signo) 
{ 
    printf("\n[MY_SHELL] "); 
    fflush(stdout); 
} 

int main() 
{ 
    int c; 
    signal(SIGINT, SIG_IGN); 
    signal(SIGINT, handle_signal); 
    printf("[MY_SHELL] "); 
    while ((c = getchar()) != EOF) { 
     if (c == '\n') 
      printf("[MY_SHELL] "); 
    } 
    printf("\n"); 
    return 0; 
} 
+0

脇に、 'char c':いいえ、いいえ、いいえ、いいえ、いいえ。 'EOF'はアウトオブバンドである必要があります。それで 'getchar'が' int'を返すのです。 – Dave

+0

@Daveあなたは正しいです。それは実際に私がインターネット上で見つけた例でした。私はそれに気付かなかった。それを今修正する。 – yasar

答えて

4

問題はsignal()機能は動作の2つの異なる形式を持つことができるということです。

  • System Vのセマンティクス、シグナルハンドラは、「ワンショット」である - こと信号処理機能が呼び出された後、信号の配置がSIG_DFLにリセットされ、信号によって中断されたシステムコールは再開されません。または
  • シグナルハンドラがではなく、シグナルが発生するとリセットされ、シグナルハンドラが実行されている間はシグナルがブロックされ、中断されたシステムコールが自動的に再開されます。そうでない場合はglibcとLinuxの

、あなたは_BSD_SOURCEが定義されている場合はBSDのセマンティクス、およびSystem Vセマンティクスを取得します。 _BSD_SOURCEマクロはデフォルトで定義されていますが、_XOPEN_SOURCE(または_POSIX_SOURCE_SVID_SOURCEのような他のマクロも同様)を定義すると、このデフォルトの定義は非表示になります。 getchar()の基礎となるread()システムコールがSIGINTによって中断された場合

の下のSystem Vセマンティクスは、その後、getchar()EINTRからerrnoセット(これはあなたのプログラムが正常に終了させます)とEOFを返します。さらに、最初のSIGINTの後、この信号の処理はデフォルトにリセットされ、SIGINTのデフォルトアクションはプロセスを終了することです(プログラムが最初のSIGINTを生き延びたとしても、2番目のプロセスは異常終了します)。

信号処理機能のインストールには、signal()をまったく使用しないでください。代わりに、sigaction()を使用する必要があります。これは移植性があり、どこでも同じセマンティクスを提供します。 sa_flagsSA_RESTARTに設定すると、sigaction()というBSDセマンティクスが得られます。

+0

しかし、どのような場合でも、C-cが最初に押されたとき(ハンドラがすでに設定されている)にプログラムが終了しないことに注意してください。 –

+0

これはここで起こっていることではありません。 '_XOPEN_SOURCE 700'セマンティクスは' SA_RESTART'が不足しているため、 'EINTR'が発生し、getcharに' EOF'が返されてプログラムが終了します。私の答えを見てください。 – Dave

+0

@Dave:あなたはかなり正しいです、私はsyscallの再起動情報でこの答えを更新しました。 – caf

1

(straceので示すように)sigprocmask()は通常、1つの呼び出しコメントアウト一方_XOPEN_SOURCE 700定義コールでsignal()

rt_sigaction(SIGINT, {SIG_IGN, [], SA_INTERRUPT|SA_NODEFER|SA_RESETHAND}, {SIG_DFL, [], 0}, 8) = 0 
rt_sigaction(SIGINT, {0x80484dc, [], SA_INTERRUPT|SA_NODEFER|SA_RESETHAND}, {SIG_IGN, [], SA_INTERRUPT|SA_NODEFER|SA_RESETHAND}, 8) = 0 

のバージョンが好ましい理由これらの微妙behavorial違いは次のとおり

rt_sigaction(SIGINT, {SIG_IGN, [INT], SA_RESTART}, {SIG_DFL, [], 0}, 8) = 0 
rt_sigaction(SIGINT, {0x80484dc, [INT], SA_RESTART}, {SIG_IGN, [INT], SA_RESTART}, 8) = 0 

_XOPEN_SOURCEに欠けている重要な余分なフラグはSA_RESTARTで、readシステムコールがシグナルが発生しなかったかのように継続することができます。それがなければ、システムコールはエラーを示します。getchar()-1を返します(しかし、真のEOFではなく失敗を示します)。プログラムが終了します。

関連する問題