分类:
2008-12-08 12:17:15
10.17 abort function
ISO C说,abort函数会调用raise()来对本进程发送一个SIGABRT信号。
我们可以捕捉该信号,来做一些操作,然后退出。
不同的实现,有不同的abort函数,例如,有的实现中,abort函数发送的是SIGILL信号,会导致进程terminate并且coredump,从而abort函数不会返回。有的实现中,abort函数会发送SIGIOT信号,并且abort函数会返回。
不同的abort实现,对standard i/o stream的处理也不一样,有的实现会flush标准输出流,有的不会。一个比较好的作法是在我们调用abort函数之前,自己去flush。
如下有一个posix.1 abort函数的实现,它可以保证,不管你的外界调用者对SIGABRT信号是如何设置的,一般情况下,都会将standard i/o streams 给flush掉。当然有个例外(下面会讲述):
#include
#include
#include
#include
void
abort(void) /* POSIX-style
abort() function */
{
sigset_t mask;
struct sigaction action;
/*
* Caller can't ignore SIGABRT,
if so reset to default.
*/
sigaction(SIGABRT, NULL,
&action);
if (action.sa_handler ==
SIG_IGN) {
action.sa_handler = SIG_DFL;
sigaction(SIGABRT, &action,
NULL);
}
if (action.sa_handler ==
SIG_DFL)
fflush(NULL); /* flush all open stdio streams */
/*
* Caller can't block SIGABRT;
make sure it's unblocked.
*/
sigfillset(&mask);
sigdelset(&mask, SIGABRT); /* mask has only SIGABRT turned off */
sigprocmask(SIG_SETMASK,
&mask, NULL);
kill(getpid(), SIGABRT); /* send the signal */
/*
* If we're here, process caught
SIGABRT and returned.
*/
fflush(NULL); /* flush all open stdio streams
*/
action.sa_handler = SIG_DFL;
sigaction(SIGABRT, &action,
NULL); /* reset to default */
sigprocmask(SIG_SETMASK,
&mask, NULL); /* just in case ... */
kill(getpid(), SIGABRT); /* and one more time */
exit(1); /* this should never be executed ... */
}
1.如果外界对SIGABRT是SIG_IGN,那么在abort函数里,将其改成了SIG_DFL
2.然后调用了fflush,这说明如果外界对SIGABRT是SIG_IGN或者SIG_DFL,abort函数就会给我们调用fflush.
3. 接下来,我们block所有的信号,除了SIGABRT,然后发送SIGABRT给自己。
4.我们知道如果kill发信号给自己,且信号没有被block,那么handler会再kill返回之前调用。
5.如果此时SIGABRT的处理是SIG_DFL,那么进程就结束了,kill 不会返回,如果SIGABRT被我们catch, 那么handler会被调用,且如果handler没有调用exit()之类的函数,那么handler结束后,kill返回,如果handler调用了exit(),那么exit()会将stream flush,然后关闭,退出。如果handler调用了_exit()那么stream就不会被flush,也不会被关闭,退出的时候file descriptor会被关闭,此时stream的数据丢掉了。
6.如果kill返回了,说明handler执行完了并且也没有调用exit类函数。好,我们将SIGABRT的处理设置为SIG_DFL,然后发该信号,就会被终止了。