首页 > 编程 > .NET > 正文

C标准库源码解剖(9):控制函数assert.h, setjmp.h和signal.h

2024-07-10 13:27:18
字体:
来源:转载
供稿:网友

控制函数用于对C语言程序的标准控制流(如if/else、switch、for等)提供扩展,在头文件assert.h、setjmp.h和signal.h中提供,分别提供表达式断言功能、非本地跳转功能、信号处理功能。
    1、assert.h: 提供用于断言的assert宏。程序中若没有定义NDEBUG,则asset(exp)对表达式exp进行断言,若断言为假(即为0),则会调用__assert_fail函数打印一条“断言失败”的消息,并终止程序。若定义了NDEBUG宏,则assert通常为空语句。

 

[cpp] view plaincopy
  1. /* ISO C99 Standard: 7.2 诊断  <assert.h> */  
  2. #ifdef  _ASSERT_H  
  3. # undef _ASSERT_H  
  4. # undef assert  
  5. # undef __ASSERT_VOID_CAST  
  6. # ifdef __USE_GNU  
  7. #  undef assert_perror  
  8. # endif  
  9. #endif /* assert.h  */  
  10. #define _ASSERT_H   1  
  11. #include <features.h>  
  12. #if defined __cplusplus && __GNUC_PREREQ (2,95)  
  13. # define __ASSERT_VOID_CAST static_cast<void>  
  14. #else  
  15. # define __ASSERT_VOID_CAST (void)  
  16. #endif  
  17. /* void assert (int expression); 
  18.    如果定义了NDEBUG,什么也不做,如果没有定义,且EXPRESSION为0,则打印一个错误消息,然后终止程序 
  19.   */  
  20. #ifdef  NDEBUG  
  21. # define assert(expr)       (__ASSERT_VOID_CAST (0))  
  22. /* void assert_perror (int errnum); 
  23.    如果定义了NDEBUG,什么也不做。如果没有定义,且ERRNUM为0,则打印对应于错误码ERRNUM的错误消息, 
  24.    然后终止程序  */  
  25. # ifdef __USE_GNU  
  26. #  define assert_perror(errnum) (__ASSERT_VOID_CAST (0))  
  27. # endif  
  28. #else /* 没有定义NDEBUG */  
  29. #ifndef _ASSERT_H_DECLS  
  30. #define _ASSERT_H_DECLS  
  31. __BEGIN_DECLS  
  32. /* 这里打印一条“断言失败”的消息,然后终止程序  */  
  33. extern void __assert_fail (__const char *__assertion, __const char *__file,  
  34.                unsigned int __line, __const char *__function)  
  35.      __THROW __attribute__ ((__noreturn__));  
  36. /* 与上面一样,但打印错误码ERRNUM的错误消息  */  
  37. extern void __assert_perror_fail (int __errnum, __const char *__file,  
  38.                   unsigned int __line,  
  39.                   __const char *__function)  
  40.      __THROW __attribute__ ((__noreturn__));  
  41.   
  42. /* 下面的函数在这里并没有使用,但为了与标准兼容,还是需要提供  */  
  43. extern void __assert (const char *__assertion, const char *__file, int __line)  
  44.      __THROW __attribute__ ((__noreturn__));  
  45.   
  46. __END_DECLS  
  47. #endif /* Not _ASSERT_H_DECLS */  
  48. /* 使用上面的函数来定义完整的assert宏 */  
  49. # define assert(expr)                           /  
  50.   ((expr)                               /  
  51.    ? __ASSERT_VOID_CAST (0)                     /  
  52.    : __assert_fail (__STRING(expr), __FILE__, __LINE__, __ASSERT_FUNCTION))  
  53. # ifdef __USE_GNU  
  54. #  define assert_perror(errnum)                     /  
  55.   (!(errnum)                                /  
  56.    ? __ASSERT_VOID_CAST (0)                     /  
  57.    : __assert_perror_fail ((errnum), __FILE__, __LINE__, __ASSERT_FUNCTION))  
  58. # endif  
  59. /* 2.4及之后版本的GCC定义了一个魔术变量__PRETTY_FUNCTION__,它包含当前定义的函数名,这在2.6版本之前 
  60.    的G++中打破了。C9x有一个类似的名为__func__的变量,但首选的是GCC的这个变量,因为它重新覆盖了C++中的 
  61.    这个函数名 */  
  62. # if defined __cplusplus ? __GNUC_PREREQ (2, 6) : __GNUC_PREREQ (2, 4)  
  63. #   define __ASSERT_FUNCTION    __PRETTY_FUNCTION__  
  64. # else  
  65. #  if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L  
  66. #   define __ASSERT_FUNCTION    __func__  
  67. #  else  
  68. #   define __ASSERT_FUNCTION    ((__const char *) 0)  
  69. #  endif  
  70. # endif  
  71. #endif /* NDEBUG.  */  

 

 

