19.9 为何Ctrl-C未能产生SIGINT(2)
http://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 <stdio.h> #include <stdlib.h> #include <unistd.h> #include <termios.h> #include <signal.h>
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 );
$ ./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)手册页了解更多信息。