Minha melhor ideia atual. Um pouco de pensamento ainda está de volta, mas tenho certeza que funcionará.
O truque é: o atomic_swap
e um ponteiro global (chame isso de SigAction* top
). Ele serve como tanto de spinlock quanto como o ponteiro para o último elemento da pilha de sinais.
Assim:
* se top == NULL
, atomic_swap(top, myPointer)
adquire o bloqueio.
* se top != NULL
, atomic_swap(top, myPointer)
colocar o myPointer no topo, enquanto o myPointer terá o elemento superior anterior da pilha.
* A pilha é uma lista encadeada, cada myPointer->next
contém o próximo elemento.
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;
}
}