Linux kernel signal implementation and usage-PHP Tutorial

Source: Internet
Author: User
Tags signal handler
Implementation and use of Linux kernel signals. The implementation and use of Linux kernel signals sends out some previously written things and learns with everyone. 1. Basic Data Structure * linux signal number structure is the implementation and use of linux kernel signals in linux kernel.
Send out some of the previous articles and learn with everyone.
1. basic data structure
* Linux signal number structure
Is a diagram of the "signal" chapter in "a deep understanding of Linux kernel 3rd"


{Task_struct} [...] [signal] specified [sighand] [blocked] [real_balocked] [saved_sigmask] [pending] [notifier] [notifier_mask] [...]


* Signal processing data structure struct sigaction {_ sighandler_t sa_handler; // signal processing function pointer unsigned long sa_flags; // signal flag position option _ sigrestore_t sa_restorer; sigset_t sa_mask; /* mask last for extensibility * // Each}; struct k_sigaction {struct sigaction sa ;};
* Signal processing function prototype/* Type of a signal handler. */typedef void (* _ sighandler_t) (int );

* The structure of the stored signal value is based on the number of CPU digits of the machine :. if it is 32 bits, two long integer arrays (64 bits in total) are required );. if it is 64-bit, only an array with a long integer (also 64-bit) is required );
# Define _ NSIG 64 # ifdef _ i386 __# define _ NSIG_BPW 32 # else # define _ NSIG_BPW 64 # endif # define _ NSIG_WORDS (_ NSIG/_ NSIG_BPW) typedef unsigned long old_sigset_t;/* at least 32 bits * // bit array that stores the signal value. each bit represents a signal value typedef struct {unsigned long sig [_ NSIG_WORDS]; // define the value of the integer signal according to the number of digits} sigset_t;

