码迷,mamicode.com
首页 > 其他好文 > 详细

10.17 abort函数

时间:2016-05-26 08:40:24      阅读:183      评论:0      收藏:0      [点我收藏+]

标签:


我们早些时候提到函数abort能够造成程序的非正常终止。

  1. #include <stdlib.h>
  2. void abort(void);
  3. This function never returns.

该函数会发送一个信号SIGABRT到调用进程。(进程不应该忽略这一信号),ISO C指出调用函数abort将会通过调用函数raise(SIGABRT)向主机环境发送一个不成功的终止通知。(ISO C states that calling abort will deliver an successful termination notification to the host environment by calling raise(SIGABRT)).
ISO C要求如果信号SIGABRT被捕获并且信号处理函数返回,abort仍然不会返回到其调用进程。如果该信号被捕获,如果该信号被捕获,信号处理函数不返回的唯一的方法是调用函数exit,_exit,_Exit,longjmp,siglongjmp.POSIX.1也指出abort将会重写信号的阻塞或者是忽略处理。
让进程捕获信号SIGABRT的目的是允许进程在终止之前执行清理工作,如果进程在信号处理函数中不终止自身进程,那么当信号处理函数返回的时候,abort将会终止进程。
ISO C将输出流是否被清空以及临时文件是否被删除交给了实现来处理,POSIX.1对此作了改变,其允许实现调用函数fclose在进程终止之前关闭已经打开的标准IO流。

早期的System V版本在abort函数中产生SIGIOT信号,进程可以捕获或者忽略该信号,并且可以从信号处理函数中返回,在这种情况下abort将会返回到其调用进程中去。
4.3BSD产生SIGILL信号,在发出信号之前,4.3BSD解除了该信号的阻塞并将其处理修改为SIG_DFL(终止并保存core文件)。这可以防止进程忽略或者是捕获该信号。
历史上,abort函数的实现对于标准IO流的处理在不同实现上有差异,为了提升程序的防御能力以及改善其可移植性,如果我们想要标准IO流被清空,我们需要在调用函数abort之前执行,我们将在err_dump函数中实现这一处理。
因为很多UNIX系统的函数tmpfile的实现在创建文件之后会立即调用unlink函数,ISO C对于临时文件的提醒我们并不需要担心。

Example

图10.25展示了POSIX.1指定的abort函数的一个实现:

  1. #include <signal.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. void abort(void) /*POSIX-style abort() function */
  6. {
  7. sigset_t mask;
  8. struct sigaction action;
  9. /*Caller can‘t ignore SIGABRT, if so reset to defualt */
  10. sigaction(SIGABRT, NULL, &action);
  11. if(action.sa_handler == SIG_IGN)
  12. {
  13. action.sa_handler = SIG_DFL;
  14. sigaction(SIGABRT, &action, NULL);
  15. }
  16. if(action.sa_handler == SIG_DFL)
  17. {
  18. fflush(NULL); /* flush all open stdio streams */
  19. }
  20. /* Caller can‘t block SIGABRT; make sure it‘s unblocked. */
  21. sigfillset(&mask);
  22. sigdelset(&mask, SIGABRT); /*mask has only SIGABRT turned off .*/
  23. sigprocmask(SIG_SETMASK, &mask, NULL);
  24. kill(getpid(), SIGABRT); /*send the signal*/
  25. /*If we‘re here,process caught SIGABRT and returned */
  26. fflush(NULL); /*flush all open stdio streams.*/
  27. action.sa_handler = SIG_DFL;
  28. sigaction(SIGABRT, &action, NULL); /*reset to default*/
  29. sigprocmask(SIG_SETMASK, &mask, NULL); /*just in case ... */
  30. kill(getpid(), SIGABRT); /*and one more time*/
  31. exit(1); /*this should never be excuted*/
  32. }

Figure 10.25 POSIX.1的abort函数的实现

首先检查信号是不是默认处理函数,如果是的话就flush所有IO流,注意这与fclose不同,因为fflush只是flush文件流但是并不关闭它们,当进程终止的时候,系统会关闭所有已经打开的文件。如果进程捕获到信号并且返回到abort函数中来,我们需要再一次flush文件流,因为进程可能再次产生了更多的输出内容,我们不需要处理的确情况是:进程捕获到信号以后调用了函数_exit或者是_Exit.在这种情况下,内存中所有没有flush的缓冲区将会被丢弃,我们假设这样做的用户是不想要缓冲区中的内容被flush的。
在10.9中我们已经了解到kill函数会产生信号,并且如果信号没有被阻塞(图10.25中的程序我们可以保证没有被阻塞),那么信号将在kill函数返回之前被发送到进程,因为我们阻塞了所有的信号除了SIGABRT,因此我们知道如果kill调用返回到abort,那么进程就已经捕获到了信号并且信号处理函数已经返回了。





10.17 abort函数

标签:

原文地址:http://www.cnblogs.com/U201013687/p/5529552.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!