本文谢绝转载,原文来自http://990487026.blog.51cto.com


《大纲》

Linux系统开发6 信号
	linux系统有64种信号
	signal man文档
	终端按键信号
		ctrl +c SIGIN
		ctrl +z SIGTSTP
		ctrl +\ SIGQUIT

	硬件产生信号
		浮点数例外信号 
		访问非法内存
		
	kill()函数
	信号与权限
	kill()函数的pid 与返回值
	信号产生原因
	
	raise() 信号
	abort() 信号
	alarm() 信号
	收到信号的默认操作
	信号阻塞 屏蔽,,
	解除信号的阻塞
	信号捕捉 sa_handler 自定义函数 方式捕捉crtl + c
	sa_handler 设定为默认 默认处理ctrl+c
	sa_handler 设定为忽略 ctrl+c
	处理信号的时候再来一次信号,并不会嵌套,
	sigaddset() 当进入信号函数的调用时
		1,没有屏蔽 ctrl+\ 信号的时候,执行信号函数会响应ctrl+\操作
		2,屏蔽 ctrl+\ 信号的时候,执行信号函数不会响应ctrl+\,等运行结束后才会响应
		
	SIGUSR1用户自定义信号
	C 标准库函数,信号捕捉函数
	system函数,集成与fork() exit() wait()一体的函数 
	可重入 不可重入函数
	Linux下的可重入安全函数
	pause()系统挂起,等待信号的来临
	pause()系统挂起,如果是忽略操作就忽略
	利用pause() 与 信号 实现my_sleep()函数
	my_sleep()函数 时序竞态问题
	my_sleep增强 sigsuspend避免了时序竞争 
	
	什么是sig_atomic_t数据类型 
	SIGCHLD 信号产生的条件	
	用信号回收子进程
	作业:


linux系统有64种信号

我们只讨论系统的前32种信号(1--31)

后面32种是硬件驱动自定义信号

chunli@ubuntu:~$ kill -l
 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
 6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX	
chunli@ubuntu:~$


signal man文档

chunli@ubuntu:~$ man 7 signal
SIGNAL(7)                     Linux Programmer's Manual                     SIGNAL(7)

NAME
       signal - overview of signals

