Articulo de referencia

establecer contexto

setcontext es una de una familia de funciones de biblioteca de C (las otras son getcontext , makecontext y swapcontext ) utilizadas para el control de contexto . La familia perm...

setcontext es una de una familia de funciones de biblioteca de C (las otras son getcontext , makecontext y swapcontext ) utilizadas para el control de contexto . La familia permite la implementación en C de patrones de flujo de control avanzados como iteradores , fibras y corrutinas . Pueden verse como una versión avanzada de setjmp/longjmp ; mientras que este último permite solo un único salto no local en la pila , permite la creación de múltiples hilos de control cooperativos , cada uno con su propia pila. setcontext setcontext

Especificación

setcontextse especificó en POSIX .1-2001 y en la Especificación Única de Unix , versión 2, pero no todos los sistemas operativos tipo Unix las proporcionan. POSIX .1-2004 dejó obsoletas estas funciones, [1] y en POSIX .1-2008 se eliminaron, y se indicó que POSIX Threads era un posible reemplazo.

Definiciones

Las funciones y los tipos asociados se definen en el archivo de encabezadoucontext.h del sistema . Esto incluye el tipo con el que operan las cuatro funciones: ucontext_t

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

uc_linkapunta al contexto que se reanudará cuando salga del contexto actual, si el contexto se creó con makecontext(un contexto secundario). uc_sigmaskse utiliza para almacenar el conjunto de señales bloqueadas en el contexto, y uc_stackes la pila utilizada por el contexto. uc_mcontextalmacena el estado de ejecución , incluidos todos los registros y los indicadores de la CPU , el puntero de instrucción y el puntero de pila ; es un tipo opaco . mcontext_t

Las funciones son:

  • int setcontext(const ucontext_t *ucp)
    Esta función transfiere el control al contexto en ucp. La ejecución continúa desde el punto en el que se almacenó el contexto en ucp. setcontextno retorna.
  • int getcontext(ucontext_t *ucp)
    Guarda el contexto actual en ucp. Esta función retorna en dos casos posibles: después de la llamada inicial o cuando un hilo cambia al contexto en ucpvia setcontexto swapcontext. La getcontextfunción no proporciona un valor de retorno para distinguir los casos (su valor de retorno se usa únicamente para señalar un error), por lo que el programador debe usar una variable de indicador explícita, que no debe ser una variable de registro y debe declararse volátil para evitar la propagación constante u otras optimizaciones del compilador .
  • void makecontext(ucontext_t *ucp, void (*func)(), int argc, ...)
    La makecontextfunción establece un hilo de control alternativo en ucp, que se ha inicializado previamente con getcontext. El ucp.uc_stackmiembro debe apuntar a una pila de tamaño adecuado; la constante SIGSTKSZse utiliza habitualmente. Cuando ucpse salta a utilizando setcontexto swapcontext, la ejecución comenzará en el punto de entrada a la función a la que apunta func, con argclos argumentos especificados. Cuando functermina, el control se devuelve a ucp.uc_link.
  • int swapcontext(ucontext_t *oucp, ucontext_t *ucp)
    Transfiere el control a ucpy guarda el estado de ejecución actual en oucp.

Ejemplo

El siguiente ejemplo demuestra un iterador que utiliza setcontext.

#include <stdio.h> #include <stdlib.h> #include <ucontext.h> #include <señal.h> 
 
 
 

/* Los tres contextos: 
* (1) main_context1 : El punto en main al que regresará el bucle. 
* (2) main_context2 : El punto en main al que 
fluirá el control desde el bucle * cambiando de contexto. 
* (3) loop_context : El punto en el bucle al que 
fluirá el control desde main * cambiando de contexto. */ 
ucontext_t main_context1 , main_context2 , loop_context ;   

/* El valor de retorno del iterador. */ 
volátil int i_from_iterator ;  

/* Esta es la función iteradora. Se ingresa en la primera llamada a 
* swapcontext, y recorre en bucle desde 0 hasta 9. Cada valor se guarda en i_from_iterator, 
* y luego se usa swapcontext para regresar al bucle principal. El bucle principal imprime 
* el valor y llama a swapcontext para volver a la función. Cuando 
se llega al final * del bucle, la función sale y la ejecución cambia al 
contexto * señalado por main_context1. */ 
void loop ( ucontext_t * loop_context , ucontext_t * other_context , int * i_from_iterator ) { int i ; for ( i = 0 ; i < 10 ; ++ i ) { /* Escribe el contador del bucle en la ubicación de retorno del iterador. */ * i_from_iterator = i ; /* Guarda el contexto del bucle (este punto en el código) en ''loop_context'',          * y cambia a other_context. */ swapcontext ( loop_context , other_context ); } /* La función pasa al contexto de llamada con un implícito      * ''setcontext(&loop_context->uc_link);'' */ } int main ( void ) { /* La pila para la función iteradora. */ char iterator_stack [ SIGSTKSZ ]; 
     
     
     

     
    
          
        
          
        
        

         
    
    
    

 
 
 

    
     

    /* Bandera que indica que el iterador se ha completado. */ 
volátil int iterator_finished ;      

    getcontext ( & loop_context ); 
/* Inicializa el contexto del iterador. uc_link apunta a main_context1, el      * punto al que regresar cuando el iterador termina. */ loop_context . uc_link = & main_context1 ; loop_context . uc_stack . ss_sp = iterator_stack ; loop_context . uc_stack . ss_size = sizeof ( iterator_stack );    

               
        
      

    /* Rellene loop_context para que haga que swapcontext inicie el bucle. La 
     conversión de tipo * (void (*)(void)) es para evitar una advertencia del compilador pero 
     * no es relevante para el comportamiento de la función. */ 
makecontext ( & loop_context , ( void ( * )( void )) loop , 3 , & loop_context , & main_context2 , & i_from_iterator ); /* Borre el indicador de finalizado. */ iterator_finished = 0 ;       
           
   
          
      

    /* Guarda el contexto actual en main_context1. Cuando finaliza el bucle, 
     * el flujo de control volverá a este punto. */ 
getcontext ( & main_context1 ); if ( ! iterator_finished ) { /* Establece iterator_finished de modo que cuando se          * regrese al getcontext anterior a través de uc_link, la condición if anterior sea falsa y          * el iterador no se reinicie. */ iterator_finished = 1 ; while ( 1 ) { /* Guarda este punto en main_context2 y cambia al iterador.              * La primera llamada comenzará el bucle. Las llamadas posteriores cambiarán al              * swapcontext en el bucle. */ swapcontext ( & main_context2 , & loop_context ); printf ( "%d \n " , i_from_iterator ); } } return 0 ; }    
  
      
        


          
       
          
            


             
             
        
    
    
     

NOTA: este ejemplo no es correcto, [1] pero puede funcionar como se pretende en algunos casos. La función makecontextrequiere que los parámetros adicionales sean de tipo int, pero el ejemplo pasa punteros. Por lo tanto, el ejemplo puede fallar en máquinas de 64 bits (específicamente arquitecturas LP64 , donde ). Este problema se puede solucionar descomponiendo y reconstruyendo valores de 64 bits, pero eso introduce una penalización en el rendimiento. sizeof(void*) > sizeof(int)

En arquitecturas donde los tipos int y puntero tienen el mismo tamaño (por ejemplo, x86-32, donde ambos tipos son de 32 bits), es posible que pueda pasar punteros como argumentos a makecontext() después de argc. Sin embargo, no se garantiza que esto sea portable, no está definido según los estándares y no funcionará en arquitecturas donde los punteros sean más grandes que int. No obstante, a partir de la versión 2.8, glibc realiza algunos cambios en makecontext(3), para permitir esto en algunas arquitecturas de 64 bits (por ejemplo, x86-64).


Para obtener y establecer el contexto, puede resultar útil un contexto más pequeño:

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

int main ( int argc , const char * argv []){ ucontext_t contexto ; obtenercontext ( & contexto ); puts ( "Hola mundo" ); dormir ( 1 ); establecercontext ( & contexto ); devolver 0 ; }     
	 
	
	
	
	
	
	 

Esto crea un bucle infinito porque el contexto contiene el contador del programa.

Referencias

  1. ^ ab Especificaciones básicas de The Open Group, número 6, IEEE Std 1003.1, edición 2004 [1]
  • Contextos del sistema V - Manual de la biblioteca C de GNU
  • setcontext(3): obtener/establecer el contexto actual del usuario –  Manual del programador de Linux – Funciones de la biblioteca
  • setcontext(3) –  Manual de funciones de la biblioteca de FreeBSD
Obtenido de "https://es.wikipedia.org/w/index.php?title=Setcontext&oldid=1212730229"