[cpp] view plaincopy
  1. /* assert.c:assert功能的实现,核心的函数为__assert_fail  */  
  2. #include <assert.h>  
  3. #include <libintl.h>  
  4. #include <stdio.h>  
  5. #include <stdlib.h>  
  6. #include <sysdep.h>  
  7. #include <unistd.h>  
  8.   
  9. extern const char *__progname;  
  10. #ifdef USE_IN_LIBIO  
  11. # include <wchar.h>  
  12. # include <libio/iolibio.h>  
  13. # define fflush(s) INTUSE(_IO_fflush) (s)  
  14. #endif  
  15. /* 本函数当传递一个包含断言表达式的字符串、一个文件名、和一个行号时,在标准 
  16.     错误流上用以下格式打印一条消息: 
  17.     a.c:10: foobar: Assertion `a == b' failed. 
  18.     然后通过调用abort来终止程序的执行 */  
  19. #ifdef FATAL_PREPARE_INCLUDE  
  20. # include FATAL_PREPARE_INCLUDE  
  21. #endif  
  22. #undef __assert_fail  
  23. void  
  24. __assert_fail (const char *assertion, const char *file, unsigned int line,  
  25.            const char *function)  
  26. {  
  27.   char *buf;  
  28. #ifdef FATAL_PREPARE  
  29.   FATAL_PREPARE;  
  30. #endif  
  31.   /* 把指定格式的消息写入到buf中 */  
  32.   if (__asprintf (&buf, _("%s%s%s:%u: %s%sAssertion `%s' failed./n"),  
  33.           __progname, __progname[0] ? ": " : "",  
  34.           file, line,  
  35.           function ? function : "", function ? ": " : "",  
  36.           assertion) >= 0)  
  37.     {  
  38.       (void) __fxprintf (NULL, "%s", buf);    /* 打印buf中的消息  */  
  39.       (void) fflush (stderr);   /* 刷新标准错误流的状态(注意stderr并不缓冲) */   
  40.       /* 我们要释放消息缓冲区,因为应用程序可能会捕捉到SIGABRT信号 */  
  41.       free (buf);  
  42.     }  
  43.   else  /* 消息写入未成功 */  
  44.     {  
  45.       /* 至少要打印一个最小的消息  */  
  46.       static const char errstr[] = "Unexpected error./n";  
  47.       __libc_write (STDERR_FILENO, errstr, sizeof (errstr) - 1);  
  48.     }  
  49.   abort ();  /* 调用abort终止程序 */  
  50. }  
  51. hidden_def(__assert_fail)  

 

 

