Sunday, October 12, 2014

Unix Prog: sigaction function(1)

1. System Definition:

 ubuntu@ip-172-31-23-227:~$ less /usr/include/signal.h  
 ......  
 /* Get and/or set the action for signal SIG. */  
 extern int sigaction (int __sig, const struct sigaction *__restrict __act,  
            struct sigaction *__restrict __oact) __THROW;  
 ......  
 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/bits/sigaction.h  
 ......  
 /* Structure describing the action to be taken when a signal arrives. */  
 struct sigaction  
  {  
   /* Signal handler. */  
 #ifdef __USE_POSIX199309  
   union  
    {  
     /* Used if SA_SIGINFO is not set. */  
     __sighandler_t sa_handler;  
     /* Used if SA_SIGINFO is set. */  
     void (*sa_sigaction) (int, siginfo_t *, void *);  
    }  
   __sigaction_handler;  
 # define sa_handler   __sigaction_handler.sa_handler  
 # define sa_sigaction  __sigaction_handler.sa_sigaction  
 #else  
   __sighandler_t sa_handler;  
 #endif  
   
   /* Additional set of signals to be blocked. */  
   __sigset_t sa_mask;  
   
   /* Special flags. */  
   int sa_flags;  
   
   /* Restore handler. */  
   void (*sa_restorer) (void);  
  };  
 ......  

For system call, sigaction. First argument is specifying the signal we want to handle, second argument describes action we want to take for specified signal. If third argument is not null, the current struct sigaction is populated over there.

Inside struct sigaction:
1) sa_handler specify the function address who point to the handler
2) sa_sigaction does the same thing, but it uses different signature to provide more information of the signal, this is needed if SA_SIGINFO is used on sa_flags. And siginfo_t provide more information about the signal. First argument of sa_sigaction is signal number, and third argument is pointer which can be converted to struct ucontext_t to identify the process context at the time of signal delivery.
Also, user could only use one of "sa_handler, sa_sigaction".

3) sa_mask indicates additional signals which is masked during the execution of this signal handler, after the execution is over, masked signals will be reset. This helps avoid other signals interrupt current execution of signal handler.
4) sa_flags specify the behavior details of the signal.

List of sa_flags supported in current system:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/bits/sigaction.h  
 .......  
 /* Bits in `sa_flags'. */  
 #define SA_NOCLDSTOP 1     /* Don't send SIGCHLD when children stop. */  
 #define SA_NOCLDWAIT 2     /* Don't create zombie on child death. */  
 #define SA_SIGINFO  4     /* Invoke signal-catching function with  
                   three arguments instead of one. */  
 #if defined __USE_UNIX98 || defined __USE_MISC  
 # define SA_ONSTACK  0x08000000 /* Use signal stack by using `sa_restorer'. */  
 #endif  
 #if defined __USE_UNIX98 || defined __USE_MISC || defined __USE_XOPEN2K8  
 # define SA_RESTART  0x10000000 /* Restart syscall on signal return. */  
 # define SA_NODEFER  0x40000000 /* Don't automatically block the signal when  
                   its handler is being executed. */  
 # define SA_RESETHAND 0x80000000 /* Reset to SIG_DFL on entry to handler. */  
 #endif  
 #ifdef __USE_MISC  
 # define SA_INTERRUPT 0x20000000 /* Historical no-op. */  
   
 /* Some aliases for the SA_ constants. */  
 # define SA_NOMASK  SA_NODEFER  
 # define SA_ONESHOT  SA_RESETHAND  
 # define SA_STACK   SA_ONSTACK  
 #endif  
 ......  

struct siginfo definition:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/asm-generic/siginfo.h  
 ......  
 typedef struct siginfo {  
     int si_signo;  
     int si_errno;  
     int si_code;  
   
     union {  
         int _pad[SI_PAD_SIZE];  
   
         /* kill() */  
         struct {  
             __kernel_pid_t _pid;  /* sender's pid */  
             __ARCH_SI_UID_T _uid;  /* sender's uid */  
         } _kill;  
   
         /* POSIX.1b timers */  
         struct {  
             __kernel_timer_t _tid; /* timer id */  
             int _overrun;      /* overrun count */  
             char _pad[sizeof( __ARCH_SI_UID_T) - sizeof(int)];  
             sigval_t _sigval;    /* same as below */  
             int _sys_private;    /* not to be passed to user */  
         } _timer;  
   
         /* POSIX.1b signals */  
         struct {  
             __kernel_pid_t _pid;  /* sender's pid */  
             __ARCH_SI_UID_T _uid;  /* sender's uid */  
             sigval_t _sigval;  
         } _rt;  
   
         /* SIGCHLD */  
         struct {  
             __kernel_pid_t _pid;  /* which child */  
             __ARCH_SI_UID_T _uid;  /* sender's uid */  
             int _status;      /* exit code */  
             __ARCH_SI_CLOCK_T _utime;  
             __ARCH_SI_CLOCK_T _stime;  
         } _sigchld;  
   
         /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */  
         struct {  
             void *_addr; /* faulting insn/memory ref. */  
 #ifdef __ARCH_SI_TRAPNO  
             int _trapno;  /* TRAP # which caused the signal */  
 #endif  
             short _addr_lsb; /* LSB of the reported address */  
         } _sigfault;  
   
         /* SIGPOLL */  
         struct {  
             __ARCH_SI_BAND_T _band; /* POLL_IN, POLL_OUT, POLL_MSG */  
             int _fd;  
         } _sigpoll;  
   
         /* SIGSYS */  
         struct {  
             void *_call_addr; /* calling user insn */  
             int _syscall;  /* triggering system call number */  
             unsigned int _arch;   /* AUDIT_ARCH_* of syscall */  
         } _sigsys;  
     } _sifields;  
 ......  
 #define si_pid     _sifields._kill._pid  
 #define si_uid     _sifields._kill._uid  
 #define si_tid     _sifields._timer._tid  
 #define si_overrun   _sifields._timer._overrun  
 #define si_sys_private _sifields._timer._sys_private  
 #define si_status    _sifields._sigchld._status  
 #define si_utime    _sifields._sigchld._utime  
 #define si_stime    _sifields._sigchld._stime  
 #define si_value    _sifields._rt._sigval  
 #define si_int     _sifields._rt._sigval.sival_int  
 #define si_ptr     _sifields._rt._sigval.sival_ptr  
 #define si_addr     _sifields._sigfault._addr  
 #ifdef __ARCH_SI_TRAPNO  
 #define si_trapno    _sifields._sigfault._trapno  
 #endif  
 #define si_addr_lsb   _sifields._sigfault._addr_lsb  
 #define si_band     _sifields._sigpoll._band  
 #define si_fd      _sifields._sigpoll._fd  
 #ifdef __ARCH_SIGSYS  
 #define si_call_addr  _sifields._sigsys._call_addr  
 #define si_syscall   _sifields._sigsys._syscall  
 #define si_arch     _sifields._sigsys._arch  
 ......  

If user setup the signal handler with SA_SIGINFO, then when handler caught the signal, it can deduce more information about why the signal is generated and identify the process context with 3rd argument.

No comments:

Post a Comment