DESCRIPTION
       Linux  supports  both  POSIX reliable signals (hereinafter "standard signals")
       and POSIX real-time signals.

   Signal dispositions
       Each signal has a  current  disposition,  which  determines  how  the  process
       behaves when it is delivered the signal.

       The  entries  in  the  "Action" column of the tables below specify the default
       disposition for each signal, as follows:

       Term   Default action is to terminate the process.

       Ign    Default action is to ignore the signal.

       Core   Default action is to terminate the process and dump core (see core(5)).

       Stop   Default action is to stop the process.

       Cont   Default action is to continue the process if it is currently stopped.

       A process can change the disposition of a signal using  sigaction(2)  or  sig‐
       nal(2).   (The latter is less portable when establishing a signal handler; see
       signal(2) for details.)  Using these system calls, a process can elect one  of
       the  following  behaviors  to  occur  on  delivery  of the signal: perform the
       default action; ignore the signal; or catch the signal with a signal  handler,
       a programmer-defined function that is automatically invoked when the signal is
       delivered.  (By default, the signal handler is invoked on the  normal  process
       stack.   It  is  possible to arrange that the signal handler uses an alternate
       stack; see sigaltstack(2) for a discussion of how to do this and when it might
       be useful.)

       The signal disposition is a per-process attribute: in a multithreaded applica‐
       tion, the disposition of a particular signal is the same for all threads.

       A child created via fork(2) inherits a copy of its  parent's  signal  disposi‐
       tions.   During an execve(2), the dispositions of handled signals are reset to
       the default; the dispositions of ignored signals are left unchanged.

   Sending a signal
       The following system calls and library functions allow the caller  to  send  a
       signal:

       raise(3)        Sends a signal to the calling thread.

       kill(2)         Sends  a  signal  to  a specified process, to all members of a
                       specified process group, or to all processes on the system.

       killpg(2)       Sends a signal to all of the members of  a  specified  process
                       group.

       pthread_kill(3) Sends a signal to a specified POSIX thread in the same process
                       as the caller.

       tgkill(2)       Sends a  signal  to  a  specified  thread  within  a  specific
                       process.    (This   is  the  system  call  used  to  implement
                       pthread_kill(3).)

       sigqueue(3)     Sends a real-time signal with accompanying data to a specified
                       process.

   Waiting for a signal to be caught
       The  following system calls suspend execution of the calling process or thread
       until a signal is caught (or an unhandled signal terminates the process):

       pause(2)        Suspends execution until any signal is caught.

       sigsuspend(2)   Temporarily changes the signal mask (see below)  and  suspends
                       execution until one of the unmasked signals is caught.

   Synchronously accepting a signal
       Rather  than asynchronously catching a signal via a signal handler, it is pos‐
       sible to synchronously accept the signal, that is, to  block  execution  until
       the  signal  is delivered, at which point the kernel returns information about
       the signal to the caller.  There are two general ways to do this:

       * sigwaitinfo(2), sigtimedwait(2), and sigwait(3) suspend execution until  one
         of the signals in a specified set is delivered.  Each of these calls returns
         information about the delivered signal.

       * signalfd(2) returns a file descriptor that can be used to  read  information
         about signals that are delivered to the caller.  Each read(2) from this file
         descriptor blocks until one of the signals in the set specified in the  sig‐
         nalfd(2)  call  is  delivered to the caller.  The buffer returned by read(2)
         contains a structure describing the signal.

   Signal mask and pending signals
       A signal may be blocked, which means that it will not be delivered until it is
       later  unblocked.  Between the time when it is generated and when it is deliv‐
       ered a signal is said to be pending.

       Each thread in a process has an independent signal mask, which  indicates  the
       set of signals that the thread is currently blocking.  A thread can manipulate
       its signal mask using pthread_sigmask(3).  In  a  traditional  single-threaded
       application, sigprocmask(2) can be used to manipulate the signal mask.

       A  child  created via fork(2) inherits a copy of its parent's signal mask; the
       signal mask is preserved across execve(2).

       A signal may be generated (and thus pending) for a process as a  whole  (e.g.,
       when sent using kill(2)) or for a specific thread (e.g., certain signals, such
       as SIGSEGV and SIGFPE, generated as a  consequence  of  executing  a  specific
       machine-language instruction are thread directed, as are signals targeted at a
       specific thread using pthread_kill(3)).   A  process-directed  signal  may  be
       delivered  to  any  one of the threads that does not currently have the signal
       blocked.  If more than one of the threads has the signal unblocked,  then  the
       kernel chooses an arbitrary thread to which to deliver the signal.

       A  thread  can  obtain  the set of signals that it currently has pending using
       sigpending(2).  This set will consist of the  union  of  the  set  of  pending
       process-directed  signals  and  the  set  of  signals  pending for the calling
       thread.

       A child created via fork(2) initially has an empty  pending  signal  set;  the
       pending signal set is preserved across an execve(2).

   Standard signals
       Linux  supports the standard signals listed below.  Several signal numbers are
       architecture-dependent, as indicated in the "Value" column.  (Where three val‐
       ues  are given, the first one is usually valid for alpha and sparc, the middle
       one for x86, arm, and most other architectures, and the  last  one  for  mips.
       (Values  for parisc are not shown; see the Linux kernel source for signal num‐
       bering on that architecture.)  A - denotes that a signal is absent on the cor‐
       responding architecture.)

       First the signals described in the original POSIX.1-1990 standard.

       Signal     Value     Action   Comment
       ──────────────────────────────────────────────────────────────────────
       SIGHUP        1       Term    Hangup detected on controlling terminal
                                     or death of controlling process
       SIGINT        2       Term    Interrupt from keyboard
       SIGQUIT       3       Core    Quit from keyboard
       SIGILL        4       Core    Illegal Instruction
       SIGABRT       6       Core    Abort signal from abort(3)
       SIGFPE        8       Core    Floating point exception
       SIGKILL       9       Term    Kill signal
       SIGSEGV      11       Core    Invalid memory reference
       SIGPIPE      13       Term    Broken pipe: write to pipe with no
                                     readers
       SIGALRM      14       Term    Timer signal from alarm(2)
       SIGTERM      15       Term    Termination signal
       SIGUSR1   30,10,16    Term    User-defined signal 1
       SIGUSR2   31,12,17    Term    User-defined signal 2
       SIGCHLD   20,17,18    Ign     Child stopped or terminated
       SIGCONT   19,18,25    Cont    Continue if stopped
       SIGSTOP   17,19,23    Stop    Stop process
       SIGTSTP   18,20,24    Stop    Stop typed at terminal
       SIGTTIN   21,21,26    Stop    Terminal input for background process
       SIGTTOU   22,22,27    Stop    Terminal output for background process

       The signals SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.

       Next  the  signals not in the POSIX.1-1990 standard but described in SUSv2 and
       POSIX.1-2001.

       Signal       Value     Action   Comment
       ────────────────────────────────────────────────────────────────────
       SIGBUS      10,7,10     Core    Bus error (bad memory access)
       SIGPOLL                 Term    Pollable event (Sys V).
                                       Synonym for SIGIO
       SIGPROF     27,27,29    Term    Profiling timer expired
       SIGSYS      12,31,12    Core    Bad argument to routine (SVr4)
       SIGTRAP        5        Core    Trace/breakpoint trap
       SIGURG      16,23,21    Ign     Urgent condition on socket (4.2BSD)
       SIGVTALRM   26,26,28    Term    Virtual alarm clock (4.2BSD)
       SIGXCPU     24,24,30    Core    CPU time limit exceeded (4.2BSD)
       SIGXFSZ     25,25,31    Core    File size limit exceeded (4.2BSD)

       Up to and including Linux 2.2,  the  default  behavior  for  SIGSYS,  SIGXCPU,
       SIGXFSZ, and (on architectures other than SPARC and MIPS) SIGBUS was to termi‐
       nate the process (without a core dump).   (On  some  other  UNIX  systems  the
       default  action  for SIGXCPU and SIGXFSZ is to terminate the process without a
       core dump.)  Linux 2.4 conforms to the  POSIX.1-2001  requirements  for  these
       signals, terminating the process with a core dump.

       Next various other signals.

       Signal       Value     Action   Comment
       ────────────────────────────────────────────────────────────────────
       SIGIOT         6        Core    IOT trap. A synonym for SIGABRT
       SIGEMT       7,-,7      Term
       SIGSTKFLT    -,16,-     Term    Stack fault on coprocessor (unused)
       SIGIO       23,29,22    Term    I/O now possible (4.2BSD)
       SIGCLD       -,-,18     Ign     A synonym for SIGCHLD
       SIGPWR      29,30,19    Term    Power failure (System V)
       SIGINFO      29,-,-             A synonym for SIGPWR
       SIGLOST      -,-,-      Term    File lock lost (unused)
       SIGWINCH    28,28,20    Ign     Window resize signal (4.3BSD, Sun)
       SIGUNUSED    -,31,-     Core    Synonymous with SIGSYS

       (Signal 29 is SIGINFO / SIGPWR on an alpha but SIGLOST on a sparc.)

       SIGEMT  is  not  specified  in  POSIX.1-2001, but nevertheless appears on most
       other UNIX systems, where its default action is  typically  to  terminate  the
       process with a core dump.

       SIGPWR  (which  is  not  specified  in  POSIX.1-2001)  is typically ignored by
       default on those other UNIX systems where it appears.

       SIGIO (which is not specified in POSIX.1-2001) is ignored by default  on  sev‐
       eral other UNIX systems.

       Where defined, SIGUNUSED is synonymous with SIGSYS on most architectures.

   Real-time signals
       Starting  with  version  2.2,  Linux  supports real-time signals as originally
       defined  in  the  POSIX.1b  real-time  extensions   (and   now   included   in
       POSIX.1-2001).   The  range  of  supported real-time signals is defined by the
       macros SIGRTMIN and SIGRTMAX.  POSIX.1-2001 requires  that  an  implementation
       support at least _POSIX_RTSIG_MAX (8) real-time signals.

       The  Linux kernel supports a range of 33 different real-time signals, numbered
       32 to 64.  However, the glibc POSIX threads implementation internally uses two
       (for  NPTL)  or  three (for LinuxThreads) real-time signals (see pthreads(7)),
       and adjusts the value of SIGRTMIN suitably (to 34 or 35).  Because  the  range
       of  available real-time signals varies according to the glibc threading imple‐
       mentation (and this variation can occur at run time according to the available
       kernel  and  glibc),  and  indeed the range of real-time signals varies across
       UNIX systems, programs should never refer to  real-time  signals  using  hard-
       coded  numbers, but instead should always refer to real-time signals using the
       notation SIGRTMIN+n, and include suitable (run-time)  checks  that  SIGRTMIN+n
       does not exceed SIGRTMAX.

       Unlike  standard  signals,  real-time signals have no predefined meanings: the
       entire set of real-time signals can be used for application-defined purposes.

       The default action for an unhandled  real-time  signal  is  to  terminate  the
       receiving process.

       Real-time signals are distinguished by the following:

       1.  Multiple  instances  of  real-time signals can be queued.  By contrast, if
           multiple instances of a standard signal are delivered while that signal is
           currently blocked, then only one instance is queued.

       2.  If  the signal is sent using sigqueue(3), an accompanying value (either an
           integer or a pointer) can be sent  with  the  signal.   If  the  receiving
           process establishes a handler for this signal using the SA_SIGINFO flag to
           sigaction(2), then it can obtain this data via the si_value field  of  the
           siginfo_t  structure  passed  as the second argument to the handler.  Fur‐
           thermore, the si_pid and si_uid fields of this structure can  be  used  to
           obtain the PID and real user ID of the process sending the signal.

       3.  Real-time signals are delivered in a guaranteed order.  Multiple real-time
           signals of the same type are delivered in the order they  were  sent.   If
           different  real-time  signals  are  sent  to a process, they are delivered
           starting with the lowest-numbered  signal.   (I.e.,  low-numbered  signals
           have  highest  priority.)   By  contrast, if multiple standard signals are
           pending for a process, the order in which they are delivered  is  unspeci‐
           fied.

       If both standard and real-time signals are pending for a process, POSIX leaves
       it unspecified which is delivered first.  Linux, like many  other  implementa‐
       tions, gives priority to standard signals in this case.

       According    to    POSIX,   an   implementation   should   permit   at   least
       _POSIX_SIGQUEUE_MAX (32) real-time signals to be queued to  a  process.   How‐
       ever,  Linux  does  things differently.  In kernels up to and including 2.6.7,
       Linux imposes a system-wide limit on the number of  queued  real-time  signals
       for  all processes.  This limit can be viewed and (with privilege) changed via
       the /proc/sys/kernel/rtsig-max file.  A related file,  /proc/sys/kernel/rtsig-
       nr,  can  be used to find out how many real-time signals are currently queued.
       In Linux 2.6.8, these /proc interfaces were replaced by the  RLIMIT_SIGPENDING
       resource limit, which specifies a per-user limit for queued signals; see setr‐
       limit(2) for further details.

       The addition or real-time signals required the  widening  of  the  signal  set
       structure  (sigset_t)  from 32 to 64 bits.  Consequently, various system calls
       were superseded by new system calls that supported  the  larger  signal  sets.
       The old and new system calls are as follows:

       Linux 2.0 and earlier   Linux 2.2 and later
       sigaction(2)            rt_sigaction(2)
       sigpending(2)           rt_sigpending(2)
       sigprocmask(2)          rt_sigprocmask(2)
       sigreturn(2)            rt_sigreturn(2)
       sigsuspend(2)           rt_sigsuspend(2)
       sigtimedwait(2)         rt_sigtimedwait(2)

   Async-signal-safe functions
       A signal handler function must be very careful, since processing elsewhere may
       be interrupted at some arbitrary point in the execution of the program.  POSIX
       has  the  concept of "safe function".  If a signal interrupts the execution of
       an unsafe function, and handler calls an unsafe function, then the behavior of
       the program is undefined.

       POSIX.1-2004  (also known as POSIX.1-2001 Technical Corrigendum 2) requires an
       implementation to guarantee that the following functions can be safely  called
       inside a signal handler:

           _Exit()
           _exit()
           abort()
           accept()
           access()
           aio_error()
           aio_return()
           aio_suspend()
           alarm()
           bind()
           cfgetispeed()
           cfgetospeed()
           cfsetispeed()
           cfsetospeed()
           chdir()
           chmod()
           chown()
           clock_gettime()
           close()
           connect()
           creat()
           dup()
           dup2()
           execle()
           execve()
           fchmod()
           fchown()
           fcntl()
           fdatasync()
           fork()
           fpathconf()
           fstat()
           fsync()
           ftruncate()
           getegid()
           geteuid()
           getgid()
           getgroups()
           getpeername()
           getpgrp()
           getpid()
           getppid()
           getsockname()
           getsockopt()
           getuid()
           kill()
           link()
           listen()
           lseek()
           lstat()
           mkdir()
           mkfifo()
           open()
           pathconf()
           pause()
           pipe()
           poll()
           posix_trace_event()
           pselect()
           raise()
           read()
           readlink()
           recv()
           recvfrom()
           recvmsg()
           rename()
           rmdir()
           select()
           sem_post()
           send()
           sendmsg()
           sendto()
           setgid()
           setpgid()
           setsid()
           setsockopt()
           setuid()
           shutdown()
           sigaction()
           sigaddset()
           sigdelset()
           sigemptyset()
           sigfillset()
           sigismember()
           signal()
           sigpause()
           sigpending()
           sigprocmask()
           sigqueue()
           sigset()
           sigsuspend()
           sleep()
           sockatmark()
           socket()
           socketpair()
           stat()
           symlink()
           sysconf()
           tcdrain()
           tcflow()
           tcflush()
           tcgetattr()
           tcgetpgrp()
           tcsendbreak()
           tcsetattr()
           tcsetpgrp()
           time()
           timer_getoverrun()
           timer_gettime()
           timer_settime()
           times()
           umask()
           uname()
           unlink()
           utime()
           wait()
           waitpid()
           write()

       POSIX.1-2008  removes  fpathconf(),  pathconf(),  and sysconf() from the above
       list, and adds the following functions:

           execl()
           execv()
           faccessat()
           fchmodat()
           fchownat()
           fexecve()
           fstatat()
           futimens()
           linkat()
           mkdirat()
           mkfifoat()
           mknod()
           mknodat()
           openat()
           readlinkat()
           renameat()
           symlinkat()
           unlinkat()
           utimensat()
           utimes()

       POSIX.1-2008 Technical Corrigendum 1 (2013) adds the following functions:

           fchdir()
           pthread_kill()
           pthread_self()
           pthread_sigmask()

   Interruption of system calls and library functions by signal handlers
       If a signal handler is invoked while a system call or library function call is
       blocked, then either:

       * the call is automatically restarted after the signal handler returns; or

       * the call fails with the error EINTR.

       Which  of  these  two behaviors occurs depends on the interface and whether or
       not the signal handler was established using the SA_RESTART flag  (see  sigac‐
       tion(2)).  The details vary across UNIX systems; below, the details for Linux.

       If  a blocked call to one of the following interfaces is interrupted by a sig‐
       nal handler, then the call will be automatically restarted  after  the  signal
       handler  returns if the SA_RESTART flag was used; otherwise the call will fail
       with the error EINTR:

           * read(2), readv(2), write(2), writev(2), and  ioctl(2)  calls  on  "slow"
             devices.   A  "slow"  device  is one where the I/O call may block for an
             indefinite time, for example, a terminal, pipe, or socket.   If  an  I/O
             call  on  a slow device has already transferred some data by the time it
             is interrupted by a signal handler, then the call will return a  success
             status (normally, the number of bytes transferred).  Note that a (local)
             disk is not a slow device according to this definition;  I/O  operations
             on disk devices are not interrupted by signals.

           * open(2), if it can block (e.g., when opening a FIFO; see fifo(7)).

           * wait(2), wait3(2), wait4(2), waitid(2), and waitpid(2).

           * Socket   interfaces:   accept(2),   connect(2),   recv(2),  recvfrom(2),
             recvmmsg(2), recvmsg(2), send(2), sendto(2), and  sendmsg(2),  unless  a
             timeout has been set on the socket (see below).

           * File  locking  interfaces:  flock(2)  and  the F_SETLKW and F_OFD_SETLKW
             operations of fcntl(2)

           * POSIX  message  queue  interfaces:  mq_receive(3),   mq_timedreceive(3),
             mq_send(3), and mq_timedsend(3).

           * futex(2)  FUTEX_WAIT (since Linux 2.6.22; beforehand, always failed with
             EINTR).

           * getrandom(2).

           * pthread_mutex_lock(3), pthread_cond_wait(3), and related APIs.

           * futex(2) FUTEX_WAIT_BITSET.

           * POSIX semaphore  interfaces:  sem_wait(3)  and  sem_timedwait(3)  (since
             Linux 2.6.22; beforehand, always failed with EINTR).

       The following interfaces are never restarted after being interrupted by a sig‐
       nal handler, regardless of the use of SA_RESTART; they always  fail  with  the
       error EINTR when interrupted by a signal handler:

           * "Input"  socket interfaces, when a timeout (SO_RCVTIMEO) has been set on
             the  socket  using  setsockopt(2):  accept(2),   recv(2),   recvfrom(2),
             recvmmsg(2) (also with a non-NULL timeout argument), and recvmsg(2).

           * "Output" socket interfaces, when a timeout (SO_RCVTIMEO) has been set on
             the socket using  setsockopt(2):  connect(2),  send(2),  sendto(2),  and
             sendmsg(2).

           * Interfaces  used to wait for signals: pause(2), sigsuspend(2), sigtimed‐
             wait(2), and sigwaitinfo(2).

           * File descriptor multiplexing interfaces: epoll_wait(2),  epoll_pwait(2),
             poll(2), ppoll(2), select(2), and pselect(2).

           * System  V  IPC  interfaces: msgrcv(2), msgsnd(2), semop(2), and semtime‐
             dop(2).

           * Sleep interfaces: clock_nanosleep(2), nanosleep(2), and usleep(3).

           * read(2) from an inotify(7) file descriptor.

           * io_getevents(2).

       The sleep(3) function is also never restarted if interrupted by a handler, but
       gives a success return: the number of seconds remaining to sleep.

   Interruption of system calls and library functions by stop signals
       On  Linux, even in the absence of signal handlers, certain blocking interfaces
       can fail with the error EINTR after the process is stopped by one of the  stop
       signals  and  then  resumed  via  SIGCONT.  This behavior is not sanctioned by
       POSIX.1, and doesn't occur on other systems.

       The Linux interfaces that display this behavior are:

           * "Input" socket interfaces, when a timeout (SO_RCVTIMEO) has been set  on
             the   socket   using  setsockopt(2):  accept(2),  recv(2),  recvfrom(2),
             recvmmsg(2) (also with a non-NULL timeout argument), and recvmsg(2).

           * "Output" socket interfaces, when a timeout (SO_RCVTIMEO) has been set on
             the  socket  using  setsockopt(2):  connect(2),  send(2), sendto(2), and
             sendmsg(2), if a send timeout (SO_SNDTIMEO) has been set.

           * epoll_wait(2), epoll_pwait(2).

           * semop(2), semtimedop(2).

           * sigtimedwait(2), sigwaitinfo(2).

           * read(2) from an inotify(7) file descriptor.

           * Linux  2.6.21  and  earlier:  futex(2)   FUTEX_WAIT,   sem_timedwait(3),
             sem_wait(3).

           * Linux 2.6.8 and earlier: msgrcv(2), msgsnd(2).

           * Linux 2.4 and earlier: nanosleep(2).

CONFORMING TO
       POSIX.1, except as noted.

SEE ALSO
       kill(1),  getrlimit(2),  kill(2),  killpg(2), restart_syscall(2), rt_sigqueue‐
       info(2),  setitimer(2),  setrlimit(2),  sgetmask(2),   sigaction(2),   sigalt‐
       stack(2),   signal(2),  signalfd(2),  sigpending(2),  sigprocmask(2),  sigsus‐
       pend(2),  sigwaitinfo(2),  abort(3),  bsd_signal(3),   longjmp(3),   raise(3),
       pthread_sigqueue(3),  sigqueue(3),  sigset(3),  sigsetops(3),  sigvec(3), sig‐
       wait(3), strsignal(3), sysv_signal(3), core(5), proc(5), nptl(7), pthreads(7),
       sigevent(7)

COLOPHON
       This  page is part of release 4.04 of the Linux man-pages project.  A descrip‐
       tion of the project, information about reporting bugs, and the latest  version
       of this page, can be found at http://www.kernel.org/doc/man-pages/.

Linux                                 2015-12-05                            SIGNAL(7)
chunli@ubuntu:~$



终端按键 够产生的信号:

ctrl +c SIGIN

ctrl +z SIGTSTP

ctrl +\ SIGQUIT

chunli@ubuntu:~/linux_c/信号$ cat main.c 
#include 
int main()
{
	while(1)
	{
		sleep(1);
	}
	
}



程序终止信号:ctrl +c SIGIN

chunli@ubuntu:~/linux_c/信号$ gcc main.c -o app &&  ./app

ctrl + c 发生终止信号
^C
chunli@ubuntu:~/linux_c/信号$


程序停止信号 ctrl +z SIGTSTP
chunli@ubuntu:~/linux_c/信号$ gcc main.c -o app &&  ./app

ctrl + z 发生停止信号相当于  20) SIGTSTP
^Z
[1]+  已停止               ./app
chunli@ubuntu:~/linux_c/信号$ bg 1
[1]+ ./app &
chunli@ubuntu:~/linux_c/信号$ 

可以看到这个程序在后台运行
chunli@ubuntu:~/linux_c/信号$ ps ajx
  PPID    PID   PGID    SID TTY       TPGID STAT   UID   TIME COMMAND
  6362   6455   6455   6362 pts/9      6456 S     1000   0:00 ./app

发送 SIGTSTP信号
chunli@ubuntu:~/linux_c/信号$ kill -20 6455
chunli@ubuntu:~/linux_c/信号$ jobs
[1]+  已停止               ./app


程序退出信号 ctrl +\ SIGQUIT
chunli@ubuntu:~/linux_c/信号$ gcc main.c -o app &&  ./app
^\退出 (核心已转储)


硬件产生信号

浮点数例外信号  CPU不能除0运算 8)SIGFPE

chunli@ubuntu:~/linux_c/信号$ cat main.c 
#include 
int main()
{
	int a = 5;
	int b = 0;
	a = a/b;
}
chunli@ubuntu:~/linux_c/信号$ gcc main.c -o app &&  ./app
浮点数例外 (核心已转储)
chunli@ubuntu:~/linux_c/信号$


访问非法内存,段错误 11)SIGSEGV信号,

chunli@ubuntu:~/linux_c/信号$ gcc main.c -o app &&  ./app
段错误 (核心已转储)
chunli@ubuntu:~/linux_c/信号$ cat main.c 
#include 
int main()
{
	char *p = "Hello World!";
	*p = 0;
}
chunli@ubuntu:~/linux_c/信号$ gcc main.c -o app &&  ./app
段错误 (核心已转储)
chunli@ubuntu:~/linux_c/信号$




kill() 函数

程序1 ,运行在后台

chunli@ubuntu:~/linux_c/信号$ cat while.c 
#include 
int main()
{
	while(1)
	{
		sleep(1);
	}
	
}

编译,放到后台执行
chunli@ubuntu:~/linux_c/信号$ gcc while.c -o while && ./while &
[1] 6829

chunli@ubuntu:~/linux_c/信号$ ps aux | grep while
chunli     6835  0.0  0.0   4224   648 pts/9    S    11:14   0:00 ./while

chunli@ubuntu:~/linux_c/信号$ ps ajx | grep while
  6829   6835   6829   6362 pts/9      6838 S     1000   0:00 ./while



程序2 ,kill函数

chunli@ubuntu:~/linux_c/信号$ cat main.c 
#include 
#include 
#include 
#include 
#include 

int main(int argc,char **argv ,char **env)
{
	if(argc < 3)
	{
		printf("请输入进程PID、信号\n");
		exit(1);
	}
	// int kill(pid_t pid, int sig);
	int ret = kill((pid_t)atoi(argv[1]),atoi(argv[2]));
	if(ret == -1)
	{
		perror("kill");
		exit(2);
	}
	return ret;
}
chunli@ubuntu:~/linux_c/信号$ gcc main.c -o app &&  ./app 
请输入进程PID、信号
chunli@ubuntu:~/linux_c/信号$


用函数,杀死这个进程

chunli@ubuntu:~/linux_c/信号$ gcc main.c -o app &&  ./app 6835 9
chunli@ubuntu:~/linux_c/信号$ -bash: 行 190:  6835 已杀死               ./while

[1]+  退出 137              gcc while.c -o while && ./while
chunli@ubuntu:~/linux_c/信号$


再试一次,发送段错误信号

chunli@ubuntu:~/linux_c/信号$ gcc while.c -o while && ./while &
[1] 6858
chunli@ubuntu:~/linux_c/信号$ gcc main.c -o app &&  ./app 6858 11
chunli@ubuntu:~/linux_c/信号$ 
[1]+  段错误               (核心已转储) gcc while.c -o while && ./while
chunli@ubuntu:~/linux_c/信号$


信号与权限

普通用户不可以越权操作杀死别人的信号

chunli@ubuntu:~/linux_c/信号$ ps aux | grep root|head -n 5
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root          1  0.0  0.6 119904  6184 ?        Ss   08:56   0:03 /sbin/init splash
root          2  0.0  0.0      0     0 ?        S    08:56   0:00 [kthreadd]
root          3  0.0  0.0      0     0 ?        S    08:56   0:00 [ksoftirqd/0]
root          5  0.0  0.0      0     0 ?        S<   08:56   0:00 [kworker/0:0H]
root          7  0.0  0.0      0     0 ?        S    08:56   0:01 [rcu_sched]
chunli@ubuntu:~/linux_c/信号$ kill -9 1
-bash: kill: (1) - 不允许的操作
chunli@ubuntu:~/linux_c/信号$



kill()函数的pid 与返回值

DESCRIPTION
       The kill() system call can be used to send any signal to any process group or process.
       If pid is positive, then signal sig is sent to the process with the ID specified by pid.
       If pid equals 0, then sig is sent to every process in the process group of the calling process.
       If pid equals -1, then sig is sent to every process for which the calling process has permission to send signals, except for process 1 (init), but see below.
       If pid is less than -1, then sig is sent to every process in the process group whose ID is -pid.
       If sig is 0, then no signal is sent, but error checking is still performed; this can be used to check for the existence of a process ID or process group ID.
       For  a  process to have permission to send a signal it must either be privileged (under Linux: have the CAP_KILL capability), or the real or effective user ID of
       the sending process must equal the real or saved set-user-ID of the target process.  In the case of SIGCONT it suffices when the sending and receiving  processes
       belong to the same session.  (Historically, the rules were different; see NOTES.)

RETURN VALUE
       On success (at least one signal was sent), zero is returned.  On error, -1 is returned, and errno is set appropriately.
       
pid > 0		sig发送给ID为pid的进程
pid == 0	sig发送给与发送进程同组的所有进程
pid < 0		sig发送给组ID为|-pid|的进程,并且发送进程具有向其发送信号的权限
pid == -1	sig发送给发送进程有权限向他们发送信号的系统上的所有进程

sig为0时,用于检测,特定为pid进程是否存在,如不存在,返回-1。



信号产生原因



1) SIGHUP:当用户退出shell时,由该shell启动的所有进程将收到这个信号,默认动作为终止进程

2)SIGINT:当用户按下了组合键时,用户终端向正在运行中的由该终端启动的程序发出此信号。默认动作为终止里程。

3)SIGQUIT:当用户按下组合键时产生该信号,用户终端向正在运行中的由该终端启动的程序发出些信号。默认动作为终止进程。

4)SIGILL:CPU检测到某进程执行了非法指令。默认动作为终止进程并产生core文件

5)SIGTRAP:该信号由断点指令或其他 trap指令产生。默认动作为终止里程 并产生core文件。

6) SIGABRT:调用abort函数时产生该信号。默认动作为终止进程并产生core文件。

7)SIGBUS:非法访问内存地址,包括内存对齐出错,默认动作为终止进程并产生core文件。

8)SIGFPE:在发生致命的运算错误时发出。不仅包括浮点运算错误,还包括溢出及除数为0等所有的算法错误。默认动作为终止进程并产生core文件。

9)SIGKILL:无条件终止进程。本信号不能被忽略,处理和阻塞。默认动作为终止进程。它向系统管理员提供了可以杀死任何进程的方法。

10)SIGUSE1:用户定义 的信号。即程序员可以在程序中定义并使用该信号。默认动作为终止进程。

11)SIGSEGV:指示进程进行了无效内存访问。默认动作为终止进程并产生core文件。

12)SIGUSR2:这是另外一个用户自定义信号 ,程序员可以在程序中定义 并使用该信号。默认动作为终止进程。1

13)SIGPIPE:Broken pipe向一个没有读端的管道写数据。默认动作为终止进程。

14) SIGALRM:定时器超时,超时的时间 由系统调用alarm设置。默认动作为终止进程。

15)SIGTERM:程序结束信号,与SIGKILL不同的是,该信号可以被阻塞和终止。通常用来要示程序正常退出。执行shell命令Kill时,缺省产生这个信号。默认动作为终止进程。

16)SIGCHLD:子进程结束时,父进程会收到这个信号。默认动作为忽略这个信号。

17)SIGCONT:停止进程的执行。信号不能被忽略,处理和阻塞。默认动作为终止进程。

18)SIGTTIN:后台进程读终端控制台。默认动作为暂停进程。

19)SIGTSTP:停止进程的运行。按下组合键时发出这个信号。默认动作为暂停进程。

21)SIGTTOU:该信号类似于SIGTTIN,在后台进程要向终端输出数据时发生。默认动作为暂停进程。

22)SIGURG:套接字上有紧急数据时,向当前正在运行的进程发出些信号,报告有紧急数据到达。如网络带外数据到达,默认动作为忽略该信号。

23)SIGXFSZ:进程执行时间超过了分配给该进程的CPU时间 ,系统产生该信号并发送给该进程。默认动作为终止进程。

24)SIGXFSZ:超过文件的最大长度设置。默认动作为终止进程。

25)SIGVTALRM:虚拟时钟超时时产生该信号。类似于SIGALRM,但是该信号只计算该进程占用CPU的使用时间。默认动作为终止进程。

26)SGIPROF:类似于SIGVTALRM,它不公包括该进程占用CPU时间还包括执行系统调用时间。默认动作为终止进程。

27)SIGWINCH:窗口变化大小时发出。默认动作为忽略该信号。

28)SIGIO:此信号向进程指示发出了一个异步IO事件。默认动作为忽略。

29)SIGPWR:关机。默认动作为终止进程。

30)SIGSYS:无效的系统调用。默认动作为终止进程并产生core文件。

31)SIGRTMIN~(64)SIGRTMAX:LINUX的实时信号,它们没有固定的含义(可以由用户自定义)。所有的实时信号的默认动作都为终止进程。



raise() abort()

kill函数或kill命令 不过,kill向调用者返回测试结果时,原来存在的被测试进程可能刚终止


自己给自己发信号

int raise(int sig)

自己终止

void abort(void)


alarm()定时器


某种软件条件已发生 定时器alarm到时,每个进程只有一个定时器

unsigned int alarm(unsigned int seconds)


计算 计算机的性能

chunli@ubuntu:~/linux_c/信号$ cat alarm.c 
#include 
#include 
int main(void)
{
	int counter;
	alarm(1);
	for(counter=0; 1; counter++)
		printf("counter=%d \n", counter);
	return 0;
}