[cpp] view plaincopy
  1. /* assert-perr.c:assert_perror功能是GNU的一个扩展,核心的函数是__assert_perror_fail */  
  2. #include <assert.h>  
  3. #include <libintl.h>  
  4. #include <stdio.h>  
  5. #include <stdlib.h>  
  6. #include <string.h>  
  7. #include <sysdep.h>  
  8. #include <unistd.h>  
  9.   
  10. extern const char *__progname;  
  11. #ifdef USE_IN_LIBIO  
  12. # include <wchar.h>  
  13. # include <libio/iolibio.h>  
  14. # define fflush(s) INTUSE(_IO_fflush) (s)  
  15. #endif  
  16. /* 本函数当传递一个包含断言表达式的字符串、一个文件名、和一个行号时,在标准 
  17.     错误流上用以下格式打印一条消息: 
  18.     a.c:10: foobar: Unexpected error: Computer bought the farm 
  19.     然后通过调用abort来终止程序的执行  */  
  20. #ifdef FATAL_PREPARE_INCLUDE  
  21. # include FATAL_PREPARE_INCLUDE  
  22. #endif  
  23. void  
  24. __assert_perror_fail (int errnum,  
  25.               const char *file, unsigned int line,  
  26.               const char *function)  
  27. {  
  28.   char errbuf[1024];  
  29.   char *buf;  
  30. #ifdef FATAL_PREPARE  
  31.   FATAL_PREPARE;  
  32. #endif  
  33.   /* 把指定格式的消息写入到buf中 */  
  34.   if (__asprintf (&buf, _("%s%s%s:%u: %s%sUnexpected error: %s./n"),  
  35.           __progname, __progname[0] ? ": " : "",  
  36.           file, line,  
  37.           function ? function : "", function ? ": " : "",  
  38.           __strerror_r (errnum, errbuf, sizeof errbuf)) >= 0)  
  39.     {  
  40.       (void) __fxprintf (NULL, "%s", buf);    /* 打印buf中的消息  */  
  41.       (void) fflush (stderr);  /* 刷新标准错误流的状态(注意stderr并不缓冲) */  
  42.       /* 我们要释放消息缓冲区,因为应用程序可能会捕捉到SIGABRT信号 */  
  43.       free (buf);  
  44.     }  
  45.   else  /* 消息写入未成功 */  
  46.     {  
  47.       /* 至少要打印一个最小的消息  */  
  48.       static const char errstr[] = "Unexpected error./n";  
  49.       __libc_write (STDERR_FILENO, errstr, sizeof (errstr) - 1);  
  50.     }  
  51.   abort ();  /* 调用abort终止程序 */  
  52. }  
  53. libc_hidden_def (__assert_perror_fail)  

 

 

[cpp] view plaincopy
  1. /* __assert.c:__assert函数的实现 */  
  2. /* 我们必须参看原型:没有定义NDEBUG时才会在<assert.h>有__assert的原型  */  
  3. #undef NDEBUG  
  4. #include <assert.h>  
  5. /* 提供__assert函数是为了与标准兼容,它的功能由__assert_fail取代 */  
  6. void  
  7. __assert (const char *assertion, const char *file, int line)  
  8. {  
  9.   __assert_fail (assertion, file, line, (const char *) 0);  
  10. }  

 

    解释:
    (1)GNU还提供了一个扩展assert_perror,功能与assert类似,只不过打印指定的错误码对应的消息,通过__assert_perror_fail函数来实现。另外提供的_assert函数是为了与标准兼容,它的功能由__assert_fail取代。
    (2)__assert_fail和__assert_perror_fail函数都是把指定格式的消息写入到buf中,然后打印buf中的消息,并刷新标准错误流的状态,释放消息缓冲区buf,最后要调用abort函数终止程序。
    2、setjmp.h: 标准库函数setjmp和longjmp实现基本形式的非本地跳转。setjmp用于保存调用者的堆栈环境(被保存在表示跳转缓冲区的jmp_buf型数组ENV中),然后返回0。longjmp用于跳转到保存堆栈环境的地方,并从那里的setjmp调用返回,返回指定的状态码,如果状态码为0则返回1。

 

