UNPV2 学习:POSIX 实时信号

编程入门 行业动态 更新时间:2024-10-24 09:22:20

UNPV2 学习:POSIX <a href=https://www.elefans.com/category/jswz/34/1771422.html style=实时信号"/>

UNPV2 学习:POSIX 实时信号

POSIX 实时信号

信号可以被分为两组:

  1. 信号值在 SIGRTMIN 与 SIGRTMAX 之间的实时信号
  2. 其它所有的信号,如 SIGALRM,SIGINT,SIGKILL 等

实时信号的工作特点:

  1. 信号被入队。同一个信号多次触发时,事件以 FIFO 的方式入队。
  2. 当多个在 SIGRTMIN 到 SIGRTMAX 之间未屏蔽的信号被入队时,数值小的信号会在数值大的信号前发送,这意味着 SIGRTMIN 信号的优先级最高。
  3. 当一个非实时信号触发时,信号处理函数的唯一参数是信号值。实时信号比这些信号携带更多的信息,实时信号的信号处理函数支持带一个 siginfo_t 结构体类型的信息。
  4. 一些新的函数被定义以支持实时信号,这些新函数允许发送者传输一个 sigval 结构。例如 sigqueue 函数替代 kill 函数来发送信号到某些进程。

实时信号由下列 Posix.1 特性产生 ,它们由包含在传递给信号处理程序的 siginfo_t 结构中的 si_code 值标识。

  • SI_ASYNCIO 异步 I/O 请求完成
  • SI_MESGQ 新的消息被投递到空的 Posix 消息队列中
  • SI_QUEUE 使用 sigqueue 函数发送信号
  • SI_TIMER 一个 timer_settime 函数设置的定时器时间耗尽
  • SI_USER 此信号使用 kill 函数发送

linux sigaction 函数

linux 中可以使用 sigaction 函数注册实时信号的处理函数,非实时的信号处理函数也可以使用此函数注册并携带更多的信息,其原型如下:

int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);

signum 为待设定的信号值,act 为信号处理函数属性的封装结构,oldact 用于返回旧的配置。sigaction 结构体的定义如下:

struct sigaction {void     (*sa_handler)(int);void     (*sa_sigaction)(int, siginfo_t *, void *);sigset_t   sa_mask;int        sa_flags;void     (*sa_restorer)(void);};

sa_handler 用以兼容旧的只以信号值为参数的信号处理函数注册,sa_sigaction 为新的信号处理函数原型,sa_mask 设定信号掩码,sa_flags 设置一些 flags,sa_restorer 用于设定从信号处理函数中恢复旧的现场需要执行的函数。在 linux 内核信号机制需要解决的两个关键问题 这篇博文中有对 sa_restorer 的相关描述,libc 中的实现是一个调用 rt_sigreturn 系统调用的函数。

siginfo_t 结构的定义如下:

siginfo_t {int      si_signo;     /* Signal number */int      si_errno;     /* An errno value */int      si_code;      /* Signal code */int      si_trapno;    /* Trap number that causedhardware-generated signal(unused on most architectures) */pid_t    si_pid;       /* Sending process ID */uid_t    si_uid;       /* Real user ID of sending process */int      si_status;    /* Exit value or signal */clock_t  si_utime;     /* User time consumed */clock_t  si_stime;     /* System time consumed */union sigval si_value; /* Signal value */int      si_int;       /* POSIX.1b signal */void    *si_ptr;       /* POSIX.1b signal */int      si_overrun;   /* Timer overrun count;POSIX.1b timers */int      si_timerid;   /* Timer ID; POSIX.1b timers */void    *si_addr;      /* Memory location which caused fault */long     si_band;      /* Band event (was int inglibc 2.3.2 and earlier) */int      si_fd;        /* File descriptor */short    si_addr_lsb;  /* Least significant bit of address(since Linux 2.6.32) */void    *si_lower;     /* Lower bound when address violationoccurred (since Linux 3.19) */void    *si_upper;     /* Upper bound when address violationoccurred (since Linux 3.19) */int      si_pkey;      /* Protection key on PTE that causedfault (since Linux 4.6) */void    *si_call_addr; /* Address of system call instructionint      si_syscall;   /* Number of attempted system call(since Linux 3.5) */unsigned int si_arch;  /* Architecture of attempted system call(since Linux 3.5) */

不同的信号会填充 siginfo_t 结构中的不同字段,例如 sigaction manual 中对 SIGBUS、SIGSEGV 等信号填充的字段的描述信息如下:

* SIGILL,  SIGFPE, SIGSEGV, SIGBUS, and SIGTRAP fill in si_addr with the address of the fault.  Onsome architectures, these signals also fill in the si_trapno field.Some  suberrors  of  SIGBUS,  in  particular  BUS_MCEERR_AO  and  BUS_MCEERR_AR,  also  fill  insi_addr_lsb.   This field indicates the least significant bit of the reported address and there‐fore the extent of the corruption.  For example, if a full page was corrupted, si_addr_lsb  con‐tains  log2(sysconf(_SC_PAGESIZE)).   When SIGTRAP is delivered in response to a ptrace(2) event(PTRACE_EVENT_foo), si_addr is not populated, but si_pid and si_uid are populated with  the  re‐spective process ID and user ID responsible for delivering the trap.  In the case of seccomp(2),the tracee will be shown as delivering the event.  BUS_MCEERR_* and si_addr_lsb  are  Linux-spe‐cific extensions.The SEGV_BNDERR suberror of SIGSEGV populates si_lower and si_upper.The SEGV_PKUERR suberror of SIGSEGV populates si_pkey.

这些信号会填充 si_addr 字段以命名异常地址的位置,在一些结构上还可能会填充其它的字段。

siginfo_t 的一个使用场景

在 dpdk 支持网卡热插拔技术需要解决的几个关键问题 这篇文章中,我描述了使用 sigbus 信号携带的 siginfo_t 结构中的 si_addr 字段来处理网卡热拔出时程序仍旧访问网卡 bar 空间触发总线异常的问题。

dpdk 中注册 sigbus 信号处理函数的代码如下:

				struct sigaction action;.................................sigemptyset(&mask);sigaddset(&mask, SIGBUS);action.sa_flags = SA_SIGINFO;action.sa_mask = mask;action.sa_sigaction = sigbus_handler;sigbus_need_recover = !sigaction(SIGBUS, &action, &sigbus_action_old);

可以看到它设置了 SA_SIGINFO 标志以支持 SIGBUS 信号携带一个 siginfo_t 结构,在 sigbus_handler 函数中使用如下代码访问 si_addr 字段:

ret = rte_bus_sigbus_handler(info->si_addr);

rte_bus_sigbus_handler 中负责查询异常的地址是否属于某个总线,并调用总线注册的 sigbus_handler 处理。

更多推荐

UNPV2 学习:POSIX 实时信号

本文发布于:2024-02-10 13:35:59,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1675721.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:实时   信号   POSIX

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!