Linux
新信號在信號處理程序中執行時到達,如何確定哪個是第一個?
我正在開發一種工具來處理大量信號(具有不同的符號)
sigaction()
。如果有新信號到來,而前一個信號在信號處理程序中,我需要處理這種情況。因此,我需要能夠處理以下“堆棧”:
- 正常流程
- signal1的處理程序
- signal2的處理程序
- …可能還有更多的信號處理程序…
(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
如果有多個核心和執行緒,它可能需要一個前綴。