* The signal processing structure in the process descriptor, struct sighand_struct {atomic_t count; struct k_sigaction action [_ NSIG]; // Each signal value corresponds to a k_sigaction structure, in the spinlock_t siglock; // signal spin lock wait_queue_head_t signalfd_wqh; // signal wait queue };

* Signal processing function installation/** For backwards compatibility. functionality superseded by sigaction. */asmlinkage unsigned longsys_signal (int sig, _ sighandler_t handler) {struct k_sigaction new_sa, old_sa; int ret; // Set the signal processing function new_sa.sa.sa_handler = handler; // after setting the signal sig, clear the signal and prevent the current signal from being blocked. the flag is new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK; // clear all sigemptyset (& new_sa.sa.sa_mask) in new_sa first; // ret = do_sigaction (sig , & New_sa, & old_sa); return ret? Ret: (unsigned long) old_sa.sa.sa_handler ;}
. Int do_sigaction (int sig, struct k_sigaction * act, struct k_sigaction * oact) for signal processing function installation {// Obtain the current process descriptor address, that is, directly obtain the address struct task_struct * t = current; struct k_sigaction * k; sigset_t mask; // check the validity of the signal: // (1) if sig is greater than 64 or less than 1, the returned parameter value is incorrect // (2) if the signal processing structure is not empty and sig is SIGKILL or SIGSTOP, because KILL and STOP are processed by the kernel, they cannot be blocked if (! Valid_signal (sig) | sig <1 | (act & sig_kernel_only (sig) return-EINVAL; // gets the default processing structure of sig signals of the current process, stored in the sighand variable of the process descriptor. K = & t-> sighand-> action [sig-1]; // use the spin lock to lock the spin_lock_irq (& current-> sighand-> siglock ); // assign the signal processing structure of the current process to a temporary variable oact and save it if (oact) * oact = * k; // if the signal structure to be set is not NULL if (act) {// delete the SIGKILL and SIGSTOP signals from the blocked signal field, the two signals are unshielded sigdelsetmask (& act-> sa. sa_mask, sigmask (SIGKILL) | sigmask (SIGSTOP); // use the new signal processing structure to replace the process processing structure (sighand) of the current process * k = * act;
/** POSIX 3.3.1.3: * "Setting a signal action to SIG_IGN for a signal that is * pending shall cause the pending signal to be discarded, * whether or not it is blocked. "**" Setting a signal action to SIG_DFL for a signal that is * pending and whose default action is to ignore the signal * (for example, SIGCHLD ), shall cause the pending signal to * be discarded, whether or not it is blocked "*/// (1) If you set the processing function of a waiting signal to SIG_IGN, the signal will be lost, regardless of whether the signal is blocked. // (2) If you set the processing function of a signal (such as SIGCHLD) that is in the waiting state and is ignored by default to SIG_DFL, no matter whether the signal is blocked or not, both may cause loss of waiting signals.
// (1) If the signal processing structure is set to SIG_IGN, TRUE is returned directly. // (2) if the processing function is set to SIG_DFL and sig is a signal ignored by the kernel, TRUE is returned directly. // If the signal processing function is set to SIG_IGN, these signals are deleted from the shared_pending shared signal queue of the process descriptor. If (sig_handler_ignored (sig_handler (t, sig), sig) {// clear the mask signal bit structure sigemptyset (& mask); // based on the signal value, set the corresponding signal bit sigaddset (& mask, sig); // delete the sig signal from the blocked signal queue of the process descriptor. Rm_from_queue_full (& mask, & t-> signal-> shared_pending); // delete the sig signal from the pending queue of the current process descriptor. Do {rm_from_queue_full (& mask, & t-> pending); // process the same thread. T = next_thread (t);} while (t! = Current) ;}} spin_unlock_irq (& current-> sighand-> siglock); return 0 ;}

* Signal information structure typedef struct siginfo {int si_signo; // signal id, including real-time (id: 32 ~ 64) non-real-time signal (id 0 ~ 32) int si_errno; // int si_code; // union {int _ pad [SI_PAD_SIZE];/* kill () */struct {pid_t _ pid; /* sender's pid */_ ARCH_SI_UID_T _ uid;/* sender's uid */} _ kill;/* POSIX.1b timers */struct {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 {pid_t _ pid;/* sender's pid */_ ARCH_SI_UID_T _ uid;/* sender's uid */sigval_t _ sigval ;} _ rt;/* SIGCHLD */struct {pid_t _ pid;/* which child */_ ARCH_SI_UID_T _ uid;/* sender's uid */int _ status; /* exit code */clock_t _ utime; clock_t _ stime;} _ sigchld;/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */struct {void _ user * _ addr; /* faulting insn/memory ref. */# ifdef _ ARCH_SI_TRAPNO int _ trapno;/* TRAP # which caused the signal */# endif} _ sigfault;/* SIGPOLL */struct {_ ARCH_SI_BAND_T _ band; /* POLL_IN, POLL_OUT, POLL_MSG */int _ fd;} _ sigpoll;} _ sifields;} siginfo_t;

* The function call relationship of the signal sending system call is as follows: sys_kill ()-> kill_something_info ()-> if (pid> 0) kill_pid_info ()-> if (pid! =-1) _ kill_pgrp_info ()-> else group_send_sig_info ()

The system calls long kill (pid_t pid, int sig); to send signals. Now let's take a look at the implementation of this system call:
Asmlinkage longsys_kill (pid_t pid, int sig) {struct siginfo info; // Set the signal value info. si_signo = sig; // the error code is 0 info. si_errno = 0; // Set the signal sending flag. The value 0 indicates that messages are sent by system calls such as kill and raise. the integer indicates that messages are sent by the kernel. si_code = SI_USER; // Set the signal process number info. si_pid = task_tgid_vnr (current); // Set the signal userid info. si_uid = current-> uid; // return kill_something_info (sig, & info, pid) to the pid );}
* Signal sending intermediate function/** kill_something_info () interprets pid in interesting ways just like kill (2 ). ** POSIX specifies that kill (-1, sig) is unspecified, but what we have * is probably wrong. shocould make it like BSD or SYSV. * /// This function varies with the process based on different PIDs. Pid is mainly divided into three types: // (1) pid> 0 // (2) pid =-1 // (3) pid <= 0 static int kill_something_info (int sig, struct siginfo * info, pid_t pid) {int ret; if (pid> 0) {// if pid> 0, the signal is sent only to a single process rcu_read_lock (); ret = kill_pid_info (sig, info, find_vpid (pid); rcu_read_unlock (); return ret ;}
Read_lock (& tasklist_lock); if (pid! =-1) {// input process number <= 0 ret = _ kill_pgrp_info (sig, info, pid? Find_vpid (-pid): task_pgrp (current);} else {// The input process number is-1 int retval = 0, count = 0; struct task_struct * p; for_each_process (p) {if (p-> pid> 1 &&! Same_thread_group (p, current) {int err = group_send_sig_info (sig, info, p); ++ count; if (err! =-EPERM) retval = err;} ret = count? Retval:-ESRCH;} read_unlock (& tasklist_lock); return ret ;}

The following function is used to send a signal to a single process. This function only sends signals to a single process and does not process the process group where the process is located. Int kill_pid_info (int sig, struct siginfo * info, struct pid * pid) {int error =-ESRCH; struct task_struct * p; rcu_read_lock (); retry: // Obtain the process descriptor structure (task_strcut *) corresponding to the pid p = pid_task (pid, PIDTYPE_PID); // Obtain the if (p) {// forward the process descriptor p, sending signal error = group_send_sig_info (sig, info, p); // if the sending signal fails and the error is-ESRCH, retry. // Note: At this time, the process may not be the original process, so you need to obtain task_struct again. If (unlikely (error =-ESRCH)/** The task was unhashed in between, try again. * If it is dead, pid_task () will return NULL, * if we race with de_thread () it will find the * new leader. */goto retry;} rcu_read_unlock (); return error ;}


. The final signal sending function is implemented by send_signal. Static int send_signal (int sig, struct siginfo * info, struct task_struct * t, int group) {struct sigpending * pending; struct sigqueue * q; assert_spin_locked (& t-> sighand-> siglock );
// Check whether the signal can be sent. if the sent process is exited, the signal is discarded. If (! Prepare_signal (sig, t) return 0; // if the group is 1 if a signal is sent to a single process, pending processes the shared blocking signal with pending = group? & T-> signal-> shared_pending: & t-> pending;/** Short-circuit ignored signals and support queuing * exactly one non-rt signal, so that we can get more * detailed information about the cause of the signal. * /// if the signal is not a real-time signal (<32) and the signal has been sent, it is being processed/not processed, and the signal is discarded. If (legacy_queue (pending, sig) return 0;/** fast-pathed signals for kernel-internal things like SIGSTOP * or SIGKILL. */if (info = SEND_SIG_FORCED) goto out_set;
/* Real-time signals must be queued if sent by sigqueue, or some other real-time mechanic. it is implementation defined whether kill () does so. we attempt to do so, on the principle of least surprise, but since kill is not allowed to fail with EAGAIN when low on memory we just make sure at least one signal gets delivered and don't pass on the info struct. */q = _ sigqueue_alloc (t, GFP_ATOMIC, (sig <SIGRTMIN & (is_si_special (info) | info-> si_code> = 0); if (q) {list_add_tail (& q-> list, & pending-> list); switch (unsigned long) info) {case (unsigned long) SEND_SIG_NOINFO: q-> info. si_signo = sig; q-> info. si_errno = 0; q-> info. si_code = SI_USER; q-> info. si_pid = task_pid_vnr (current); q-> info. si_uid = current-> uid; break; case (unsigned long) SEND_SIG_PRIV: q-> info. si_signo = sig; q-> info. si_errno = 0; q-> info. si_code = SI_KERNEL; q-> info. si_pid = 0; q-> info. si_uid = 0; break; default: copy_siginfo (& q-> info, info); break ;}
} Else if (! Is_si_special (info) {if (sig >=sigrtmin & info-> si_code! = SI_USER)/** Queue overflow, abort. we may abort if the signal was rt * and sent by user using something other than kill (). */return-EAGAIN;} out_set: signalfd_notify (t, sig); sigaddset (& pending-> signal, sig); complete_signal (sig, t, group); return 0 ;}

Http://www.bkjia.com/PHPjc/1124516.htmlwww.bkjia.comtruehttp://www.bkjia.com/PHPjc/1124516.htmlTechArticlelinux kernel signal implementation and use of the previous written something, and everyone to learn. 1. Basic Data Structure * The linux signal number structure is a "deep understanding of linux kernel...

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.