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
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
从另一个终端上执行如下命令投递SIGINT信号:
$ kill -INT ps auwx | grep Disable_Ctrl_C | grep -v grep | awk '{print $2;}'
参看termios(3)手册页了解更多信息。