[cpp] view plaincopy
  1. /* ISO C99 Standard: 7.13 非本地跳转 <setjmp.h> */  
  2. #ifndef _SETJMP_H  
  3. #define _SETJMP_H   1  
  4. #include <features.h>  
  5. __BEGIN_DECLS  
  6. #include <bits/setjmp.h>      /* 获取__jmp_buf  */  
  7. #include <bits/sigset.h>      /* 获取__sigset_t  */  
  8.   
  9. /* 调用环境,可能还会附加一个被保存的信号掩码  */  
  10. struct __jmp_buf_tag  
  11.   {  
  12.     /* 注意:依赖于机器的__sigsetjmp定义假定一个jmp_buf从__jmp_buf开始,后面紧跟着 
  13.         __mask_was_saved。不要移动这些成员或者在前面添加其他的成员 */  
  14.     __jmp_buf __jmpbuf;     /* 调用环境  */  
  15.     int __mask_was_saved;   /* 保存信号掩码吗?  */  
  16.     __sigset_t __saved_mask;    /* 被保存的信号掩码  */  
  17.   };  
  18.   
  19. __BEGIN_NAMESPACE_STD  
  20. typedef struct __jmp_buf_tag jmp_buf[1];  /* 定义jmp_buf数组 */  
  21. /* 在ENV中保存调用环境,同时也会保存信号掩码,返回0 */  
  22. extern int setjmp (jmp_buf __env) __THROW;  
  23. __END_NAMESPACE_STD  
  24. /* 在ENV中保存调用环境,如果SAVEMASK不为零,则同时也会保存信号掩码。返回0。 
  25.     这是sigsetjmp函数的内部名称 */  
  26. extern int __sigsetjmp (struct __jmp_buf_tag __env[1], int __savemask) __THROW;  
  27. #ifndef __FAVOR_BSD  
  28. /* 在ENV中保存调用环境,不保存信号掩码。返回0 */  
  29. extern int _setjmp (struct __jmp_buf_tag __env[1]) __THROW;  
  30. /* 不保存信号掩码。这与BSD函数'_setjmp'等价 */  
  31. # define setjmp(env)    _setjmp (env)  
  32. #else  
  33. /* 在4.3 BSD兼容模式下,setjmp像sigsetjmp(ENV,1)一样来保存信号掩码。我们 
  34.     必须定义一个宏,因为ISO C指出setjmp是完整的 */  
  35. # define setjmp(env)    setjmp (env)  
  36. #endif /* Favor BSD.  */  
  37.   
  38. __BEGIN_NAMESPACE_STD  
  39. /* 跳转到保存在ENV中的环境处,使那里的setjmp调用返回VAL,或者返回1(如果VAL为0) */  
  40. extern void longjmp (struct __jmp_buf_tag __env[1], int __val)  
  41.      __THROW __attribute__ ((__noreturn__));  
  42. __END_NAMESPACE_STD  
  43. #if defined __USE_BSD || defined __USE_XOPEN  
  44. /* 与上面相同。通常_longjmp与setjmp一起使用,不保存信号掩码。但怎样保存ENV决定了longjmp 
  45.     是否恢复掩码;而_longjmp只是一个别名 */  
  46. extern void _longjmp (struct __jmp_buf_tag __env[1], int __val)  
  47.      __THROW __attribute__ ((__noreturn__));  
  48. #endif  
  49.   
  50. #ifdef  __USE_POSIX  
  51. /* 对jmp_buf和sigjmp_buf使用同样的类型。__mask_was_saved标志决定 
  52.     longjmp是否将恢复信号掩码 */  
  53. typedef struct __jmp_buf_tag sigjmp_buf[1];  
  54. /* 在ENV中保存调用环境,同时也会保存信号掩码(如果SAVEMASK不为零),返回0  */  
  55. # define sigsetjmp(env, savemask)   __sigsetjmp (env, savemask)  
  56. /* 跳转到保存在ENV中的环境处,使那里的sigsetjmp调用返回VAL,或者返回(如果VAL为0) 
  57.     恢复信号掩码(如果那个sigsetjmp保存了它的话)。本函数只是longjmp的一个别名 */  
  58. extern void siglongjmp (sigjmp_buf __env, int __val)  
  59.      __THROW __attribute__ ((__noreturn__));  
  60. #endif /* Use POSIX.  */  
  61. __END_DECLS  
  62. #endif /* setjmp.h  */  

 

 

[cpp] view plaincopy
  1. /* setjmp.c:setjmp函数的实现  */  
  2. #include <errno.h>  
  3. #include <setjmp.h>  
  4. /* 在ENV中人嘎当前程序的位置,然后返回0  */  
  5. int  
  6. __libc_sigsetjmp (jmp_buf env, int savemask)  
  7. {  
  8.   /* 如果被请求的话,保存信号掩码  */  
  9.   __sigjmp_save (env, savemask);  
  10.   __set_errno (ENOSYS);  
  11.   /* 没有信号失败 */  
  12.   return 0;  
  13. }  
  14. weak_alias (__libc_sigsetjmp, __sigsetjmp)  
  15. stub_warning (__sigsetjmp)  
  16. #include <stub-tag.h>  

 

 

