Home  >  Article  >  Backend Development  >  Implementation and use of linux kernel signals_PHP tutorial

Implementation and use of linux kernel signals_PHP tutorial

WBOY
WBOYOriginal
2016-07-12 08:53:27973browse

Implementation and use of Linux kernel signals

Post some of the things I wrote before and learn with everyone.
1. Basic data structure
* Linux signal number structure
The following picture is a picture of the "Signals" chapter of "In-depth Understanding of the Linux Kernel 3rd Edition" Implementation and use of linux kernel signals_PHP tutorial
Implementation and use of linux kernel signals_PHP tutorial

{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 option__sigrestore_t sa_restorer; sigset_t sa_mask; /* mask last for extensibility */ //Every};struct k_sigaction { struct sigaction sa;};
* signal processing function prototype/ * Type of a signal handler. */typedef void (*__sighandler_t)(int);

* The structure to save the signal value is based on the number of bits of the machine's CPU:. If it is 32 bits, two An array of long integers (64 bits in total);. If it is 64 bits, only one array of long integers (also 64 bits) is needed;
#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 */// A bit array that holds the signal value, each bit represents a signal value typedef struct { unsigned long sig[_NSIG_WORDS]; / /Save the value of the integer signal according to the definition of bits} sigset_t;

* 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 spinlock_t siglock; //Signal spin lock wait_queue_head_t signalfd_wqh; //Signal waiting 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; // Set the flag bit to clear the signal after sending the signal sig and prevent the current signal from being blocked. new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK; // Clear all signal bits in new_sa first sigemptyset(&new_sa.sa.sa_mask); // Ret = do_sigaction(sig, &new_sa, &old_sa); return ret ? ret : (unsigned long)old_sa.sa.sa_handler;}
. Installation of signal processing function 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 in current 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, return parameter value error // (2 ) If the signal processing structure is not empty and sig is SIGKILL or SIGSTOP, the return parameter error is because KILL and STOP are processed by the kernel and cannot be blocked if (!valid_signal(sig) || sig sighand->action[sig- 1]; // Use spin lock to lock spin_lock_irq(¤t->sighand->siglock); // Assign the signal processing structure of the current process to a temporary variable oact and save it if (oact) *oact = *k; // The signal structure to be set is not NULL if (act) { // Delete the SIGKILL and SIGSTOP signals from the masked signal field. These two signals are not maskable sigdelsetmask(&act->sa.sa_mask, sigmask(SIGKILL ) | sigmask(SIGSTOP)); // Replace the process processing structure (sighand) of the current process with the new signal processing structure *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 a waiting signal processing function is set to SIG_IGN, it will cause the The signal is lost, whether or not the signal is blocked. // (2) If the processing function of a signal (such as SIGCHLD) that is in a waiting state and whose default processing method is ignored is set to SIG_DFL, then the waiting signal may be lost regardless of whether the signal is blocked.
// (1) If the signal processing structure is set to SIG_IGN, TRUE will be returned directly. // (2) If the processing function is set to SIG_DFL and sig is a signal ignored by the kernel, TRUE will be returned directly.// If the signal processing function is set to SIG_IGN, delete these signals 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); // Set the corresponding signal bit according to the signal value sigaddset(&mask, sig); // Change sig The signal is removed from the process descriptor's blocking signal queue. 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); // Do the same thing for the thread of the process. 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 is 32~64) and non-real-time signal (id is 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 signal sending system call function call relationship 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()

Signal sending is implemented through the system call long kill(pid_t pid, int sig);. Now let's 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; // Set the error number to 0 info.si_errno = 0 ; // Set the signal sending flag, 0 indicates that it is sent by system calls such as kill and raise; the integer indicates that it is sent by the kernel info.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; // 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,sig) is unspecified, but what we have* is probably wrong. Should make it like BSD or SYSV.*/// This function is based on different pid, different behaviors of processes. Mainly divide pid into three categories: // (1) pid > 0// (2) pid == -1// (3) pid 0) { //If pid>0, the signal is only sent at this time For 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) { //Incoming Process number 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 Sending a signal to a single process is implemented through the following function. This function only sends signals to a single process and does not deal with the process group in which the process belongs, etc.int kill_pid_info(int sig, struct siginfo *info, struct pid *pid){ int error = -ESRCH; struct task_struct *p; rcu_read_lock();retry: // Get the process descriptor structure corresponding to pid (task_strcut *) p = pid_task(pid, PIDTYPE_PID); // Obtain successfully if (p) { // Send signal to process descriptor p error = group_send_sig_info(sig, info, p); // If signal sending fails and the error is equal to -ESRCH, Try again. // Note: At this time, the process may not be the original process, so you need to obtain the 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;}


. Send signal function The final signal sending 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 is Can be sent, if the sent process is in the exit state, the signal is discarded. if (!prepare_signal(sig, t)) return 0; // If a signal is sent to a single process, group is 1, and 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 that we can get more * detailed information about the cause of the signal. */ // If the signal is a non-real-time signal ( /* Real-time signals must be queued if sent by sigqueue, or some other real-time mechanism. 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 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; }

www.bkjia.comtruehttp: //www.bkjia.com/PHPjc/1124516.htmlTechArticleImplementation and use of linux kernel signals. Post some of the things I have written before and learn with everyone. 1. Basic data structure * Linux signal number structure The following picture is "In-depth understanding of the Linux kernel...
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn