Article de reference

définir le contexte

typedef struct { ucontext_t * uc_link ; sigset_t uc_sigmask ; stack_t uc_stack ; mcontext_t uc_mcontext ; ... } ucontext_t ; uc_link pointe vers le contexte qui sera repris lors...

typedef struct { ucontext_t * uc_link ; sigset_t uc_sigmask ; stack_t uc_stack ; mcontext_t uc_mcontext ; ... } ucontext_t ;

uc_linkpointe vers le contexte qui sera repris lorsque le contexte actuel se termine, si ce dernier a été créé avec makecontext(un contexte secondaire). uc_sigmasksert à stocker l'ensemble des signaux bloqués dans le contexte, et uc_stackreprésente la pile utilisée par ce contexte. uc_mcontextstocke l'état d'exécution , y compris tous les registres et indicateurs du processeur , le pointeur d'instruction et le pointeur de pile ; est un type opaque .mcontext_t

Les fonctions sont :

  • intsetcontext(constucontext_t*ucp)
    Cette fonction transfère le contrôle au contexte dans ucp. L'exécution reprend à partir du point où le contexte a été stocké dans ucp. setcontextne retourne pas.
  • intgetcontext(ucontext_t*ucp)
    Enregistre le contexte actuel ucp. Cette fonction renvoie `true` dans deux cas : après l’appel initial, ou lorsqu’un thread bascule vers le contexte via `get` ucpou setcontext`return` swapcontext. La getcontextfonction ne fournit pas de valeur de retour permettant de distinguer les cas (sa valeur de retour sert uniquement à signaler une erreur), le programmeur doit donc utiliser une variable d’indicateur explicite, qui ne doit pas être un registre et doit être déclarée `volatile` pour éviter la propagation de constantes ou d’autres optimisations du compilateur .
  • voidmakecontext(ucontext_t*ucp,void(*func)(),intargc,...)
    Cette makecontextfonction établit un thread d'exécution alternatif dans ucp, préalablement initialisé à l'aide de getcontext. Le ucp.uc_stackmembre doit pointer vers une pile de taille appropriée ; la constante SIGSTKSZest couramment utilisée. Lorsque ucpest sauté à l'aide de setcontextou swapcontext, l'exécution commencera au point d'entrée de la fonction pointée par func, avec argcles arguments spécifiés. Lorsque funcse termine, le contrôle est rendu à ucp.uc_link.
  • intswapcontext(ucontext_t*oucp,ucontext_t*ucp)
    Transfère le contrôle ucpet enregistre l'état d'exécution actuel dans oucp.

Exemple

L'exemple ci-dessous illustre un itérateur utilisant setcontext.

#include <stdio.h> #include <stdlib.h> #include <ucontext.h> #include <signal.h>/* Les trois contextes : * (1) main_context1 : Le point de la fonction main vers lequel la boucle retournera. * (2) main_context2 : Le point de la fonction main vers lequel le contrôle de la boucle sera transféré par changement de contexte. * (3) loop_context : Le point de la fonction loop vers lequel le contrôle de la fonction main sera transféré par changement de contexte. */ ucontext_t main_context1 , main_context2 , loop_context ;/* La valeur de retour de l'itérateur. */ volatile int i_from_iterator ;/* This is the iterator function. It is entered on the first call to * swapcontext, and loops from 0 to 9. Each value is saved in i_from_iterator, * and then swapcontext used to return to the main loop. The main loop prints * the value and calls swapcontext to swap back into the function. When the end * of the loop is reached, the function exits, and execution switches to the * context pointed to by main_context1. */voidloop(ucontext_t*loop_context,ucontext_t*other_context,int*i_from_iterator){inti;for(i=0;i<10;++i){/* Write the loop counter into the iterator return location. */*i_from_iterator=i;/* Save the loop context (this point in the code) into ''loop_context'', * and switch to other_context. */swapcontext(loop_context,other_context);}/* The function falls through to the calling context with an implicit * ''setcontext(&loop_context->uc_link);'' */}intmain(void){/* The stack for the iterator function. */chariterator_stack[SIGSTKSZ];/* Flag indicating that the iterator has completed. */volatileintiterator_finished;getcontext(&loop_context);/* Initialise the iterator context. uc_link points to main_context1, the * point to return to when the iterator finishes. */loop_context.uc_link=&main_context1;loop_context.uc_stack.ss_sp=iterator_stack;loop_context.uc_stack.ss_size=sizeof(iterator_stack);/* Initialisation de loop_context pour que swapcontext démarre la boucle. Le transtypage * (void (*)(void)) sert à éviter un avertissement du compilateur, mais il n'a aucune incidence sur le comportement de la fonction. */ makecontext ( & loop_context , ( void ( * )( void )) loop , 3 , & loop_context , & main_context2 , & i_from_iterator ); /* Effacement de l'indicateur de fin. */ iterator_finished = 0 ;/* Sauvegarde le contexte actuel dans main_context1. Lorsque la boucle est terminée, * le flux de contrôle retournera à ce point. */ getcontext ( & main_context1 ); if ( ! iterator_finished ) { /* Initialise iterator_finished afin que lorsque le getcontext précédent est * retourné via uc_link, la condition if ci-dessus soit fausse et que l' itérateur ne soit pas * redémarré. */ iterator_finished = 1 ; while ( 1 ) { /* Sauvegarde ce point dans main_context2 et bascule vers l'itérateur. * Le premier appel lancera la boucle. Les appels suivants basculeront vers * le swapcontext dans la boucle. */ swapcontext ( & main_context2 , & loop_context ); printf ( "%d " , i_from_iterator ); } } return 0 ; }

REMARQUE : cet exemple est incorrect , mais peut fonctionner comme prévu dans certains cas. La fonction makecontextexige que les paramètres supplémentaires soient de type `int` int, or l’exemple utilise des pointeurs. Par conséquent, l’exemple peut échouer sur les machines 64 bits (en particulier les architectures LP64 ). Ce problème peut être contourné en décomposant puis en reconstruisant les valeurs 64 bits, mais cela entraîne une perte de performance.sizeof(void*)>sizeof(int)

Sur les architectures où les types `int` et `pointer` ont la même taille (par exemple, x86-32, où les deux types sont codés sur 32 bits), il est possible de passer des pointeurs comme arguments à `makecontext()` après `argc`. Cependant, cette méthode n'est pas portable, n'est pas conforme aux normes et ne fonctionne pas sur les architectures où les pointeurs sont plus grands que les entiers. Néanmoins, à partir de la version 2.8, glibc apporte des modifications pour makecontext(3)autoriser cette pratique sur certaines architectures 64 bits (par exemple, x86-64).

Pour obtenir et définir un contexte, un contexte plus petit peut s'avérer utile :

#include <stdio.h> #include <ucontext.h> #include <unistd.h>int main ( int argc , const char * argv []) { ucontext_t context ; getcontext ( & context ); puts ( "Hello world" ); sleep ( 1 ); setcontext ( & context ); return 0 ; }

Cela crée une boucle infinie car le contexte contient le compteur de programme.

Plus d articles de Worldlex Wiki

Revenez a l index pour explorer davantage de pages sur l histoire, la science, la culture, la geographie et la societe en francais.

Explorer l index