[cpp] view plaincopy
  1. /* longjmp.c:longjmp函数的实现 */  
  2. #include <stddef.h>  
  3. #include <setjmp.h>  
  4. #include <signal.h>  
  5. /* 在ENV中的相应成员上设置信号掩码,并且跳转到ENV指定的位置处,导致那里的 
  6.     setjmp调用返回VAL,或者返回1(如果VAL为0) */  
  7. void  
  8. __libc_siglongjmp (sigjmp_buf env, int val)  
  9. {  
  10.   /* 在展开的堆栈结构上需要做清理工作  */  
  11.   _longjmp_unwind (env, val);  
  12.   if (env[0].__mask_was_saved)  
  13.     /* 恢复被保存的掩码  */  
  14.     (void) __sigprocmask (SIG_SETMASK, &env[0].__saved_mask,  
  15.               (sigset_t *) NULL);  
  16.   /* 调用依赖于机器的函数来恢复机器状态  */  
  17.   __longjmp (env[0].__jmpbuf, val ?: 1);  
  18. }  
  19. strong_alias (__libc_siglongjmp, __libc_longjmp)  
  20. libc_hidden_def (__libc_longjmp)  
  21. weak_alias (__libc_siglongjmp, _longjmp)  
  22. weak_alias (__libc_siglongjmp, longjmp)  
  23. weak_alias (__libc_siglongjmp, siglongjmp)  

 

    注意setjmp和longjmp函数都是直接调用内部函数来完成工作的。头文件setjmp.h中的其他部分都是BSD、XOPEN或POSIX方面的扩展。
    3、signal.h: 定义了信号原子类型sig_atomic_t、信号处理函数的注册signal、发送信号的函数raise。它包含了bits/signum.h,这个Linux系统的头文件中定义了C标准中的信号及其他一些信号。标准C语言中的信号有SIGINT,SIGILL,SIGABRT,SIGFPE,SIGSEGV,SIGTERM,还要3个特殊的信号SIGERR,SIG_DFL, SIG_IGN,因此标准C语言中总共有9个信号。

    signal.h代码如下:

 

