2017-02-18 1 views
0

Je construis un planificateur de threads d'espace utilisateur préemptif qui utilise un temporisateur pour interrompre les threads et basculer entre eux en fonction de la priorité. Cependant, une fois qu'un thread est interrompu, je n'arrive pas à le laisser finir; recommencez le. Est ce que je demande même possible en utilisant swapcontext? Le résultat de ce code, qui devrait permettre à itake5seconds() de se terminer, ne fait que répéter le message "Hello" encore et encore.Comment puis-je reprendre l'exécution d'une fonction (ne pas la redémarrer) en utilisant swapcontext()?

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#include <time.h> 
#include <sys/time.h> 
#include <ucontext.h> 

static ucontext_t mainc, newthread; 

void itake5seconds() 
{ 
    puts("Hello. I take 5 seconds to run."); 
    sleep(5); 
    puts("And I'm done! Wasn't that nice?"); 
} 

void timer_handler(int signum) 
{ 
    puts("Doing some scheduler stuff."); 
    swapcontext(&mainc, &newthread); 
} 

int main(int argc, char* argv[]) 
{ 
    struct sigaction sa; 

    memset(&sa, 0, sizeof(sa)); 
    sa.sa_handler = &timer_handler; 
    sigaction(SIGALRM, &sa, NULL); 

    getcontext(&newthread); 
    newthread.uc_stack.ss_sp = malloc(5000); 
    newthread.uc_stack.ss_size = 5000; 
    newthread.uc_link = &mainc; 
    makecontext(&newthread, &itake5seconds, 0); 

    struct itimerval timer; 
    timer.it_value.tv_sec = 0; 
    timer.it_value.tv_usec = 500000; 
    timer.it_interval.tv_sec = 0; 
    timer.it_interval.tv_usec = 500000; 

    setitimer(ITIMER_REAL, &timer, NULL); 

    while(1); 

    return 0; 
} 

Répondre

0

Votre code appelle une fonction "dangereuse" dans le gestionnaire de signaux (swapcontext). Par conséquent, le comportement de votre programme est "indéfini".

De man 7 signal:

Une fonction de gestionnaire de signal doit être très prudent, car le traitement ailleurs peut être interrompu à un moment arbitraire dans l'exécution du programme. POSIX a le concept de "fonction sûre". Si un signal interrompt l'exécution d'une fonction dangereuse et que le gestionnaire appelle une fonction dangereuse, alors le comportement du programme n'est pas défini.

Voir la section « Exemple de contexte SVID manipulation » Complete Context Control pour un exemple de la façon dont vous pouvez travailler cela avec un gestionnaire de signal. Mais fondamentalement, vous utiliseriez une variable globale volatile int pour marquer que votre gestionnaire de signal a été appelé et faites plutôt l'appel swapcontext à partir du code normal (c'est-à-dire du code qui ne fonctionne pas dans le contexte de la gestion du signal).

0

Le problème était que je ne sauvegardais pas le contexte d'exécution actuel que swapcontext() renvoie à son premier paramètre.

+0

Pouvez-vous fournir le code mis à jour pour que tout le monde puisse le voir? – Mike