范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

Linuxfd系列信号编程(signal)竟能这样做?涨姿势

  来源 | 奇点云存储(id : qiyacloud)授权转载
  如若转载请联系原公众号
  信号是什么?
  平台声明 :
  Linux 操作系统
  首先说,信号(signal)是什么?
  信号( signal )本质是 Linux 进程间通信的一种机制,也叫 软中断信号 。既然是通信机制,那么就是传递信息用的,信号传递的信息很简单,就是一个整数,一般用于配合系统管理任务,比如进程的终结、恢复、热加载等。
  信号都用整数常量表示,命名以 SIG 为前缀,比如 SIGINT( ctrl-c 触发),SIGKILL( kill -9 触发 )。
  信号一般怎么产生?  由内核产生,比如内存错误,除 0 等错误,内核通过信号通知到相应的进程;  可以由其他进程传递给目标进程,比如 kill 命令就是专门干这个事情的;
  信号处理分为两个阶段 :  发送阶段:内核将信号(signal)放到对应的 pending 队列中;  传递阶段:也叫做处理阶段,内核将信号从 pending 队列中取出来,并且进行处理,一般是调用相应的回调函数(处理方式有三种:用户定义、内核默认定义 SIG_DEL、忽略 SIG_IGN);
  signalfd 是什么?
  了解了什么是信号( signal ),那 signalfd 又会是什么呢?
  是一个跟信号关联的 文件描述符 ,能够以 io 的行为获取到系统信号,属性上来讲 signalfd 也是一个匿名 fd 类型。
  signalfd 长什么样子?
  奇点按照  man signalfd  里面的例子,写了个 demo,跑在 Linux 机器上,按照惯例去看下 fd 的样子。 root@ubuntu:~# ll /proc/15445/fd  lrwx------ 1 root root 64 Aug 24 16:42 3 -> anon_inode:[signalfd]  root@ubuntu:~# cat /proc/15445/fdinfo/3  pos: 0 flags: 02 mnt_id: 11 sigmask: 0000000000000006
  从这里可以得到简单的信息:  signal 用的匿名 inode ,signalfd 属于匿名 fd 的一种;  句柄关联的重要信息就是 sigmask,通过  /proc/${pid}/fdinfo/3  能看到这个值;
  signalfd 使用姿势?
  其实信号是很讲究的,甚至有信号编程一说,Linux 的 signalfd 为信号的处理提供了一种新的方法, 统一到文件的 io 模式,契合一切接文件的理念 。
  系统调用:  #include   int signalfd(int fd, const sigset_t *mask, int flags);
  该系统调用返回一个整数类型 signalfd,这个句柄跟信号行为绑定,当发生信号的时候,句柄触发可读事件。
  第一个参数也可以传入一个有效的信号 fd 的句柄, 如果传入的是 -1 ,那么内核会自动创建一个新的 fd 。
  完整的代码例子,在 Linux 机器上,通过  man signalfd  就可以获取到。 // 信号清零 sigemptyset(&mask);  // 添加信号到掩码集 sigaddset(&mask, SIGINT); sigaddset(&mask, SIGQUIT);  // 设置该进程为对应的信号集的内容(当前已经的信号集合做并集、交集、覆盖) // 这行代码才是真正的信号设置; sigprocmask(SIG_BLOCK, &mask, NULL)  // 创建 signalfd 句柄(绑定信号) sfd = signalfd(-1, &mask, 0);  for (;;) {     // 读取 signalfd 数据(数据代表信号)     s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo));     // ...     // 信号的逻辑处理 }
  上面的例子,signalfd 没有信号(没有可读事件)的时候会阻塞在  read  调用上,运行效果如下: root@ubuntu:~/temp# ./a.out  ^CGot SIGINT ^CGot SIGINT ^CGot SIGINT
  可以看到每一次  ctrl + c  触发的信号被捕捉到,并且打印出来。用文件 io 的方式来接收信号,牛。
  怎么做到的呢?照例,我们浅析一下内核的代码,位于  fs/signalfd.c ,这是一个很小的文件,正是这个文件完成了对信号"文件化"的封装。
  上面最重要的两个调用:  sigprocmask  :设置当前进程的信号掩码,把 SIGINT ,SIGQUIT  处理屏蔽掉,关闭内核默认行为; signalfd  :获取到一个和信号关联的"文件"句柄;
  signalfd 原理剖析
  环境声明 :
  Linux 内核版本 4.19
  1    signalfd  SYSCALL_DEFINE3(signalfd,int, ufd,sigset_t __user *, user_mask,size_t, sizemask){return do_signalfd4(ufd, &mask,0);}staticintdo_signalfd4(int ufd,sigset_t *mask,int flags){structsignalfd_ctx *ctx;// 如果是 -1,内核创建;if (ufd ==-1) {// ctx->sigmask = *mask;// 获取一个匿名句柄;ufd = anon_inode_getfd("[signalfd]", &signalfd_fops, ctx, O_RDWR | (flags & (O_CLOEXEC | O_NONBLOCK)));}else {// 校验传入的句柄是否合法struct fd f = fdget(ufd);ctx = f.file->private_data;if (f.file->f_op != &signalfd_fops) {return -EINVAL;}// 覆盖设置新的值ctx->sigmask = *mask;// 唤醒阻塞在当前进程的信号等待队列wake_up(¤t->sighand->signalfd_wqh);}return ufd;}
  看一下 signalfd 支持的接口调用:  static const struct file_operations signalfd_fops = {      .show_fdinfo    = signalfd_show_fdinfo,     .poll       = signalfd_poll,     .read       = signalfd_read,     // ... };
  通过这个可以知道 signalfd 支持的特性:  支持  /proc/${pid}/fdinfo/xx  查看信息( 对应 signalfd_show_fdinfo  函数 ); 支持 read,close 调用 ( 对应  signalfd_read  函数 ); 支持 poll 调用,支持 epoll 管理( 对应  signalfd_poll  函数 );
  2    signalfd_poll
  这个函数做的事情非常简单,就是把 等待对象 挂到当前进程的信号结构的链表上。表头是: current->sighand->signalfd_wqh  ,这个就有意思了,这里直接挂到当前进程的结构上。换句话说,唤醒也是自此表头开始。
  回忆一下 timerfd ,是挂在  timerfd_ctx->wqh  的字段上。这里的差别是因为信号是对进程来说的。
  3    signalfd_read
  读一个 signalfd 的操作非常简单,主要逻辑:  查看当前队列中是否有信号,有的话就取出来,填充到用户给的结构体中;  如果句柄是阻塞类型的,在没有信号的时候,会切走 cpu,等到有信号的时候切回来。如果是非阻塞类型的,直接报错,返回 EAGAIN ;
  简要的代码注释如下:  static ssize_t signalfd_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) {     // read 数据的存放结构体     siginfo = (struct signalfd_siginfo __user *) buf;     do {         // 取出信号队列中的一个信号,填充好 info 结构体         ret = signalfd_dequeue(ctx, &info, nonblock);         // 循环操作,填充用户指定个数的信号         ret = signalfd_copyinfo(siginfo, &info);         // ...     } while (--count);     return total ? total: ret; }  static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, siginfo_t *info, int nonblock) {     // 取出一个信号     ret = dequeue_signal(current, &ctx->sigmask, info);     // 如果没有 pending 的信号,就看是否是非阻塞请求,非阻塞请求就报错跳出;     // 阻塞请求就继续往后走      // 把当前位置加入到信号唤醒地方(这样后续有信号的时候,能够立马切回来)     add_wait_queue( t->sighand->signalfd_wqh, &wait);     for (;;) {         // 取信号         ret = dequeue_signal(current, &ctx->sigmask, info);         // 判断是否还有 pending 的信号;         if (signal_pending(current)) {         }         // 让出 cpu,调度切走         schedule();     }      // 把当前进程从 signalfd_wqh 摘掉     remove_wait_queue( t->sighand->signalfd_wqh, &wait); }
  这里就能非常清晰的看到, 进程有信号的时候,signalfd 句柄就是可读的 。
  signal 和 epoll 的配合
  1    熟悉的 epoll_ctl
  epoll_ctl  注册 signalfd 的时候,调用 signalfd_poll  ,signalfd_poll  会把 epoll 创建的 wait entry 挂到 current->sighand  上。唤醒的时候调用这个 wait 链表的回调。
  2    什么时候唤醒呢?
  唤醒的操作其实不在 signalfd.c 文件中,而是在原有的信号软中断的流程中。
  在内核函数  signalfd_notify  中,会判断进程的 sighand->signalfd_wqh  是否非空,如果非空,说明有人关注这个信号,那么就会通知到对应的 waiter 。
  为了知识的完整性,说个点, signalfd_notify  其实在 timer 定时器的流程中也有调用,但跟我们本次主干没啥关系,这里忽略。
  信号的发送唤醒的简要示意图:
  所有的信号发送都会调用到  send_signal  ,在这个里面实现了唤醒 sighand->signalfd_wqh  链表的操作。从而使得 epoll 感知到 signalfd 可读了(因为来信号了),使得 epoll 从 epoll_wait 出唤醒,然后调用 read 操作,把信号的相关信息从句柄中读出来。 signalfd_notify     -> wake_up (唤醒等待队列,也就是 epoll)         -> ep_poll_callback
  划重点:唤醒在 信号发送 的过程。
  总结
  信号能够像文件一样 read 出来,这种优雅的信号处理方式 得益于 signalfd 的封装 ;  信号是挂在在进程 task_struct 结构体上的, 信号队列非空的时候 signalfd 句柄可读 ;  和 epoll 池的配合同样还是老套路,epoll_ctl 注册的时候调用  .poll  接口挂载 epoll 的 wait entry 到 sighand->signalfd_wqh  之上,信号发送时调用 signalfd_notify  唤醒 epoll ; signalfd 也是一种 匿名 fd 类型 ;

力挺云南精品咖啡豆,瑞幸加码小黑杯线下零售行业的驱动力往往来自很多方面,也造就了一大批成功的企业,比如说精细化运营,比方说线上线下结合比方说极致的口碑和病毒营销,但源头的驱动力,往往是来自靠着对产品的持续打磨和创新失速的爱回收,C2B业务增长乏力尽管国内互联网行业早已脱离了CopytoChina时代,但大洋彼岸一有垂直赛道中头部玩家登陆资本市场,无疑都会掀起国内从业者对这一赛道的重估。从网约车到民宿,莫不如是。而最近,这一百亿补贴图书,拼多多的新算盘当拼多多的百亿补贴杀入图书,会有什么效果?3月31日,拼多多正式开启了多多读书月活动。根据拼多多官方的描述,这次拼多多联合了中信出版社知识出版局青岛出版社等30余家出版社和图书公司研制出世界最大推力火箭发动机,中国人登月稳了近日由我国自主研制的目前世界上推力最大和工程化应用的整体式固体火箭发动机,在航天科技集团四院试车成功。该发动机直径3。5米,推力达500吨,采用高性能纤维复合材料壳体,高装填整体浇德尔塔和拉姆达,谁才是病毒之王?变异毒株已经成为世界上很多个国家新增感染病例里的主导病毒株,所以大家现在也知道了这个新冠突变是很麻烦的,果然突变又来了,德尔塔还没完,新的一个拉姆达又被报道出来。有各种各样的说法,行星撞地球为何偏爱黑龙江?这不又一个陨石坑被发现了说起陨石坑大家觉得不新鲜,月亮啊水星啊这种天体上特别多,但其实陨石坑在地球上很少,尤其在我国其实对于研究人员来说一直很头疼,就是很难找到陨石坑,这对科学家来说是一种遗憾,因为你没有驭由心行自在2022款大蚂蚁上市补贴后售价15。66万元起10月28日,奇瑞新能源2022款大蚂蚁正式上市!2021款大蚂蚁于去年9月22日上市,一年之后,奇瑞新能源再次为我们带来了全新力作。新款大蚂蚁整车共有包含了外观升级驱动升级智能升养狗狗前需要做哪些准备买车,需要考虑全家的需要。而狗狗,作为许多家庭的一分子,也想要在车里拥有自己的一席之地。出去郊游,哪能少了他们可爱调皮的身影?奇瑞大蚂蚁作为一部大五座SUV,以4630191016华为想要重上巅峰,真的只能走IDM模式么?大家都知道华为是5G通讯技术世界领导者,那华为P50手机为何没了5G网络?只因为P50用了高通芯片骁龙888处理器,如果是高通骁龙888我觉得有一种可能就是高通没有把这个5g版的骁Burberry首次亮相中国国际进口博览会为支持中国积极推动对外开放的承诺,博柏利今日宣布首次参加中国国际进口博览会。博柏利标志性嘎巴甸面料的最新迭代产品将首次亮相,以自然场景的沉浸式体验展示其全新的外套系列,礼赞品牌悠久品鉴Rado瑞士雷达表全陶时刻近日,Rado瑞士雷达表全陶时刻媒体品鉴会上海场顺利举行,在惬意且不失活力的氛围中,媒体嘉宾鉴赏了库克船长真我等品牌旗舰系列多款荣膺国际设计大奖的设计师合作款腕表,及即将发布的新品
广汽石墨烯电池续航1000公里?业内专家尚需市场检验近日,广汽埃安发布公告称,自家的石墨烯技术即将进入量产阶段。据了解,广汽埃安的石墨烯基超级快充电池仅需8分钟即可冲入80的电量,NEDC测试下,续航可达1000公里。对此,广州汽车为什么说大吸力并非吸尘器选购的唯一标准,答案一目了然对于一款吸尘器的需求,如果各位觉得只是要求吸力大那就想错了。在目前吸尘器技术蓬勃发展的今天,大吸力只是吸尘器的一个指标而已。就如我在前文分享过LGA9K吸尘器的拖把功能,没错,这还电动拖把实不实用,看看韩国人的清洁神器前几天给大家开箱了LG的A9K无线吸尘器,因为配件和功能较多,所以仅仅只是开箱。本文来给大家分享一下其作为拖把时的体验。其实现在凡是高档的吸尘器,都已经是洗拖一体式了。又有人一拖把比亚迪刀片电池获得现代汽车订单,明年有望供货海外媒体援引知情人士消息显示,比亚迪刀片电池获得了韩国现代汽车集团的认可,并已经成立现代项目部,有望明年实现出口供货。针对此消息,比亚迪董秘表示,不排除在未来与现代合作的可能性。去年三美国国家运输安全委员会车企对车祸中的锂电池危害严重缺乏了解近日美国国家运输安全委员会(NTSB)提出了一些建议,意在提醒消防员和警察在处理锂电池电动车火灾时更充分地做好准备。市面上的电动汽车正在以肉眼可见的速度增加,涉及电动汽车的事故或者解决三元锂安全问题,密度提升9。4,广汽埃安发布弹匣电池电池组是电动汽车的核心零部件,但是其安全性能也一直受到部分消费者质疑。相对的,国家也有相关的测试标准,其中针刺测试是对动力电池对严格的测试之一。国家规定,用一根直径58毫米的金属针91十条新能源汽车行业的每日必读简报(210208)上汽集团宣布,1月份旗下新能源汽车销量5。8万辆,同比增长446。6。2。胡润研究院发布的2020方太胡润财富报告显示,中国高净值人群最青睐的汽车品牌保时捷蝉联榜首,奔驰劳斯莱斯和电动汽车趴窝不用叫拖车,华为曝光了解决此问题的新专利随着技术的进步和社会对环境的关注,电动汽车取代燃油车的趋势也越来越明显。不过,在电动汽车普及之前,车辆续航充电桩布局等问题还亟待解决。与燃油车不同,电动汽车续航耗尽之后,需要用拖车比亚迪上月销售纯电动汽车14463辆,同比大增181昨日,汽车制造商比亚迪公布了其2021年1月份的销售数据。数据显示,上个月该公司新能源汽车销量为20178辆,同比大增183,其中纯电动汽车的销量数据为14463辆,同比增长了18小米回应传闻电动汽车制造业务尚未立项此前,有媒体爆料称,小米已经决定进入汽车行业,未来小米的汽车业务将由小米CEO雷军亲自带队。受此利好消息影响,小米股票一度暴涨10。不过小米并没有让此消息成为石锤。2月21日晚,小富士康高管透露,两辆基于自有平台打造的轻型车将于今年亮相近日,富士康科技集团的高管在记者会上透露,2021年Q4,富士康将会推出两辆采用自家平台打造的轻型车。与此同时,富士康还会推出一辆商用的电动巴士。之所以作为消费类电子产品代工厂的富