[cpp] view plaincopy
  1. /* ISO C99 Standard: 7.14 信号处理 <signal.h> */  
  2. #ifndef _SIGNAL_H  
  3. #if !defined __need_sig_atomic_t && !defined __need_sigset_t  
  4. # define _SIGNAL_H  
  5. #endif  
  6. #include <features.h>  /* 定义了一些编译选项 */  
  7. __BEGIN_DECLS  
  8. #include <bits/sigset.h>      /* 获取__sigset_t和__sig_atomic_t类型  */  
  9. /* 一个可以自动修改的内部类型,它不可能是一个到达运算中间的信号 */  
  10. #if defined __need_sig_atomic_t || defined _SIGNAL_H  
  11. # ifndef __sig_atomic_t_defined  
  12. #  define __sig_atomic_t_defined  
  13. __BEGIN_NAMESPACE_STD  
  14. typedef __sig_atomic_t sig_atomic_t;  /* 定义信号原子类型 */  
  15. __END_NAMESPACE_STD  
  16. # endif  
  17. # undef __need_sig_atomic_t  
  18. #endif  
  19. #if defined __need_sigset_t || (defined _SIGNAL_H && defined __USE_POSIX)  
  20. # ifndef __sigset_t_defined  
  21. #  define __sigset_t_defined  
  22. typedef __sigset_t sigset_t;  /* 信号集类型 */  
  23. # endif  
  24. # undef __need_sigset_t  
  25. #endif  
  26. #ifdef _SIGNAL_H  
  27. #include <bits/types.h>   /* 定义了一些扩展整数类型 */  
  28. #include <bits/signum.h>  /* 定义了C标准中的信号及其他一些信号 */  
  29. #if defined __USE_XOPEN || defined __USE_XOPEN2K  
  30. # ifndef __pid_t_defined  
  31. typedef __pid_t pid_t;  /* 进程ID类型 */  
  32. #  define __pid_t_defined  
  33. #endif  
  34. #ifdef __USE_XOPEN  
  35. # endif  
  36. # ifndef __uid_t_defined  
  37. typedef __uid_t uid_t;  /* 用户ID类型 */  
  38. #  define __uid_t_defined  
  39. # endif  
  40. #endif  /* Unix98 */  
  41.   
  42. /* 信号处理函数类型  */  
  43. typedef void (*__sighandler_t) (int);  
  44. /* X/Open的signal定义指定SVID的语义。当需要X/Open兼容性时使用另外一个函数sysv_signal */  
  45. extern __sighandler_t __sysv_signal (int __sig, __sighandler_t __handler)  
  46.      __THROW;  
  47. #ifdef __USE_GNU  
  48. extern __sighandler_t sysv_signal (int __sig, __sighandler_t __handler)  
  49.      __THROW;  
  50. #endif  
  51. /* 为信号SIG设置信号处理函数HANDLER,返回原来的信号处理函数,出错则返回SIG_ERR 
  52.     默认情况下signal拥有BSD风格的语义 */  
  53. __BEGIN_NAMESPACE_STD  
  54. #ifdef __USE_BSD  
  55. extern __sighandler_t signal (int __sig, __sighandler_t __handler)  
  56.      __THROW;  
  57. #else  
  58. /* 确保使用的signal实现是SVID的版本 */  
  59. # ifdef __REDIRECT_NTH  
  60. extern __sighandler_t __REDIRECT_NTH (signal,  
  61.                       (int __sig, __sighandler_t __handler),  
  62.                       __sysv_signal);  
  63. # else  
  64. #  define signal __sysv_signal  
  65. # endif  
  66. #endif  
  67. __END_NAMESPACE_STD  
  68. #ifdef __USE_XOPEN  
  69. /* X/Open的signal定义与BSD的版本有冲突,因此它们定义定义另外一个函数bsd_singnal */  
  70. extern __sighandler_t bsd_signal (int __sig, __sighandler_t __handler)  
  71.      __THROW;  
  72. #endif  
  73. /* 发送信号SIG给PID表示的这个进程。如果PID为0,则发送信号SIG给当前进程组的所有进程。 
  74.     如果PID<-1,则发送SIG给PID表示的进程组中的所有进程 */  
  75. #ifdef __USE_POSIX  
  76. extern int kill (__pid_t __pid, int __sig) __THROW;  
  77. #endif /* Use POSIX.  */  
  78. #if defined __USE_BSD || defined __USE_XOPEN_EXTENDED  
  79. /* 发送信号SIG给进程组PGRP中的所有进程。如果PGRP为0,则发送信号SIG给 
  80.     当前进程组的所有进程 */  
  81. extern int killpg (__pid_t __pgrp, int __sig) __THROW;  
  82. #endif /* Use BSD || X/Open Unix.  */  
  83. __BEGIN_NAMESPACE_STD  
  84. /* 发送信号SIG。例如,发送SIG给你自己  */  
  85. extern int raise (int __sig) __THROW;  
  86. __END_NAMESPACE_STD  
  87. /* 下面都是一些扩展或内部函数 */  
  88. #endif /* signal.h  */  
  89. __END_DECLS  
  90. #endif /* not signal.h */  

 

    bits/signum.h代码如下:

 