countechunli@ubuntu:~/linux_c/信号$ gcc -o alarm alarm.c && ./alarm  >/tmp/alarm 
闹钟
chunli@ubuntu:~/linux_c/信号$ tail /tmp/alarm
counter=4763221 
counter=4763222 
counter=4763223 
counter=4763224 
counter=4763225 
counter=4763226 
counter=4763227 
counter=4763228 
counter=4763229 
counter=chunli@ubuntu:~/linux_c/信号$


收到信号的默认操作

Signal     Value     Action   Comment
──────────────────────────────────────────────────────────────────────
SIGHUP        1       Term    Hangup detected on controlling terminal or death of controlling process
SIGINT        2       Term    Interrupt from keyboard
SIGQUIT       3       Core    Quit from keyboard
SIGILL        4       Core    Illegal Instruction
SIGABRT       6       Core    Abort signal from abort(3)
SIGFPE        8       Core    Floating point exception
SIGKILL       9       Term    Kill signal
SIGSEGV      11       Core    Invalid memory reference
SIGPIPE      13       Term    Broken pipe: write to pipe with no readers
SIGALRM      14       Term    Timer signal from alarm(2)
SIGTERM      15       Term    Termination signal
SIGUSR1   30,10,16    Term    User-defined signal 1
SIGUSR2   31,12,17    Term    User-defined signal 2
SIGCHLD   20,17,18    Ign     Child stopped or terminated
SIGCONT   19,18,25    Cont    Continue if stopped
SIGSTOP   17,19,23    Stop    Stop process
SIGTSTP   18,20,24    Stop    Stop typed at terminal
SIGTTIN   21,21,26    Stop    Terminal input for background process
SIGTTOU   22,22,27    Stop    Terminal output for background process

The signals SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.



信号阻塞 屏蔽,,

Linux系统开发6 信号_第1张图片

chunli@ubuntu:~/linux_c/信号$ cat sigpromask.c 
#include 
#include 
#include 
void printsigset(const sigset_t *set)
{
	int i = 0;
	for(i = 1;i<32;i++)
	{
		if(sigismember(set,i) == 1)
		{
			putchar('1');
		}
		else
		{
			putchar('0');
		}
	}
	puts("");	//空行
}

int main(void)
{
	sigset_t s;
	sigset_t p;	//64位系统下有128个字节
	sigemptyset(&s);	//清空信号
	sigaddset(&s,SIGINT);	//添加一个信号,
	sigaddset(&s,SIGTSTP);	//添加一个信号,
	sigaddset(&s,SIGQUIT);	//添加一个信号,
	sigprocmask(SIG_BLOCK,&s,NULL);	//与原来的信号与操作,不要传出数据NULL,当然也可以接受
	int i = 10;
	while(i--)
	{
		sigpending(&p);
		printsigset(&p);
		sleep(1);
	}
	return 0;

}
chunli@ubuntu:~/linux_c/信号$ 


编译运行,
chunli@ubuntu:~/linux_c/信号$ gcc -o sig sigpromask.c && ./sig
0000000000000000000000000000000
^C0100000000000000000000000000000
^\0110000000000000000000000000000
0110000000000000000000000000000
0110000000000000000000000000000
^Z0110000000000000000100000000000
0110000000000000000100000000000
0110000000000000000100000000000
0110000000000000000100000000000
0110000000000000000100000000000
chunli@ubuntu:~/linux_c/信号$




解除信号的阻塞

chunli@ubuntu:~/linux_c/信号$ cat sigpromask.c 
#include 
#include 
#include 
void printsigset(const sigset_t *set)
{
	int i = 0;
	for(i = 1;i<32;i++)
	{
		if(sigismember(set,i) == 1)
		{
			putchar('1');
		}
		else
		{
			putchar('0');
		}
	}
	puts("");	//空行
}

int main(void)
{
	sigset_t s;
	sigset_t p;	//64位系统下有128个字节
	sigemptyset(&s);	//清空信号
	sigaddset(&s,SIGINT);	//添加一个信号,
	sigaddset(&s,SIGTSTP);	//添加一个信号,
	sigaddset(&s,SIGQUIT);	//添加一个信号,
	sigprocmask(SIG_BLOCK,&s,NULL);	//与原来的信号与操作,不要传出数据NULL,当然也可以接受
	//完成之后,ctrl+c信号就会被阻塞
	int i = 0;
	while(i++ <100)
	{
		sleep(1);
		sigpending(&p);	//取出信号集信息
		printsigset(&p);//打印出来
		if(i == 5)
		{
			sigdelset(&s,SIGINT);	//标记SIGINT信号位删除,相当于置0
			sigprocmask(SIG_UNBLOCK,&s,NULL);	//相当于标记为1的就解除阻塞
			//那么就只剩 SIGINT 信号是阻塞的了
		}
	}
	return 0;
}
编译运行:
5秒后恢复 crtl+\ 的退出功能
chunli@ubuntu:~/linux_c/信号$ gcc -o sig sigpromask.c && ./sig
^C^Z0100000000000000000100000000000
^\0110000000000000000100000000000
0110000000000000000100000000000
0110000000000000000100000000000
0110000000000000000100000000000
退出 (核心已转储)
chunli@ubuntu:~/linux_c/信号$ 

但是无论ctrl+c 多少次,都不能终止程序
chunli@ubuntu:~/linux_c/信号$ gcc -o sig sigpromask.c && ./sig
^C^C0100000000000000000000000000000
^C^C0100000000000000000000000000000
^C^C^C^C^C0100000000000000000000000000000
0100000000000000000000000000000
^C^C^C^C0100000000000000000000000000000
^C^C0100000000000000000000000000000
^C^C0100000000000000000000000000000
^C^C^C^C^C0100000000000000000000000000000
^C0100000000000000000000000000000
0100000000000000000000000000000
0100000000000000000000000000000
^\退出 (核心已转储)
chunli@ubuntu:~/linux_c/信号$



信号捕捉 sa_handler 自定义函数 方式捕捉crtl + c

chunli@ubuntu:~/linux_c/信号$ cat sigaction.c 
#include 
#include 
#include 
//	man 2 sigaction
//	struct sigaction {
//		void     (*sa_handler)(int);
//		void     (*sa_sigaction)(int, siginfo_t *, void *);
//		sigset_t   sa_mask;
//		int        sa_flags;
//		void     (*sa_restorer)(void);
//	};


void do_sig(int num)
{
	printf("\n捕捉到的信号是SIG = %d\n",num);
}
int main(void)
{
	struct sigaction act;	
	act.sa_handler  = do_sig;	//结构体函数指针,指向自定义的函数
	sigemptyset(&act.sa_mask);	//清空信号集
	//act.sa_flags  = 0;
	sigaction(SIGINT,&act,NULL);	//捕捉
	int i = 1;
	while(i++)
	{
		printf("Hello while\n");
		sleep(1);
	}
	return 0;
}
chunli@ubuntu:~/linux_c/信号$ gcc -o action sigaction.c && ./action
Hello while
Hello while
Hello while
^C
捕捉到的信号是SIG = 2
Hello while
Hello while
^C
捕捉到的信号是SIG = 2
Hello while
^\退出 (核心已转储)
chunli@ubuntu:~/linux_c/信号$



sa_handler 设定为默认 默认处理ctrl+c

chunli@ubuntu:~/linux_c/信号$ cat sigaction.c 
#include 
#include 
#include 
//	man 2 sigaction
//	struct sigaction {
//		void     (*sa_handler)(int);
//		void     (*sa_sigaction)(int, siginfo_t *, void *);
//		sigset_t   sa_mask;
//		int        sa_flags;
//		void     (*sa_restorer)(void);
//	};

//	sa_handler 函数指针
//	sa_handler specifies the action to be associated with signum and 
//	may be SIG_DFL for the default action, SIG_IGN to ignore this signal, 
//	or a pointer to  a  signal handling function.  
//	This function receives the signal number as its only argument.


void do_sig(int num)
{
	printf("\n捕捉到的信号是SIG = %d\n",num);
}
int main(void)
{
	struct sigaction act;	
	//act.sa_handler  = do_sig;	//结构体函数指针,指向自定义的函数
	act.sa_handler  = SIG_DFL;
	sigemptyset(&act.sa_mask);	//清空信号集
	//act.sa_flags  = 0;
	sigaction(SIGINT,&act,NULL);	//捕捉
	int i = 1;
	while(i++)
	{
		printf("Hello while\n");
		sleep(1);
	}
	return 0;
}
chunli@ubuntu:~/linux_c/信号$ 
编译运行:ctrl+c终止有效果
chunli@ubuntu:~/linux_c/信号$ gcc -o action sigaction.c && ./action
Hello while
Hello while
Hello while
^C



sa_handler 设定为忽略 ctrl+c

chunli@ubuntu:~/linux_c/信号$ cat sigaction.c 
#include 
#include 
#include 
//	man 2 sigaction
//	struct sigaction {
//		void     (*sa_handler)(int);
//		void     (*sa_sigaction)(int, siginfo_t *, void *);
//		sigset_t   sa_mask;
//		int        sa_flags;
//		void     (*sa_restorer)(void);
//	};

