senales
Diferencias
Muestra las diferencias entre dos versiones de la página.
Ambos lados, revisión anteriorRevisión previaPróxima revisión | Revisión previa | ||
senales [2012/09/24 23:38] – lmateu | senales [2016/11/24 13:13] (actual) – [sigaction/sigprocmask] lmateu | ||
---|---|---|---|
Línea 74: | Línea 74: | ||
< | < | ||
- | /* Leer una lnea del teclado | + | /* Leer una línea |
#include < | #include < | ||
- | #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 < | #include < | ||
#include < | #include < | ||
Línea 82: | Línea 82: | ||
volatile int flag; | volatile int flag; | ||
| | ||
- | /* funcin | + | /* función |
void ring() { | void ring() { | ||
flag=0; | flag=0; | ||
} | } | ||
| | ||
- | /* funcin | + | /* función |
int gettext(char *buf, int bufsize, int timeout) { | int gettext(char *buf, int bufsize, int timeout) { | ||
int nchars; | int nchars; | ||
Línea 115: | Línea 115: | ||
} | } | ||
</ | </ | ||
+ | |||
+ | ==== Señales y setjmp/ | ||
+ | |||
+ | Supongamos que queremos llamar una función, pero si la función toma más tiempo que digamos 2 segungos queremos | ||
+ | abortar la llamada. | ||
+ | longjmp desde la rutina de atención de la señal: | ||
+ | |||
+ | < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | /* | ||
+ | * Ejemplo de uso de signal y longjmp para implementar un timeout | ||
+ | * Esta implementacion usualmente solo funciona para la primera invocacion | ||
+ | */ | ||
+ | |||
+ | static jmp_buf ring; | ||
+ | |||
+ | void clock(int sig) | ||
+ | { | ||
+ | longjmp(ring, | ||
+ | } | ||
+ | |||
+ | int call_with_timeout(int (*f)(void *), void *p, int timeout) | ||
+ | { | ||
+ | int res; | ||
+ | void (*hdlr)(); | ||
+ | |||
+ | hdlr = signal(SIGALRM, | ||
+ | |||
+ | if (setjmp(ring) != 0) { | ||
+ | signal(SIGALRM, | ||
+ | fprintf(stderr, | ||
+ | return 1; | ||
+ | } | ||
+ | |||
+ | alarm(timeout); | ||
+ | res = f(p); | ||
+ | printf(" | ||
+ | alarm(0); | ||
+ | |||
+ | signal(SIGALRM, | ||
+ | return(res); | ||
+ | } | ||
+ | |||
+ | int fun(void *p) { | ||
+ | sleep(2); | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | int main() { | ||
+ | call_with_timeout(fun, | ||
+ | call_with_timeout(fun, | ||
+ | return 0; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Este código funciona en Linux, pero debido a un problema de estandarización, | ||
+ | Unix. El problema es que en algunos Unix la rutina de atención del timer (ejemplo: clock) se llama con | ||
+ | la señal SIGALRM deshabilitada. | ||
+ | señal queda deshabilitada y por lo tanto la señal de un segundo timeout podría nunca recibirse. | ||
+ | |||
+ | Este es el caso de Linux, pero afortunadamente hay otro aspecto que evita el problema el Linux. | ||
+ | setjmp graba el estado de las señales que están activas/ | ||
+ | En buenas cuentas longjmp activa nuevamente la señal SIGALRM y por eso funciona. | ||
+ | estándar en todos los Unix. Sin embargo sí es estándar que las funciones sigsetjmp y siglongjmp graban | ||
+ | el estado de las señales o no de acuerdo a un parámetro de sigsetjmp. | ||
+ | estas funciones en el código de más arriba: | ||
+ | |||
+ | < | ||
+ | #define _POSIX_C_SOURCE 1 | ||
+ | |||
+ | void clock(int sig) { | ||
+ | siglongjmp(ring, | ||
+ | } | ||
+ | | ||
+ | ... | ||
+ | | ||
+ | int call_with_timeout(int (*f)(void *), void *p, int timeout) { | ||
+ | ... | ||
+ | if (sigsetjmp(ring, | ||
+ | ... | ||
+ | } | ||
+ | ... | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Es necesario definir la macro _POSIX_C_SOURCE porque no es una función estándar de ansi-C. | ||
+ | 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. | ||
+ | jamás y por lo tanto se transforman en goteras. | ||
+ | una traza de todos los recursos pedidos para así liberarlos cuando se cumpla el timeout. | ||
+ | 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. | ||
+ | del malloc y por lo tanto el heap que maneja malloc queda en un estado inconsistente. | ||
+ | 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. | ||
+ | señal deben ser simples como asignar una variable global por ejemplo. | ||
+ | ==== sigaction/ | ||
+ | |||
+ | La función signal es la primera función que existió en Unix para atrapar señales. | ||
+ | usar la función sigaction para tener más control sobre donde y cómo se debe ejecutar la rutina de atención. | ||
+ | Por ejemplo: | ||
+ | |||
+ | * si la señal se deshabilita o no mientras se ejecuta la rutina de atención | ||
+ | * en que pila se ejecuta la señal | ||
+ | * si la señal vuelve a su estado por omisión una vez que se gatilla la señal | ||
+ | * etc. | ||
+ | |||
+ | Del mismo modo, sigprocmask permite deshabilitar/ | ||
+ | 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. | ||
+ | invocar nuevamente sigprocmask para reactivar nuevamente la señal. | ||
+ | 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. | ||
+ | |||
+ | ==== Ejercicio ==== | ||
+ | |||
+ | Resuelva la parte c de la pregunta 1 del [[http:// |
senales.1348529939.txt.gz · Última modificación: 2012/09/24 23:38 por lmateu