2013-03-27 8 views
6

Ho ridotto un enorme codice di schedulatore di fibra che stava producendo il problema nelle righe sottostanti.
Quello che mi aspetto è un ritorno pulito al contesto, passato al gestore, ogni volta.
Quello che ottengo è "Handler." Stampato tre volte e poi un errore di segmentazione.L'utilizzo del terzo parametro (contesto void * di un gestore di sigaction con SIG_INFO ha come risultato un errore di segmentazione

#include <ucontext.h> 
#include <signal.h> 
#include <stdio.h> 

ucontext_t currently_executed_context; 

void handler_sigusr1(int signum, siginfo_t* siginfo, void* context) 
{ 
    currently_executed_context = (*(ucontext_t*)context); 

    printf("Handler. "); 
    setcontext(&currently_executed_context); 
} 

int main() 
{ 
    setbuf(stdout,0); 

    struct sigaction action_handler; 

    action_handler.sa_sigaction = handler_sigusr1; 
    action_handler.sa_flags = SA_SIGINFO; 

    sigaction(SIGUSR1,&action_handler,NULL); 

    for(;;) { kill(getpid(),SIGUSR1); sleep(1); } 

    return 0; 
} 

Utilizzato sia gcc-4.4.3 che gcc-4.4.5 su due diverse distribuzioni Linux.

+0

Non sicuro al 100% su questo, ma hai davvero bisogno di copiare il 'ucontext_t' in questo modo? Invece, fai semplicemente 'setcontext ((ucontext_t *) context);' nel tuo gestore (lanciare il 'void *' al tipo giusto e passarlo su ...). – twalberg

+0

È sempre più sicuro prendere i dati a cui punta un puntatore (quando l'oggetto originale non è necessario o enorme), specialmente in una situazione in cui potresti perderlo. Inoltre, a causa della mancanza di idee e di diverse ore di modifiche, ho già provato tutte le varianti di quella soluzione (e l'ho persino ripensato ora per sicurezza) - no go. –

+0

In generale, sono d'accordo sulla sicurezza, ma ho notato che la pagina man di 'setcontext()' afferma che 'ucontext_t' * deve * essere uno che proviene da' getcontext() ',' makecontext() ', o come parametro passato a un gestore di segnali, che la copia manuale sorta ignora. Non sono sicuro di come fare una copia in byte della struttura potrebbe invalidarlo, ma ho pensato che non faceva male a chiedere ... – twalberg

risposta

1

A questo punto, la mia ricerca del problema può essere fornita come risposta parziale.

In primo luogo, ho trovato this article, che è vecchio e non cita alcuna fonte ufficiale di informazioni: http://zwillow.blogspot.com/2007/04/linux-signal-handling-is-broken.html. Questa è una citazione pertinente:

Secondo problema: non è possibile utilizzare setcontext() per lasciare il gestore di segnale e passare a un altro contesto precedentemente salvato. (O, se è per questo, non è possibile utilizzarlo per tornare alla stessa contesto passato come argomento al gestore del segnale.) In altre parole, come gestore di segnale

static void sighandler(
    int signo, siginfo_t *psi, void *pv) 
{ 
    memcpy(puc_old, pv, sizeof(ucontext_t)); 
    /* choose another context to dispatch */ 
    setcontext(puc_another); 
} 

non funziona. Non ripristina la maschera di segnale specificata in puc_other, non ristabilisce stack di segnali alternativi, ecc. Tuttavia, questo schema funziona perfettamente su Solaris.

Se qualcuno può confermare la parte su Solaris, sarebbe apprezzato.

In secondo luogo, dopo aver parlato con un docente universitario, ho capito che l'impostazione/lo scambio di un contesto da un gestore di segnale non è così semplice come farlo in altre situazioni. Purtroppo, la persona che mi ha spiegato questo non ha potuto fornire ulteriori dettagli al momento.

Così, entrambe le mie fonti non sembrano del tutto affidabili, ma sono comunque indizi.