Implementation and use of Linux kernel signals
Send some things that you have written before and learn from them.
1, basic data structure
* Linux Signal number structure
In-depth understanding of the 3rd edition of the Linux kernel, the "signals" chapter of the figure
{Task_struct} [...] [Signal]------------------------------[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 bit option __sigrestore_t sa_res Torer; sigset_t Sa_mask; /* Mask last for Extensibility *///per};struct k_sigaction {struct sigaction sa;};
* Signal Processing function prototype/* Type of a signal handler. */typedef void (*__sighandler_t) (int);
* The structure of the value that holds the signal is based on the number of bits of the machine's CPU:. If 32 bits, the array of two long integers (total 64 bits) is required; If 64 bits, only an array of long integers (also 64 bits) 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 + bits *///the bit array that holds the signal values, each bit representing a signal value typedef struct {unsigned long sig[_nsig_words];//The value of the integer signal is saved according to the number of digits} sigset_ T
* Signal processing structure in Process descriptor struct Sighand_struct {atomic_t count; struct k_sigaction action[_nsig];//each signal value corresponds to a k_sigaction structure spinlock_t Siglock; Signal spin lock wait_queue_head_t SIGNALFD_WQH; Signal waiting Queue};
* Signal processing function installs/** 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 signal processing function New_sa.sa.sa_handler = handler; Sets the signal to clear the signal after the sig is sent and prevents the current signal from being shielded by the flag bit new_sa.sa.sa_flags = Sa_oneshot | Sa_nomask; First, clear all signal bits in the New_sa sigemptyset (&new_sa.sa.sa_mask); being ret = Do_sigaction (sig, &new_sa, &old_sa); return ret? RET: (unsigned long) Old_sa.sa.sa_handler;}
. Signal processing function installation int do_sigaction (int sig, struct k_sigaction *act, struct k_sigaction *oact) {//Get the current process descriptor address, That is, directly obtain the address of current in the struct task_struct *t = current; struct K_sigaction *k; sigset_t Mask; Check the legitimacy of the signal://(1) If the sig is greater than 64 or less than 1, the return parameter value error//(2) if the signal processing structure is not empty, and the sig is Sigkill or sigstop return parameter error, because kill and stop is handled by the kernel, cannot be masked if (!valid _signal (SIG) | | Sig < 1 | | (Act && Sig_kernel_only (SIG))) Return-einval; Gets the default processing structure of the current process to the sig signal, which is stored in the Sighand variable of the process descriptor. K = &t->sighand->action[sig-1]; Lock SPIN_LOCK_IRQ (¤t->sighand->siglock) with spin lock; The signal processing structure of the current process is assigned to a temporary variable oact saved if (oact) *oact = *k; To set the signal structure to not be null if (ACT) {//To remove the Sigkill and sigstop signals from the masked signal field, the two signals are not shielded sigdelsetmask (&act->sa.sa_mask, Sigmask (SIGKILL) | Sigmask (SIGSTOP)); Replace the process processing structure of the current process with the new signal processing structure (sighand) *k = *act;
/* * POSIX 3.3.1.3: * "Setting a signal action to sig_ign for a signal" was * pending shall cause the pending signal to Be discarded, * whether or isn't it is blocked. ' * * ' Setting a signal action to SIG_DFL for a signal so 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 a waiting signal processing function is set to sig_ign, it will cause the signal to be lost, regardless of whether the signal is blocked. (2) If a waiting state and the default processing is ignored signal (such as SIGCHLD) of the processing function set to SIG_DFL, then, whether the signal is blocked, can cause the loss of waiting signal.
(1) If the processing structure of the signal is set to Sig_ign, the direct return is true. (2) If the processing function is set to SIG_DFL and the sig is a signal ignored by the kernel, it returns true directly. If the signal processing function is set to sig_ign, these signals are removed from the shared_pending shared signal queue of the process descriptor. if (sig_handler_ignored (Sig_handler (T, SIG), SIG)) {//clear mask signal bit bit structure sigemptyset (&mask);//set corresponding signal bit according to signal value Sigaddset (&mask, SIG); Remove the sig signal from the blocking signal queue of the process descriptor. Rm_from_queue_full (&mask, &t->signal->shared_pending); Removes the sig signal from the pending queue of the current process descriptor. do {rm_from_queue_full (&mask, &t->pending);//For the thread of the process, do the same processing. t = Next_thread (t); } while (t! = current); }} SPIN_UNLOCK_IRQ (¤t->sighand->siglock); return 0;}
* Signal Information structure typedef struct SIGINFO {int si_signo;//signal ID, including real-time (ID 32~64) and 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 is 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 signal sending system calls the function call relationship as follows: Sys_kill (), Kill_something_info (), if (pid>0) Kill_pid_info (), if (pid!=-1) __kill_ Pgrp_info (), Else Group_send_sig_info ()
Signal sending is accomplished by calling long kill (pid_t pid, int sig) through the system. Now let me look at the implementation of this system call:
Asmlinkage Longsys_kill (pid_t pid, int sig) {struct Siginfo info;//Set signal value Info.si_signo = sig;//Set error number to 0 Info.si_errno = 0; Set the signal sending flag, 0 marked kill,raise and other system calls sent; integer indicates that the kernel sends info.si_code = Si_user; Set signal process Number Info.si_pid = TASK_TGID_VNR (current); Set signal UserID Info.si_uid = current->uid; Send signal to PID return Kill_something_info (Sig, &info, PID);}
* Send signal Intermediate function/** Kill_something_info () interprets PID in interesting ways just like Kill (2). * * POSIX Specifies that kill ( -1,s IG) is unspecified, and what we have* is probably wrong. Should make it like BSD or sysv.*///the function according to different PID, process different behavior. The main PID is divided into three categories://(1) PID > 0//(2) pid = = -1//(3) PID <= 0static 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_VPI D (PID)); Rcu_read_unlock (); return ret; }
Read_lock (&tasklist_lock); if (pid! =-1) {//Incoming process number <=0 ret = __kill_pgrp_info (sig, Info, PID find_vpid (-pid): Task_pgrp (current));} else {// The incoming 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;}
. Sending a signal to a single process sends a signal to a single process is achieved through the following functions. This function sends a signal only to a single process, not to the process group in which the process resides. int kill_pid_info (int sig, struct siginfo *info, struct pid *pid) {int error =-esrch; struct task_struct *p; rcu_read_loc K (); retry://Get PID corresponding to the process descriptor structure (task_strcut *) p = pid_task (PID, pidtype_pid); Get success if (p) {//To process descriptor p, send signal error = Group_send_sig_info (sig, Info, p);//If the send signal fails and the error equals-esrch, retry. Note: It is possible that the process is not the original process at this time, so you need to get the task_struct again. if (unlikely (Error = =-esrch))/* * The task is unhashed in between, try again. * If it is dead, Pid_task () would return NULL, * if we race with De_thread () it'll find the * new leader. */goto retry; } rcu_read_unlock (); return error;}
. Send signal function The final signal transmission is implemented by send_signal. static int send_signal (int sig, struct siginfo *info, struct task_struct *t, int group) {struct sigpending *pending; struc T Sigqueue *q; Assert_spin_locked (&t->sighand->siglock);
Check if the signal can be sent, if the sent process is in the exit state, discard the signal. if (!prepare_signal (SIG, T)) return 0; If a signal is sent to a single process, the group is 1, at which point the pending is a shared blocking signal processing pending = group? &t->signal->shared_pending: &t->pending; /* * Short-circuit ignored signals and support queuing * Exactly one non-rt signal, so the we can get more * detailed inf Ormation about the cause of the signal. *//If the signal is a non-real-time signal (<32), and the signal has been sent, is being processed/not processed, discard the signal. 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 is queued if sent by Sigqueue, or some other real-time mechanism. It is implementation defined whether kill () does so. We attempt to does so, on the principle of least surprise, but since kill are not allowed to fail with Eagain when low on mem Ory 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, ABO Rt. We may abort if the signal is 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.html www.bkjia.com true http://www.bkjia.com/PHPjc/1124516.html techarticle implementation and use of Linux kernel signals send some things that you have written before and learn from them. 1, basic data structure * Linux signal number structure is "in-depth understanding of the Linux kernel ...