Skip to content

Latest commit

 

History

History
177 lines (154 loc) · 4.33 KB

200904231116.txt.md

File metadata and controls

177 lines (154 loc) · 4.33 KB

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( &current_term );
 */
if ( tcsetattr( STDIN_FILENO, TCSANOW, &current_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)手册页了解更多信息。