나는 많은 수의 신호를 처리하는 도구를 개발 중입니다.다른기호) 및 sigaction()
.
새 신호가 들어오고 이전 신호가 신호 처리기 내부에 있는 경우 이 상황을 처리해야 합니다. 따라서 다음 "스택"을 처리할 수 있어야 합니다.
- 정상적인 과정
- 매니저신호 1
- 매니저신호 2
- ...그리고 아마도 더 많은 신호 처리기가 있을 것입니다...
(내가 아는 한, 신호 핸들러는 자체 컨텍스트에서 실행되므로 실제 스택은 없지만 이것이 내 문제를 설명하는 방법입니다.)
glibc2 API를 사용하고 있습니다.
문제는 절망적이지 않습니다(주 실행 흐름에서 나중에 처리되도록 기본 프로세스의 재진입 데이터 구조에 신호 정보를 전달할 수 있음).핸들러가 "스택"의 첫 번째 핸들러인지 확인하는 신뢰할 수 있는 방법이 필요합니다.
신호를 마스킹하는 것은 선택 사항이 아니며, (결합된 신호에서) 신호 손실을 최소화하는 것이 우선입니다.
나는해야한다믿을 수 있는방법. 전역 sigatomic_t를 스핀록으로 사용하는 것도 문제가 됩니다. 시작 후 즉시 새 신호가 나타나지 않을 것이라고 보장할 수 없기 때문입니다.신호 1핸들러(잠금 획득을 시도하기 전)
매뉴얼과 glibc 문서를 파헤친 후, 신호 처리기가 첫 번째 처리기인지 확인할 수 있는 신뢰할 수 있는 방법을 찾지 못했습니다. 이것이 가능한가?
답변1
신호를 차단하도록 신호 처리기를 구성한 다음 이 신호를 받았다고 주석을 달고 차단을 해제하세요.
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 */
}
마지막 보류 중인_signals.empty() 확인과 iret 사이에 작은 경쟁 조건이 있다는 점에 유의하세요. 메인 코드에서 일부 검사를 수행한다면 그대로 두겠습니다. 현재 가지고 있는 신호의 양을 고려하면 어쨌든 빨리 처리될 것입니다. 그렇지 않으면 마지막에 신호 시간을 다시 측정하고 반환하기 전에 보류 중인 신호가 여전히 비어 있는지 확인할 수 있습니다.
답변2
다른 접근 방식은 다음과 같습니다.
다양한 신호를 수신할 수 있지만 신호 세트는 제한되어 있습니다. 또한 신호가 도착하는 순서에는 크게 신경 쓰지 않으므로 수신된 신호 수를 간단히 계산할 수 있습니다.
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
코어와 스레드가 여러 개인 경우 접두사가 필요할 수 있습니다 .
답변3
내 최고의 아이디어. 일부 아이디어는 아직 돌아오지 않았지만 성공할 것이라고 확신합니다.
비결은 다음과 같습니다. atomic_swap
그리고 전역 포인터(라고 부릅니다 SigAction* top
). 그것은 다음과 같이 작용한다스핀 잠금과 신호 스택의 마지막 요소에 대한 포인터입니다.
따라서 * if top == NULL
, atomic_swap(top, myPointer)
잠금을 획득합니다. * if top != NULL
, atomic_swap(top, myPointer)
myPointer를 스택 맨 위에 놓으면 myPointer는 스택의 이전 최상위 요소를 갖게 됩니다. * 스택은 연결된 목록이며 각 연결된 목록에는 myPointer->next
다음 요소가 포함됩니다.
SigAction* top = NULL;
void handler(SigAction* action) {
SigAction bkp;
restart:
bkp = action;
atomic_swap(&top, &action);
if (!action) { // we acquired the lock
run_handler(action);
atomic_swap(&top, &action); // release the lock
if (action!= bkp) { // if there is a new element in the stack
action = bkp->next;
goto restart;
}
} else { // the lock is not ours
action->next = bkp;
}
}