浅谈 Signal 与 APC 实现

引言

之前在学习 linux signal 机制实现的时候,发现和 windows 的APC机制有些不谋而合的味道,遂贴出了二者在使用上相同的片段。今天专程花时间对APC的实现进行了分析,好好扒一扒二者在实现上异同之处。 本文的错误或不足之处望大家指正。

本文环境

抛开环境对比分析实现是不可能,要限定一个范围。
本文的 signal 机制参考为 linux 1.0.9
本文的 APC 机制参考为 WRK 1.2

简述signal机制

Signals are a limited form of inter-process communication (IPC), typically used in Unix, Unix-like, and other POSIX-compliant operating systems. A signal is an asynchronous notification sent to a process or to a specific thread within the same process in order to notify it of an event that occurred. Signals originated in 1970s Bell Labs Unix and have been more recently specified in the POSIX standard.

以上是摘自wiki 的说明,大意是

在 POSIX 中规定了信号标准,信号是发送到进程或同一进程中的特定线程的异步通知,以通知发生的事件。

由于 信号的处理过程和中断类似(注册中断处理函数,等待信号到达等),所以有时候又称为软中断信号。

简述APC机制

首先贴一下APC 的全称 Asynchronous procedure call,解释为异步过程调用。
wike 对于 APC 的解释如下:

In Windows, an asynchronous procedure call (abbreviated APC) is a function that executes asynchronously in the context of a specific thread.[1] APCs can be generated by the system (kernel-mode APCs) or by an application (user mode APCs).

在一个指定的线程上下文上异步执行一个函数,APC 可以在应用层或内核层设置。

二者的异同

二者虽说都是异步调用,但是signal 是在收到信号时进行调用,而APC只是一种推迟执行的异步函数调用,二者的具体交付时间均不可控,只能在一定范围内的可控。

从实现角度看Signal

先看 linux 的信号安装,这只是其中一种方式

// 在指定信号上指定处理函数
asmlinkage int sys_signal(int signum, unsigned long handler)
{
    struct sigaction tmp;
    // 对 signum 参数做检查并限制
    if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
        return -EINVAL;
    // 对处理函数地址进行检查
    if (handler >= TASK_SIZE)
        return -EFAULT;
    tmp.sa_handler = (void (*)(int)) handler;
    tmp.sa_mask = 0;
    tmp.sa_flags = SA_ONESHOT | SA_NOMASK;
    tmp.sa_restorer = NULL;
    // 返回原本的处理函数
    handler = (long) current->sigaction[signum-1].sa_handler;
    // 对结构体直接赋值
    current->sigaction[signum-1] = tmp;
    // 主要是对 tmp.sa_handler 进行检查
    // 如果是系统提供的默认值,则做相应的处理
    // 这个函数不影响分析
    check_pending(signum);
    return handler;
}

从以上代码可以简单看出几点,linux 信号处理放在一个struct sigaction结构中,每个进程的task_struct中有一个 称为sigactionsigaction数组。

提一下信号的不可靠性
另外,只要有相应的信号到达,信号处理函数就有概率被调用。
为什么说有概率 由于linux 使用 task_struct 中的unsigned long signal的位来标示信号是否达到,所以任意一个信号只存在到达和未到达状态,这样信号就可能发生丢失等不可靠的情况。
例如连续发送两次某信号,后面的一次信号就有概率会”覆盖”掉前一个,实际就会发生 信号处理函数只调用一次的情况。

具体看代码send_sig 的实现

static int generate(unsigned long sig, struct task_struct * p)
{
    <
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值