[cpp] view plaincopy
  1. /* bits/signum.h:信号码定义,Linux版本  */  
  2. #ifdef  _SIGNAL_H  
  3. /* 伪信号函数  */  
  4. #define SIG_ERR ((__sighandler_t) -1)       /* 出错时返回  */  
  5. #define SIG_DFL ((__sighandler_t) 0)        /* 默认行为  */  
  6. #define SIG_IGN ((__sighandler_t) 1)        /* 忽略信号  */  
  7. #ifdef __USE_UNIX98  
  8. # define SIG_HOLD   ((__sighandler_t) 2)    /* 给信号加保留的掩码  */  
  9. #endif  
  10.   
  11. /* 信号  */  
  12. #define SIGHUP      1   /* 挂断 (POSIX).  */  
  13. #define SIGINT      2   /* 中断 (ANSI).  */  
  14. #define SIGQUIT     3   /* 退出 (POSIX).  */  
  15. #define SIGILL      4   /* 非法指令 (ANSI).  */  
  16. #define SIGTRAP     5   /* 跟踪捕捉 (POSIX).  */  
  17. #define SIGABRT     6   /* 异常终止,如调用abort (ANSI).  */  
  18. #define SIGIOT      6   /* 图像输出终端(IOT)陷阱 (4.2 BSD).  */  
  19. #define SIGBUS      7   /* 总线错误 (4.2 BSD).  */  
  20. #define SIGFPE      8   /* 浮点数异常 (ANSI).  */  
  21. #define SIGKILL     9   /* 杀死,此信号可解锁 (POSIX).  */  
  22. #define SIGUSR1     10  /* 用户定义信号1 (POSIX).  */  
  23. #define SIGSEGV     11  /* 段错误,即无效内存访问 (ANSI).  */  
  24. #define SIGUSR2     12  /* 用户定义信号2 (POSIX).  */  
  25. #define SIGPIPE     13  /* 管道错误 (POSIX).  */  
  26. #define SIGALRM     14  /* 时钟警告 (POSIX).  */  
  27. #define SIGTERM     15  /* 终止 (ANSI).  */  
  28. #define SIGSTKFLT   16  /* 堆栈故障  */  
  29. #define SIGCLD      SIGCHLD /* 等同于SIGCHLD (System V).  */  
  30. #define SIGCHLD     17  /* 子进程状态已经改变 (POSIX).  */  
  31. #define SIGCONT     18  /* 继续 (POSIX).  */  
  32. #define SIGSTOP     19  /* 停止,此信号可解锁 (POSIX).  */  
  33. #define SIGTSTP     20  /* 键盘发的停止信号 (POSIX).  */  
  34. #define SIGTTIN     21  /* 从tty进行后台读操作 (POSIX).  */  
  35. #define SIGTTOU     22  /* 后台写入tty (POSIX).  */  
  36. #define SIGURG      23  /* socket紧急状态 (4.2 BSD).  */  
  37. #define SIGXCPU     24  /* 超出CPU限制 (4.2 BSD).  */  
  38. #define SIGXFSZ     25  /* 超出文件大小限制 (4.2 BSD).  */  
  39. #define SIGVTALRM   26  /* 时钟虚拟警告 (4.2 BSD).  */  
  40. #define SIGPROF     27  /* 时钟Profiling警告 (4.2 BSD).  */  
  41. #define SIGWINCH    28  /* 窗口大小改变 (4.3 BSD, Sun).  */  
  42. #define SIGPOLL     SIGIO   /* 可移植的事件发生 (System V).  */  
  43. #define SIGIO       29  /* 可以执行I/O (4.2 BSD).  */  
  44. #define SIGPWR      30  /* 重启时电源失效 (System V).  */  
  45. #define SIGSYS      31  /* 错误的系统调用  */  
  46. #define SIGUNUSED   31  
  47. #define _NSIG       65  /* 最大的信号值+1(包括实时信号)  */  
  48. #define SIGRTMIN        (__libc_current_sigrtmin ())  
  49. #define SIGRTMAX        (__libc_current_sigrtmax ())  
  50. /* 这些是内核的硬限制。这些值不应该在用户级别使用 */  
  51. #define __SIGRTMIN  32  
  52. #define __SIGRTMAX  (_NSIG - 1)  
  53. #endif  /* <signal.h> included.  */  

 

    signal函数和raise函数的实现:

 

[cpp] view plaincopy
  1. /* signal.c:signal函数的实现  */  
  2. #include <errno.h>  
  3. #include <signal.h>  
  4. /* 为信号SIG设置信号处理函数HANDLER,返回原来的信号处理函数,出错则返回SIG_ERR  */  
  5. __sighandler_t  
  6. signal (sig, handler)  
  7.      int sig;  
  8.      __sighandler_t handler;  
  9. {  
  10.   __set_errno (ENOSYS);  
  11.   return SIG_ERR;  
  12. }  
  13. weak_alias (signal, ssignal)  
  14. stub_warning (signal)  
  15. stub_warning (ssignal)  
  16. #include <stub-tag.h>  

 

 

[cpp] view plaincopy
  1. /* raise.c:raise函数的实现  */  
  2. #include <signal.h>  
  3. #include <errno.h>  
  4. /* 发送SIG  */  
  5. int  
  6. raise (sig)  
  7.      int sig;  
  8. {  
  9.   __set_errno (ENOSYS);  
  10.   return -1;  
  11. }  
  12. weak_alias (raise, gsignal)  
  13. stub_warning (raise)  
  14. stub_warning (gsignal)  
  15. #include <stub-tag.h>  

 

    注意signal和raise函数并没有做任何特别的实现,只是处理了一下出错时的情况(返回SIG_ERR,即-1)。真正的实现使用Linux中有对应功能的函数,signal直接映射到Linux的ssignal函数,raise直接映射到Linux的gsignal函数。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表