Herramientas de usuario

Herramientas del sitio


senales

Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anteriorRevisión previa
Próxima revisión
Revisión previa
senales [2012/10/01 14:39] lmateusenales [2016/11/24 13:13] (actual) – [sigaction/sigprocmask] lmateu
Línea 76: Línea 76:
   /* Leer una línea del teclado dándole 10 segundos de plazo */   /* Leer una línea del teclado dándole 10 segundos de plazo */
   #include <stdio.h>   #include <stdio.h>
-  #undef __USE_BSD /* para que el read pueda ser interrumpido por una seal */+  #undef __USE_BSD /* para que el read pueda ser interrumpido por una señal */
   #include <signal.h>   #include <signal.h>
   #include <unistd.h>   #include <unistd.h>
Línea 82: Línea 82:
   volatile int flag;    volatile int flag; 
                  
-  /* función para atrapar la seal de alarma */+  /* función para atrapar la señal de alarma */
   void ring() {   void ring() {
     flag=0;     flag=0;
Línea 140: Línea 140:
 } }
  
-int call_with_timeout(int (*f)(), int timeout)+int call_with_timeout(int (*f)(void *), void *p, int timeout)
 { {
     int res;     int res;
Línea 154: Línea 154:
  
     alarm(timeout); /* programamos el timer */     alarm(timeout); /* programamos el timer */
-    res = f();+    res = f(p);
     printf("exito!\n");     printf("exito!\n");
     alarm(0);  /* apagamos el timer */     alarm(0);  /* apagamos el timer */
Línea 162: Línea 162:
 } }
  
-int fun() {+int fun(void *p) {
   sleep(2);   sleep(2);
   return 0;   return 0;
Línea 168: Línea 168:
  
 int main() { int main() {
-  call_with_timeout(fun, 1); +  call_with_timeout(fun, NULL, 1); 
-  call_with_timeout(fun, 1);+  call_with_timeout(fun, NULL, 1);
   return 0;   return 0;
 } }
Línea 195: Línea 195:
   ...   ...
      
-  int call_with_timeout(int (*f)(), int timeout) {+  int call_with_timeout(int (*f)(void *), void *p, int timeout) {
     ...     ...
     if (sigsetjmp(ring, 1) != 0) {     if (sigsetjmp(ring, 1) != 0) {
Línea 207: Línea 207:
 POSIX sí la define. POSIX sí la define.
  
 +=== Discusión ===
 +
 +Otro punto importante que no se debe olvidar es lo que pasa con los recursos solicitados por la
 +función.  ¿Qué pasa con la memoria pedida o los archivos abiertos?  Estos recursos no se liberarán
 +jamás y por lo tanto se transforman en goteras.  Si se va a emplear este enfoque, hay que mantener
 +una traza de todos los recursos pedidos para así liberarlos cuando se cumpla el timeout.  Esto
 +no es trivial de hacer.
 +
 +También hay que considerar que la invocación de la rutina que atiende la señal puede provocar dataraces.
 +Por ejemplo supongamos que la función f usa malloc.  La señal del timeout puede gatillarse justo a la mitad
 +del malloc y por lo tanto el heap que maneja malloc queda en un estado inconsistente.  Si la función que atiende
 +la señal también invoca malloc, se puede producir una inconsistencia que gatille un segmentation fault o
 +que se entregue 2 veces el mismo pedazo de memoria.  Por lo tanto las acciones de la rutina de atención de la
 +señal deben ser simples como asignar una variable global por ejemplo.
 ==== sigaction/sigprocmask ==== ==== sigaction/sigprocmask ====
  
Línea 218: Línea 232:
   * etc.   * etc.
  
-Del mismo modo, sigprocmask permite deshabilitar/activar señales explícitamente.+Del mismo modo, sigprocmask permite deshabilitar/activar señales explícitamente.  Esta función es de utilidad por ejemplo 
 +para resolver el datarace asociado al uso de malloc tanto en el código en donde puede ocurrir una señal como en la función 
 +que atiende esa señal.  La solución está en invocar sigprocmask antes de invocar malloc para inhibir la señal en cuestión e 
 +invocar nuevamente sigprocmask para reactivar nuevamente la señal.  De esta forma si se gatilla la señal mientras se ejecuta 
 +malloc, la señal quedará pendiente y solo se invocará la rutina de atención cuando se reactive la señal en la 
 +segunda llamada de sigprocmask. 
 Consulte la página del manual para averiguar más sobre estas funciones. Consulte la página del manual para averiguar más sobre estas funciones.
 +
 +==== Ejercicio ====
 +
 +Resuelva la parte c de la pregunta 1 del [[http://users.dcc.uchile.cl/~lmateu/CC3301/controles/c3-142.pdf|control 3 de 2014/2]].  Pruebe su solución con el archivo [[http://users.dcc.uchile.cl/~lmateu/CC3301/download/largo.zip|largo.zip]].  En este problema la variable nodo podría apuntar a una dirección inválida.  Si trata de acceder a nodo->prox se gatillará la señal SIGSEGV que normalmente termina el proceso.  Para evitar que el proceso termine, Ud. debe capturar la señal SIGSEGV.  La dificultad está en que si la rutina que atiende la señal retorna, se volverá a hacer el acceso inválido.  Para eludir el acceso inválido Ud. debe usar sigsetjmp en la función largo e invocar siglongjmp en la rutina que atiende la señal.
senales.1349102377.txt.gz · Última modificación: 2012/10/01 14:39 por lmateu