19.9 为何Ctrl-C未能产生SIGINT(2) https://scz.617.cn/unix/200904231116.txt Q: plank@SMTH 2009-04-22 02:02 一个前台进程,从stdin输入,但这个进程不响应Ctrl-C。查看了termios结构的c_cc [VINTR],等于3,正常。程序里没有安装SIGINT信号处理函数。如果从另一个终端上 "kill -2 ",可以杀掉该进程。这说明之前按Ctrl-C并未将SIGINT投递到该进 程。为什么? A: scz@nsfocus 2009-04-23 11:16 至少有一种可能,c_lflag的ISIG被复位了,此时Ctrl-C不会产生SIGINT信号。下面 这个Disable_Ctrl_C.c演示了这种效果。 -------------------------------------------------------------------------- /* * For x86/Linux Kernel 2.6.18-4 * gcc-3.3 -Wall -pipe -O3 -o Disable_Ctrl_C Disable_Ctrl_C.c */ #include #include #include #include #include static struct termios original_term; /* * for signal handlers */ typedef void Sigfunc ( int ); static void Atexit ( void ( *func ) ( void ) ) { if ( 0 != atexit( func ) ) { /* * perror( "atexit error" ); */ exit( EXIT_FAILURE ); } return; } /* end of Atexit */ static void on_sigint ( int signo ) { /* * 演示用,不推荐在信号处理函数中使用fprintf() */ fprintf( stderr, "\nsigno = %d\n", signo ); /* * 这次我们使用atexit()函数 */ exit( EXIT_SUCCESS ); } /* end of on_sigint */ static Sigfunc * PrivateSignal ( int signo, Sigfunc *func ) { struct sigaction act, oact; act.sa_handler = func; sigemptyset( &act.sa_mask ); act.sa_flags = 0; if ( signo == SIGALRM ) { #ifdef SA_INTERRUPT /* * SunOS 4.x */ act.sa_flags |= SA_INTERRUPT; #endif } else { #ifdef SA_RESTART /* * SVR4, 4.4BSD */ act.sa_flags |= SA_RESTART; #endif } if ( sigaction( signo, &act, &oact ) < 0 ) { return( SIG_ERR ); } return( oact.sa_handler ); } /* end of PrivateSignal */ static Sigfunc * Signal ( int signo, Sigfunc *func ) { Sigfunc *sigfunc; if ( SIG_ERR == ( sigfunc = PrivateSignal( signo, func ) ) ) { perror( "signal" ); exit( EXIT_FAILURE ); } return( sigfunc ); } /* end of Signal */ static void terminate ( void ) { /* * 恢复原始终端属性 */ tcsetattr( STDIN_FILENO, TCSANOW, &original_term ); _exit( EXIT_SUCCESS ); } /* end of terminate */ int main ( int argc, char * argv[] ) { int ret = EXIT_FAILURE; struct termios current_term; if ( isatty( STDIN_FILENO ) == 0 ) { fprintf( stderr, "standard input is not a terminal device\n" ); goto main_exit; } /* * 保存原始终端属性 */ if ( tcgetattr( STDIN_FILENO, &original_term ) < 0 ) { perror( "tcgetattr( STDIN_FILENO, ... ) failed" ); goto main_exit; } /* * 安装一些回调函数 */ Atexit( terminate ); Signal( SIGINT, on_sigint ); current_term = original_term; /* * When any of the characters INTR, QUIT, SUSP, or DSUSP are received, * generate the corresponding signal. */ current_term.c_lflag &= ~ISIG; /* * 也可以直接调用cfmakeraw(),这包括将ISIG复位的操作。 * * cfmakeraw( ¤t_term ); */ if ( tcsetattr( STDIN_FILENO, TCSANOW, ¤t_term ) < 0 ) { perror( "tcsetattr( STDIN_FILENO, TCSANOW, ... ) failed" ); goto main_exit; } /* * 产生阻塞 */ getchar(); ret = EXIT_SUCCESS; printf( "ok\n" ); main_exit: return( ret ); } /* end of main */ -------------------------------------------------------------------------- $ ./Disable_Ctrl_C ^C^C^C // getchar()产生阻塞,在此狂按Ctrl-C,没反应 signo = 2 // 从另一个终端上"kill -2 ",on_sigint()被执行 $ 从另一个终端上执行如下命令投递SIGINT信号: $ kill -INT `ps auwx | grep Disable_Ctrl_C | grep -v grep | awk '{print $2;}'` 参看termios(3)手册页了解更多信息。