博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
linux的signal_pending及signal
阅读量:2499 次
发布时间:2019-05-11

本文共 6484 字,大约阅读时间需要 21 分钟。

1. signal_pending( current )的作用

仅检查当前进程是否有信号处理(不会在这里处理信号),返回不为0表示有信号需要处理

1.1. 两个信号的概念

signal pending:指在信号被处理之前生成信号的状态,是信号生成和信号消除的中间状态

signal blocking:指阻塞正在处理的信号,这是一种信号处理方法

2. 常规使用场景

if (signal_pending(current)) {     ret = -ERESTARTSYS;     return ret;    }

signal_pending(current)检查到当前进程有信号需要处理时,退出当前的系统调用,并返回"-ERESTARTSYS";然后便会进入对应的Signal处理函数。

"-ERESTARTSYS"表示信号函数处理完毕后重新执行之前的那个系统调用(如果Signal处理函数之前有系统调用的话)。

3. 情景分析

当一个系统调用处于睡眠状态时(如:等待输入缓冲区不为空),如果此时产生信号,这个信号仅在thread_info结构中标识以下,即所谓"发信号";

"发信号"动作会唤醒系统调用,系调调用便会执行signal_pending(current)检测是否有信号,如果有信号则系统调用返回-ERESTARTSYS,在从系统调用的返回用户空间后,会根据thread_info中信号标识位调用相应的Signal处理函数,这里就是所谓的“接收信号”;
Signal信号函数处理完成后,上层库函数会根据系统调用的ERESTARTSYS返回值重启该系统调用,重启的系统调用会再次检查缓冲区:为空,说明刚才的信号不是缓冲区有数据了的信号,继续等待,重复刚才的过程;不为空,就可以直接处理数据,系统调用正常结束,最后返回用户空间的应用程序。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CKEWdp00-1607526956110)(https://www.programmersought.com/images/355/4c97b4155d2f61758a00b981fec7160b.JPEG)]
Processing process:
When the program is running in user mode -> the process enters the kernel due to a system call or interruption -> turns to the user mode to execute the signal processing function -> enters the kernel after the signal processing function is completed -> returns to the user mode to continue executing the program

First, the program is executed in user mode. On the eve of the process falling into the kernel and returning from the kernel, it will check whether the signal has not been processed, and if it has and is not blocked, it will call the corresponding signal handler to process it. First, the kernel creates a layer on the user stack, in which the return address is set to the address of the signal processing function, so that when the kernel returns to the user mode, the signal processing function will be executed. When the signal processing function is executed, it will enter the kernel again, mainly to detect whether there is a signal that has not been processed, and to restore the original program interrupt execution point, restore the kernel stack, etc., so that when returning from the kernel, it will return to the original program execution place Up

4. 检测进程p是否有待处理的信号的代码

static inline int signal_pending(struct task_struct *p) {    return unlikely(test_tsk_thread_flag(p, TIF_SIGPENDING)); // p->thread_info->flags中TIF_SIGPENDING位是否置位}#define TIF_SIGPENDING          2   static inline int test_tsk_thread_flag(struct task_struct *tsk, int flag) {    return test_ti_thread_flag(task_thread_info(tsk), flag);}static inline int test_ti_thread_flag(struct thread_info *ti, int flag) {      return test_bit(flag, &ti->flags);}static inline int test_bit(int nr, const volatile void * addr) {      return (1UL &(((const int *) addr)[nr >> 5] >>(nr & 31) )) != 0UL; // 检测addr的第nr位是否为1(addr右起最低位为第0位)

5. Signal operation 信号操作实验

#include
#include
#include
/* * Add the signal SIGINT to the signal set, set the signal set to a blocked signal set, get the pending signal set, and print it out. When you enter Ctrl+C, you can find that the pending signal set has changed. * * in conclusion: * * If a signal is blocked by the process, it will not be passed to the process, but it will stay in the pending state.When the signal is blocked, The signal will be processed immediately. */// Block a signal, print the pending signal setvoid printsigset(sigset_t *set){ int i = 0; for(;i<32;i++){ if(sigismember(set,i)) //Determine whether the specified signal is in the target set putchar('1'); else putchar('0'); } puts("");}int main(){ sigset_t s,p; //Define the signal set object, and clear the initialization, sigset_t 128bytes sigemptyset(&s); sigaddset(&s,SIGINT); //Add signal to the signal set, SIGINT是 ctrl+c发出的信号 sigprocmask(SIG_BLOCK,&s,NULL); //Set blocking signal set, SIGINT信号被阻挡后ctrl+c是无法停止程序的 while(1) { sigpending(&p); //Get pending signal set printsigset(&p); sleep(1); } return 0;}
int sigemptyset(sigset_t *set); //Initialize the signal set pointed to by set, and clear the corresponding bits of all signals, indicating that the signal set does not contain any valid signalsint sigfillset(sigset_t *set); //Initialize the signal set pointed to by set and set the corresponding bits of all signals, indicating that the effective signal of the signal machine includes all the signals supported by the system.int sigaddset(sigset_t *set,int signo); //Add some kind of valid signal to the signal set.int sigdelset(sigset_t *set,int signo); //Delete a valid signal in the signal setint sigismemeber(sigset_t* set,int signo); //It is a Boolean function, used to determine whether a signal set contains a certain signal, if it contains a thief, it returns 1, if it does not, it returns 0, and it returns -1 on errorint sigprocmask(int how,const sigset_t*set,sigset_t *oset); //Read or change the signal shielding word (blocking signal set) of the process, if successful, return 0, fail, return -1int sigpending(sigset_t *set); //Read the pending signal set of the current process and pass it through the set parameter. If the call is successful, it returns 0, and if it fails, it returns -1.

6. linux kernel对ERESTARTSYS等返回值的处理

If a process is blocked on a system call it is put on a waitqueue in the TASK_INTERRUPTIBLE or TASK_UNINTERRUPTIBLE state. In the former case, upon receiving a signal, the kernel puts it back in the TASK_RUNNING state, adds the process to the runqueue and adds the signal to the list of pending signals.

When the process is scheduled, it continues the execution of the system call. Since the syscall was not completed, the possible return codes are:

EINTR

ERESTARTNOHAND
ERESTART_RESTARTBLOCK
ERESTARTSYS
ERESTARTNOINTR
On the exit path from the system call, the pending signals are checked. In this case, your SIG_ALRM handler is called and immediately afterwards the kernel checks the return code of the system call. In general, the following cases may occur:

Return code is EINTR: the user mode process is resumed and the return value of read will be exactly -EINTR

Return code is ERESTARTNOINTR: the system call is reexecuted
Return code is ERESTARTSYS: system call is reexecuted if SA_RESTART flag is set, otherwise -EINTR is returned to userspace.
Return code is ERESTARTNOHAND or ERESTART_RESTARTBLOCK: usermode process is resumed and -EINTR returned.
Reexecuting a system call means that the process EIP is decremented by 2 and it is therefore forced to execute again int 0x80.

参考资料

转载地址:http://uwerb.baihongyu.com/

你可能感兴趣的文章
HDP Sandbox里面git clone不了数据(HTTP request failed)【目前还没解决,所以hive的练习先暂时搁置了】
查看>>
动态分区最佳实践(一定要注意实践场景)
查看>>
HIVE—索引、分区和分桶的区别
查看>>
Hive进阶总结(听课总结)
查看>>
大数据领域两大最主流集群管理工具Ambari和Cloudera Manger
查看>>
Sqoop往Hive导入数据实战
查看>>
Mysql到HBase的迁移
查看>>
Sqoop import进阶
查看>>
Hive语句是如何转化成MapReduce任务的
查看>>
Hive创建table报错:Permission denied: user=lenovo, access=WRITE, inode="":suh:supergroup:rwxr-xr-x
查看>>
Hive执行job时return code 2排查
查看>>
hive常用函数及数据结构介绍
查看>>
Hive面试题干货(亲自跟着做了好几遍,会了的话对面试大有好处)
查看>>
力扣题解-230. 二叉搜索树中第K小的元素(递归方法,中序遍历解决)
查看>>
力扣题解-123. 买卖股票的最佳时机 III(动态规划)
查看>>
Django 源码阅读:服务启动(wsgi)
查看>>
Django 源码阅读:url解析
查看>>
Docker面试题(一)
查看>>
第一轮面试题
查看>>
2020-11-18
查看>>