//	sa_handler 函数指针
//	sa_handler specifies the action to be associated with signum and 
//	may be SIG_DFL for the default action, SIG_IGN to ignore this signal, 
//	or a pointer to  a  signal handling function.  
//	This function receives the signal number as its only argument.


void do_sig(int num)
{
	printf("\n捕捉到的信号是SIG = %d\n",num);
}
int main(void)
{
	struct sigaction act;	
	//act.sa_handler  = do_sig;	//结构体函数指针,指向自定义的函数
	//act.sa_handler  = SIG_DFL;
	act.sa_handler  = SIG_IGN;
	sigemptyset(&act.sa_mask);	//清空信号集
	//act.sa_flags  = 0;
	sigaction(SIGINT,&act,NULL);	//捕捉
	int i = 1;
	while(i++)
	{
		printf("Hello while\n");
		sleep(1);
	}
	return 0;
}
编译运行:确实忽略了ctrl+c
chunli@ubuntu:~/linux_c/信号$ gcc -o action sigaction.c && ./action
Hello while
^C^CHello while
^C^C^CHello while
^CHello while
^CHello while
^\退出 (核心已转储)
chunli@ubuntu:~/linux_c/信号$


处理信号的时候再来一次信号,并不会嵌套,执行完了再一次执行信号函数

chunli@ubuntu:~/linux_c/信号$ cat sigaction.c 
#include 
#include 
#include 
//	man 2 sigaction
//	struct sigaction {
//		void     (*sa_handler)(int);
//		void     (*sa_sigaction)(int, siginfo_t *, void *);
//		sigset_t   sa_mask;
//		int        sa_flags;
//		void     (*sa_restorer)(void);
//	};

//	sa_handler 函数指针
//	sa_handler specifies the action to be associated with signum and 
//	may be SIG_DFL for the default action, SIG_IGN to ignore this signal, 
//	or a pointer to  a  signal handling function.  
//	This function receives the signal number as its only argument.


void do_sig(int num)
{
	printf("Hello SIG\n");
	int i = 2;
	while(i--)
	{
		sleep(1);
		printf("\n捕捉到的信号是SIG = %d\n",num);
	}
	printf("SIG while end\n");
}
int main(void)
{
	struct sigaction act;	
	act.sa_handler  = do_sig;	//结构体函数指针,指向自定义的函数
	//act.sa_handler  = SIG_DFL;
	//act.sa_handler  = SIG_IGN;
	sigemptyset(&act.sa_mask);	//清空信号集
	//act.sa_flags  = 0;
	sigaction(SIGINT,&act,NULL);	//捕捉
	int i = 1;
	while(i++)
	{
		printf("Hello while\n");
		sleep(1);
	}
	return 0;
}
chunli@ubuntu:~/linux_c/信号$ 




chunli@ubuntu:~/linux_c/信号$ gcc -o action sigaction.c && ./action
Hello while
^CHello SIG
捕捉到的信号是SIG = 2
捕捉到的信号是SIG = 2
SIG while end
Hello while
^CHello SIG
捕捉到的信号是SIG = 2
捕捉到的信号是SIG = 2
SIG while end
Hello SIG
Hello while
^\退出 (核心已转储)
chunli@ubuntu:~/linux_c/信号$


sigaddset() 当进入信号函数的调用时屏蔽ctrl+\

退出信号函数的调用后,ctrl+\ 继续默认

1,没有屏蔽 ctrl+\ 信号的时候,执行信号函数会响应ctrl+\操作

chunli@ubuntu:~/linux_c/信号$ cat sigaction.c 
#include 
#include 
#include 
//	man 2 sigaction
//	struct sigaction {
//		void     (*sa_handler)(int);
//		void     (*sa_sigaction)(int, siginfo_t *, void *);
//		sigset_t   sa_mask;
//		int        sa_flags;
//		void     (*sa_restorer)(void);
//	};

//	sa_handler 函数指针
//	sa_handler specifies the action to be associated with signum and 
//	may be SIG_DFL for the default action, SIG_IGN to ignore this signal, 
//	or a pointer to  a  signal handling function.  
//	This function receives the signal number as its only argument.


void do_sig(int num)
{
	printf("Hello SIG\n");
	int i = 5;
	while(i--)
	{
		sleep(1);
		printf("\n捕捉到的信号是SIG = %d\n",num);
	}
	printf("SIG while end\n");
}
int main(void)
{
	struct sigaction act;	
	act.sa_handler  = do_sig;	//结构体函数指针,指向自定义的函数
	//act.sa_handler  = SIG_DFL;
	//act.sa_handler  = SIG_IGN;
	sigemptyset(&act.sa_mask);	//清空信号集
	//sigaddset(&act.sa_mask,SIGQUIT);//当进入信号函数的调用时屏蔽ctrl+\
	act.sa_flags  = 0;
	sigaction(SIGINT,&act,NULL);	//捕捉
	int i = 1;
	while(i++)
	{
		printf("Hello while\n");
		sleep(1);
	}
	return 0;
}
chunli@ubuntu:~/linux_c/信号$ 
编译运行:
chunli@ubuntu:~/linux_c/信号$ gcc -o action sigaction.c && ./action
Hello while
^CHello SIG
^\退出 (核心已转储)
chunli@ubuntu:~/linux_c/信号$



2,屏蔽 ctrl+\ 信号的时候,执行信号函数不会响应ctrl+\,等运行结束后才会响应

chunli@ubuntu:~/linux_c/信号$ cat sigaction.c 
#include 
#include 
#include 
//	man 2 sigaction
//	struct sigaction {
//		void     (*sa_handler)(int);
//		void     (*sa_sigaction)(int, siginfo_t *, void *);
//		sigset_t   sa_mask;
//		int        sa_flags;
//		void     (*sa_restorer)(void);
//	};

//	sa_handler 函数指针
//	sa_handler specifies the action to be associated with signum and 
//	may be SIG_DFL for the default action, SIG_IGN to ignore this signal, 
//	or a pointer to  a  signal handling function.  
//	This function receives the signal number as its only argument.


void do_sig(int num)
{
	printf("Hello SIG\n");
	int i = 5;
	while(i--)
	{
		sleep(1);
		printf("\n捕捉到的信号是SIG = %d\n",num);
	}
	printf("SIG while end\n");
}
int main(void)
{
	struct sigaction act;	
	act.sa_handler  = do_sig;	//结构体函数指针,指向自定义的函数
	//act.sa_handler  = SIG_DFL;
	//act.sa_handler  = SIG_IGN;
	sigemptyset(&act.sa_mask);	//清空信号集
	sigaddset(&act.sa_mask,SIGQUIT);//当进入信号函数的调用时屏蔽ctrl+\
	act.sa_flags  = 0;
	sigaction(SIGINT,&act,NULL);	//捕捉
	int i = 1;
	while(i++)
	{
		printf("Hello while\n");
		sleep(1);
	}
	return 0;
}
chunli@ubuntu:~/linux_c/信号$ gcc -o action sigaction.c && ./action
Hello while
Hello while
^CHello SIG
^\
捕捉到的信号是SIG = 2

捕捉到的信号是SIG = 2

捕捉到的信号是SIG = 2

捕捉到的信号是SIG = 2

捕捉到的信号是SIG = 2
SIG while end
退出 (核心已转储)
chunli@ubuntu:~/linux_c/信号$


SIGUSR1用户自定义信号

chunli@ubuntu:~/linux_c/信号$ cat sigaction.c 
#include 
#include 
#include 
//	man 2 sigaction
//	struct sigaction {
//		void     (*sa_handler)(int);
//		void     (*sa_sigaction)(int, siginfo_t *, void *);
//		sigset_t   sa_mask;
//		int        sa_flags;
//		void     (*sa_restorer)(void);
//	};

//	sa_handler 函数指针
//	sa_handler specifies the action to be associated with signum and 
//	may be SIG_DFL for the default action, SIG_IGN to ignore this signal, 
//	or a pointer to  a  signal handling function.  
//	This function receives the signal number as its only argument.


void do_sig(int num)
{
	printf("Hello SIG %d \n",num);
}
int main(void)
{
	struct sigaction act;	
	act.sa_handler  = do_sig;	//结构体函数指针,指向自定义的函数
	act.sa_flags  = 0;
	sigaction(SIGUSR1,&act,NULL);	//捕捉 SIGUSR1自定义信号
	int i = 1;
	while(i++)
	{
		printf("Hello while\n");
		sleep(1);
	}
	return 0;
}
编译运行:
chunli@ubuntu:~/linux_c/信号$ gcc -o action sigaction.c && ./action 
Hello while
Hello while
Hello SIG 10 
Hello while
Hello while
^C

一边发kill信号
chunli@ubuntu:~/linux_c/信号$ ps aux | head -n 1 &&  ps aux | tail  -n 4 | head -n 1
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
chunli     8136  0.0  0.0   4356   688 pts/9    S+   15:57   0:00 ./action
chunli@ubuntu:~/linux_c/信号$ kill -SIGUSR1 8136


C 标准库函数,信号捕捉函数

chunli@ubuntu:~/linux_c/信号$ cat sigaction.c 
#include 
#include 
#include 

//C 标准库函数,信号捕捉
void do_sig(int n)
{
	printf("Hello SIG %d \n",n);
}
int main(void)
{
	signal(SIGINT,do_sig);
	while(1)
	{
		printf("well well \n");
		sleep(1);
	}
	return 0;
}
chunli@ubuntu:~/linux_c/信号$ gcc -o action sigaction.c && ./action 
well well 
well well 
^CHello SIG 2 
well well 
well well 
well well 
^CHello SIG 2 
well well 
well well 
^\退出 (核心已转储)
chunli@ubuntu:~/linux_c/信号$





system函数,集成与fork() exit() wait()一体的函数 

chunli@ubuntu:~/linux_c/信号$ cat system.c 
#include 
#include 
int main(int argc,char *argv[])
{
	system("cat /etc/fstab");
	return 0;
}
编译运行:
chunli@ubuntu:~/linux_c/信号$ gcc system.c && ./a.out
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
#                
# / was on /dev/sda1 during installation
UUID=59de25c8-6fc2-4346-b1ef-4cbbb3751e53 /               ext4    errors=remount-ro 0       1
# swap was on /dev/sda5 during installation
UUID=4ac1879d-5732-4436-aeda-39a1ba7adf0c none            swap    sw              0       0
chunli@ubuntu:~/linux_c/信号$



可重入 不可重入函数

当在执行函数A时,发生信号处理函数正好也是函数A,如果是不可重入函数,那就受影响


字符串分割,链表插入等默认都是不可重入函数


strtok_r的可重入函数

chunli@ubuntu:~/linux_c/信号$ cat strtok_r.c 
#include 
#include 
int main(void)
{
	char str[] = "Hello China Linux guy!";
	char *save = str;
	char *p = NULL;
	while( (p = strtok_r(save," ",&save)) != NULL )
	{
		printf("%s \n",p);
	}
	return 0;
}
chunli@ubuntu:~/linux_c/信号$ gcc strtok_r.c && ./a.out
Hello 
China 
Linux 
guy! 
chunli@ubuntu:~/linux_c/信号$


Linux下的可重入安全函数

  Async-signal-safe functions
       A signal handler function must be very careful, since processing elsewhere may be interrupted at some arbitrary point in the execution of the program.  POSIX has
       the  concept of "safe function".  If a signal interrupts the execution of an unsafe function, and handler calls an unsafe function, then the behavior of the pro‐
       gram is undefined.

       POSIX.1-2004 (also known as POSIX.1-2001 Technical Corrigendum 2) requires an implementation to guarantee that the  following  functions  can  be  safely  called
       inside a signal handler:

           _Exit()
           _exit()
           abort()
           accept()
           access()
           aio_error()
           aio_return()
           aio_suspend()
           alarm()
           bind()
           cfgetispeed()
           cfgetospeed()
           cfsetispeed()
           cfsetospeed()
           chdir()
           chmod()
           chown()
           clock_gettime()
           close()
           connect()
           creat()
           dup()
           dup2()
           execle()
           execve()
           fchmod()
           fchown()
           fcntl()
           fdatasync()
           fork()
           fpathconf()
           fstat()
           fsync()
           ftruncate()
           getegid()
           geteuid()
           getgid()
           getgroups()
           getpeername()
           getpgrp()
           getpid()
           getppid()
           getsockname()
           getsockopt()
           getuid()
           kill()
           link()
           listen()
           lseek()
           lstat()
           mkdir()
           mkfifo()
           open()
           pathconf()
           pause()
           pipe()
           poll()
           posix_trace_event()
           pselect()
           raise()
           read()
           readlink()
           recv()
           recvfrom()
           recvmsg()
           rename()
           rmdir()
           select()
           sem_post()
           send()
           sendmsg()
           sendto()
           setgid()
           setpgid()
           setsid()
           setsockopt()
           setuid()
           shutdown()
           sigaction()
           sigaddset()
           sigdelset()
           sigemptyset()
           sigfillset()
           sigismember()
           signal()
           sigpause()
           sigpending()
           sigprocmask()
           sigqueue()
           sigset()
           sigsuspend()
           sleep()
           sockatmark()
           socket()
           socketpair()
           stat()
           symlink()
           sysconf()
           tcdrain()
           tcflow()
           tcflush()
           tcgetattr()
           tcgetpgrp()
           tcsendbreak()
           tcsetattr()
           tcsetpgrp()
           time()
           timer_getoverrun()
           timer_gettime()
           timer_settime()
           times()
           umask()
           uname()
           unlink()
           utime()
           wait()
           waitpid()
           write()

       POSIX.1-2008 removes fpathconf(), pathconf(), and sysconf() from the above list, and adds the following functions:

           execl()
           execv()
           faccessat()
           fchmodat()
           fchownat()
           fexecve()
           fstatat()
           futimens()
           linkat()
           mkdirat()
           mkfifoat()
           mknod()
           mknodat()
           openat()
           readlinkat()
           renameat()
           symlinkat()
           unlinkat()
           utimensat()
           utimes()

       POSIX.1-2008 Technical Corrigendum 1 (2013) adds the following functions:

           fchdir()
           pthread_kill()
           pthread_self()
           pthread_sigmask()

	   
	   	


pause()系统挂起,等待信号的来临

chunli@ubuntu:~/linux_c/信号$ cat pause.c 
#include 
#include 
#include 
#include 
void do_sig(int n)
{
	printf("sig = %d\n",n);
}
int main(void)
{
	struct sigaction act;
	act.sa_handler = do_sig;
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	sigaction(SIGUSR1,&act,NULL);
	

	pause();
	printf("I'm OK!\n");
	return 0;
}
chunli@ubuntu:~/linux_c/信号$ 

编译运行:
chunli@ubuntu:~/linux_c/信号$ gcc pause.c && ./a.out
sig = 10
I'm OK!
chunli@ubuntu:~/linux_c/信号$ 

发送信号:
chunli@ubuntu:~/linux_c/信号$ ps aux | head -n 1 &&  ps aux | tail  -n 4 | head -n 1
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
chunli     8522  0.0  0.0   4224   728 pts/9    S+   17:14   0:00 ./a.out
chunli@ubuntu:~/linux_c/信号$ kill -SIGUSR1 8522



pause()系统挂起,如果是忽略操作就忽略

chunli@ubuntu:~/linux_c/信号$ cat pause.c 
#include 
#include 
#include 
#include 
void do_sig(int n)
{
	printf("sig = %d\n",n);
}
int main(void)
{
	struct sigaction act;
	//act.sa_handler = do_sig;
	act.sa_handler = SIG_IGN;
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	sigaction(SIGUSR1,&act,NULL);
	

	pause();
	printf("I'm OK!\n");
	return 0;
}

编译运行:
chunli@ubuntu:~/linux_c/信号$ gcc pause.c && ./a.out

发送信号
chunli@ubuntu:~/linux_c/信号$ ps aux | head -n 1 &&  ps aux | tail  -n 4 | head -n 1
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
chunli     8557  0.0  0.0   4224   652 pts/9    S+   17:18   0:00 ./a.out
chunli@ubuntu:~/linux_c/信号$ kill -SIGUSR1 8557
chunli@ubuntu:~/linux_c/信号$



利用pause() 与 信号 实现my_sleep()函数

#include 
#include 
#include 
#include 
#include 

void do_sig(int n)
{
	//空函数
}
void my_sleep(int n)
{
	signal(SIGALRM,do_sig);
	alarm(n);
	pause();
}
int main(void)
{
	printf("%ld\n",time(NULL));
	my_sleep(5);
	printf("%ld\n",time(NULL));
	return 0;
}
chunli@ubuntu:~/linux_c/信号$ gcc pause.c && ./a.out
1470908043
1470908048
chunli@ubuntu:~/linux_c/信号$




my_sleep()函数 时序竞态问题

执行完alarm(n)函数后,CPU被优先级高的进程夺走

如果n秒内此进程没有被CPU调度,一旦错过alarm信号,将永远挂起了


my_sleep增强 sigsuspend避免了时序竞争 

chunli@ubuntu:~/linux_c/信号$ cat pause.c 
#include 
#include 
#include 
#include 
#include 

void sig_alrm(int n)
{
	//do nothing 
}
//sigsuspend避免了时序竞争 sleep增强
unsigned int my_sleep(int n)
{
	struct sigaction newact;	
	struct sigaction oldact;	
	sigset_t newmask;
	sigset_t oldmask;
	sigset_t suspmask;
	unsigned int unslept;
	newact.sa_handler = sig_alrm;
	sigemptyset(&newact.sa_mask);
	newact.sa_flags = 0;
	sigaction(SIGALRM,&newact,&oldact);
	sigemptyset(&newmask);
	sigaddset(&newmask,SIGALRM);
	sigprocmask(SIG_BLOCK,&newmask,&oldmask);
	alarm(n);
	suspmask = oldmask;
	sigdelset(&suspmask,SIGALRM);
	sigsuspend(&suspmask);
	unslept = alarm(0);
	sigprocmask(SIG_SETMASK,&oldmask,NULL);
	return unslept;
}
int main(void)
{
	printf("%ld\n",time(NULL));
	my_sleep(5);
	printf("%ld\n",time(NULL));
	return 0;
}
chunli@ubuntu:~/linux_c/信号$ gcc pause.c && ./a.out
1470911330
1470911335
chunli@ubuntu:~/linux_c/信号$


