Linux

新信號在信號處理程序中執行時到達,如何確定哪個是第一個?

  • September 5, 2015

我正在開發一種工具來處理大量信號(具有不同的符號)sigaction()

如果有新信號到來,而前一個信號在信號處理程序中,我需要處理這種情況。因此,我需要能夠處理以下“堆棧”:

  1. 正常流程
  2. signal1的處理程序
  3. signal2的處理程序
  4. …可能還有更多的信號處理程序…

(Afaik 沒有真正的堆棧,因為信號處理程序在它們自己的上下文中執行,但這就是我可以說明我的問題的方式。)

我正在使用glibc2 api。

問題並非沒有希望(我可以將信號資訊傳遞給主程序中的可重入資料結構,以便稍後從主執行流中處理),但是我需要一種可靠的方法來從處理程序中找出,如果它是第一個是否在“堆棧”上。

屏蔽信號是不行的,最大程度地減少信號損失(來自合併的信號)是重中之重。

我需要可靠的方法。使用全域 sigatomic_t 作為自旋鎖也是有問題的,因為我不能保證新信號不會在signal1處理程序開始之後(但在嘗試獲取鎖之前)到來。

在對手冊和 glibc 文件進行了大量探勘之後,我沒有找到任何可靠的方法讓信號處理程序找出他是否是第一個。有可能嗎?

將您的信號處理程序配置為屏蔽信號,然後在註釋您收到此信號後取消屏蔽。

volatile_t sig_atomic_t signal_count;
void mysignalhandler(int signo) {
  sig_atomic_t depth = ++signal_count;
  pending_signals.push(signo)
  if (depth > 1) return;
  sigprocmask(<unblock all signals>)

   while (!pending_signals.empty())
      /* Process pending_signals */
}

請注意,在最後一個 pending_signals.empty() 檢查和 iret 之間有一個小的競爭條件。如果您要在主程式碼中進行一些檢查,我會保留它,考慮到您的信號數量,它可能很快就會被處理。否則,您可以在最後再次為信號計時,並在返回之前檢查 pending_signals 是否仍為空。

這是一種不同的方法:

您可能會收到許多不同的信號,但信號的集合是有限的。另外,我們不太關心他們到達的順序,所以我們可以簡單地計算我們收到的信號數量:

long signals[SIGRTMAX];
int signal_handler(int signum) {
   signals[argc]++;

   /* Locklessly process the contents of signals */
}

gcc -O1 -masm=intel將其轉換為一條指令:

add QWORD PTR signals[0+rdi*8], 1

儘管LOCK如果有多個核心和執行緒,它可能需要一個前綴。

引用自:https://unix.stackexchange.com/questions/227580