【问题标题】:Why some system calls shield SIGPROF signal under strace为什么有些系统调用会在 strace 下屏蔽 SIGPROF 信号
【发布时间】:2019-11-04 05:58:26
【问题描述】:

当我 strace 这段代码时


void printMsg();

int main() {
  signal(SIGPROF, printMsg);

  struct itimerval tick;
  memset(&tick, 0, sizeof(tick));

  tick.it_value.tv_sec = 1;  // sec
  tick.it_value.tv_usec = 0; // micro sec.
  tick.it_interval.tv_sec = 0;
  tick.it_interval.tv_usec = 0;

  setitimer(ITIMER_PROF, &tick, NULL);

  while(1) {
    ;
  }

  return 0;
}

void printMsg() {
    printf("%s","Hello World!!\n");
}

我在 1 秒后收到了SIGPROF 信号,如预期的那样

...
05:54:10 setitimer(ITIMER_PROF, {it_interval={0, 0}, it_value={1, 0}}, NULL) = 0
05:54:11 --- SIGPROF {si_signo=SIGPROF, si_code=SI_KERNEL} ---
...

但是当我在while(1) 中添加write(2, "", 0)read(2, "", 0) 之类的系统调用并再次strace 时,看起来SIGPROF 无法被触发。但是while(1)中的time(0)可以正常触发SIGPROF。

顺便说一句,我使用这段代码来模拟下面的 PHP 脚本,它忽略了 PHP-FPM SAPI 下的时间限制,

<?php
set_time_limit(5);  // PHP uses setitimer(ITIMER_PROF) to implement this function
while (true) {
    flush();       // PHP uses write(<fd>, "", 0) to implement this function
}

【问题讨论】:

  • 如何得到输出格式?我的意思是你使用什么系统/编译器/工具。你能说吗?顺便说一句,我在while 循环中添加了write(1, STDIN_FILENO, 12); 并捕获了信号。
  • 请注意,您的信号处理函数printMsg() 是不安全的。您只能从信号处理程序中安全地调用异步信号安全函数。 printf() 不是异步信号安全的。在 Linux 上,请参阅 man7.org/linux/man-pages/man7/signal-safety.7.html
  • @snr 是的,write(1, STDIN_FILENO, 12); 有效。我写了while (1) write(2, "", 0),又检查了一遍,这个空的write确实屏蔽了信号SIGPROF。我使用 gcc 版本 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.4)

标签: c linux strace


【解决方案1】:

代码使用 ITIMER_PROF 触发 SIGPROF,它在进程执行时进行计数,或者系统代表进程运行时进行计数。

当进程进入“读”或“写”调用时,它不是“运行”。进程进入 IO 等待(系统会将 CPU 分配给其他进程)。当进程处于 IOWait 时,计时器不会移动。当有执行处理的系统调用(主要在系统空间中)时 - 例如time() 是一个紧密的循环,计时器会移动。

https://www.tecmint.com/linux-process-management/中查看有关进程状态的更多信息

如果您想测量“时钟”时间,请考虑将 timer_create 与 CLOCK_REALTIME 或 CLOCK_MONOTONIC 一起使用

【讨论】:

  • 或使用ITIMER_REALSIGALRM
  • 是否保证阻塞中的进程无法接收信号,即在 IO 等待期间? -1 来自我。顺便说一句,你应该看看我的其他评论。它是如何工作的?
  • 我相信进程可以在 IOWait 期间获得信号(例如 SIGPIPE、SIGALRM),而无需通过“运行”模式。在单线程模式下,一旦处理了一个信号,系统调用就会以 EINTR 结束。
  • @snr 我试过write(1, STDIN_FILENO, 12); 并且它有效,但我认为write() 接受void* buf 作为它的第二个参数,而不是一个int #define STDIN_FILENO 0
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-02
相关资源
最近更新 更多