什么是sig_atomic_t数据类型 


当把变量声明为该类型会保证该变量在使用或赋值时, 

无论是在32位还是64位的机器上都能保证操作是原子的, 它会根据机器的类型自动适应。

这个类型是定义在signal.h文件中。下面来说说这个类型。

在处理信号(signal)的时候,有时对于一些变量的访问希望不会被中断,

无论是硬件中断还是软件中断,这就要求访问或改变这些变量需要在计算机的一条指令内完成。

通常情况下,int类型的变量通常是原子访问的,也可以认为 sig_atomic_t就是int类型的数据,

因为对这些变量要求一条指令完成,所以sig_atomic_t不可能是结构体,只会是数字类型。

chunli@ubuntu:~/linux_c/信号$ uname -rm
4.4.0-34-generic x86_64


chunli@ubuntu:~/linux_c/信号$ cat long_long.c 
#include 
#include 
int main()
{
	printf("int = %ld \n",sizeof(int));
	printf("long = %ld \n",sizeof(long ));
	printf("long long = %ld \n",sizeof(long long ));
	printf("double = %ld \n",sizeof(double));
	printf("char* = %ld \n",sizeof(char *));
	printf("sig_atomic_t= %ld \n",sizeof(sig_atomic_t));
	

}
chunli@ubuntu:~/linux_c/信号$ gcc long_long.c && ./a.out 
int = 4 
long = 8 
long long = 8 
double = 8 
char* = 8 
sig_atomic_t= 4 
chunli@ubuntu:~/linux_c/信号$


SIGCHLD 信号产生的条件

1 子进程终止时

2 子进程接收到SIGSTOP信号停止时

3 子进程处在停止态,接受到SIGCONT后唤醒时


可以看出[默认是忽略子进程发过来的信号]:

chunli@ubuntu:~$ man 7  signal
Signal     Value     Action   Comment
──────────────────────────────────────────────────────────────────────
SIGHUP        1       Term    Hangup detected on controlling terminal
			     or death of controlling process
SIGINT        2       Term    Interrupt from keyboard
SIGQUIT       3       Core    Quit from keyboard
SIGILL        4       Core    Illegal Instruction
SIGABRT       6       Core    Abort signal from abort(3)
SIGFPE        8       Core    Floating point exception
SIGKILL       9       Term    Kill signal
SIGSEGV      11       Core    Invalid memory reference
SIGPIPE      13       Term    Broken pipe: write to pipe with no readers
SIGALRM      14       Term    Timer signal from alarm(2)
SIGTERM      15       Term    Termination signal
SIGUSR1   30,10,16    Term    User-defined signal 1
SIGUSR2   31,12,17    Term    User-defined signal 2
SIGCHLD   20,17,18    Ign     Child stopped or terminated
SIGCONT   19,18,25    Cont    Continue if stopped
SIGSTOP   17,19,23    Stop    Stop process
SIGTSTP   18,20,24    Stop    Stop typed at terminal
SIGTTIN   21,21,26    Stop    Terminal input for background process


用信号回收子进程

chunli@ubuntu:~/linux_c/信号$ cat child.c 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
void sys_err(char *str)
{
	perror(str);
	exit(1);
}
void do_sig_child(int signo)
{
	int status;
	pid_t pid;
	while ((pid = waitpid(0, &status, WNOHANG)) > 0) 
	{
		if (WIFEXITED(status))
			printf("child %d exit %d\n", pid, WEXITSTATUS(status));
		else if (WIFSIGNALED(status))
			printf("child %d cancel signal %d\n", pid, WTERMSIG(status));
	}
}

int main(void)
{
	pid_t pid;
	int i;
	//阻塞SIGCHLD
	for (i = 0; i < 10; i++) 
	{

		if ((pid = fork()) == 0)
			break;
		else if (pid < 0)
			sys_err("fork");
	}
	if (pid == 0) 
	{
		int n = 5;
		while (n--) 
		{
			printf("child ID %d\n", getpid());
			sleep(1);
		}
		return i;	//每个子进程的i是不一样的
	}
	else if (pid > 0) 
	{
		//先设置捕捉
		//再解除对SIGCHLD的阻塞
		struct sigaction act;
		act.sa_handler = do_sig_child;
		sigemptyset(&act.sa_mask);
		act.sa_flags = 0;
		sigaction(SIGCHLD, &act, NULL);
		int n = 10;
		while (n--) 
		{
			printf("Parent ID %d\n", getpid());
			sleep(1);
		}
	}
	return 0;
}

1,正常编译运行:
chunli@ubuntu:~/linux_c/信号$ gcc child.c && ./a.out 
child ID 5413
child ID 5414
child ID 5415
child ID 5418
child ID 5422
child ID 5421
child ID 5420
child ID 5419
Parent ID 5412
child ID 5416
child ID 5417
child ID 5413
child ID 5415
child ID 5414
Parent ID 5412
child ID 5417
child ID 5416
child ID 5421
child ID 5420
child ID 5418
child ID 5419
child ID 5422
child ID 5415
child ID 5413
child ID 5414
child ID 5417
child ID 5416
child ID 5421
child ID 5420
child ID 5419
child ID 5418
child ID 5422
Parent ID 5412
child ID 5415
child ID 5422
child ID 5421
child ID 5420
child ID 5419
child ID 5418
Parent ID 5412
child ID 5416
child ID 5417
child ID 5413
child ID 5414
child ID 5422
child ID 5421
child ID 5420
child ID 5418
child ID 5419
Parent ID 5412
child ID 5416
child ID 5417
child ID 5415
child ID 5413
child ID 5414
child 5415 exit 2
child 5416 exit 3
child 5418 exit 5
child 5419 exit 6
child 5420 exit 7
child 5417 exit 4
child 5421 exit 8
child 5422 exit 9
Parent ID 5412
child 5413 exit 0
Parent ID 5412
child 5414 exit 1
Parent ID 5412
Parent ID 5412
Parent ID 5412
chunli@ubuntu:~/linux_c/信号$ 


2,手动kill子进程,编译运行:
chunli@ubuntu:~/linux_c/信号$ gcc child.c && ./a.out 
child ID 5664
child ID 5666
child ID 5667
child ID 5668
child ID 5669
Parent ID 5663
child ID 5671
child ID 5672
child ID 5673
child ID 5670
child ID 5665
child ID 5664
child ID 5666
child ID 5668
child ID 5667
child ID 5669
Parent ID 5663
child ID 5670
child ID 5672
child ID 5673
child ID 5671
child ID 5665
child 5673 cancel signal 9
Parent ID 5663
child ID 5664
child ID 5666
child ID 5667
child ID 5668
child ID 5669
child ID 5672
child ID 5671
child ID 5670
child ID 5665
child 5672 cancel signal 9
Parent ID 5663
child 5671 cancel signal 9
Parent ID 5663
child ID 5664
child ID 5666
child ID 5668
child ID 5669
child ID 5667
child ID 5665
child ID 5670
child 5669 cancel signal 9
Parent ID 5663
child 5670 cancel signal 9
Parent ID 5663
child 5668 cancel signal 9
Parent ID 5663
child ID 5664
child ID 5666
child ID 5667
child ID 5665
child 5667 cancel signal 9
Parent ID 5663
child 5664 exit 0
Parent ID 5663
child 5665 exit 1
child 5666 exit 2

chunli@ubuntu:~/linux_c/信号$ 
chunli@ubuntu:~$ kill -9 `ps aux| grep a.out | awk '{print $2}'|tail -n 2|head -n 1`
chunli@ubuntu:~$ kill -9 `ps aux| grep a.out | awk '{print $2}'|tail -n 2|head -n 1`
chunli@ubuntu:~$ kill -9 `ps aux| grep a.out | awk '{print $2}'|tail -n 2|head -n 1`
chunli@ubuntu:~$ kill -9 `ps aux| grep a.out | awk '{print $2}'|tail -n 2|head -n 1`
chunli@ubuntu:~$ kill -9 `ps aux| grep a.out | awk '{print $2}'|tail -n 2|head -n 1`
chunli@ubuntu:~$ kill -9 `ps aux| grep a.out | awk '{print $2}'|tail -n 2|head -n 1`
chunli@ubuntu:~$ kill -9 `ps aux| grep a.out | awk '{print $2}'|tail -n 2|head -n 1`
-bash: kill: (5718) - 没有那个进程
chunli@ubuntu:~$




作业:

1.当进程处理SIGINT信号时,临时阻塞SIGQUIT信号。 2.进程间利用信号传参,来控制

数据同步,如两个进程交叉报数。