Hola a todos,
Soy nuevo en el foro, y medianamente novato en esto de la programación en C, sobre todo a cierto nivel. Estoy haciendo un cliente TCP que pide datos a un servidor de manera asíncrona. Quiero que este programa, cada x tiempo (es decir, de manera síncrona), vigile si otro está vivo (digamos que cuida de su hermano). Para el envío y recepción de datos uso sockets, y en la rx en concreto utilizo la función select() sobre sockets bloqueantes). Para realizar la vigilancia del proceso hermano, hago uso del temporizador del sistema mediante la función setitimer. El modo que tengo de hacer esta vigilancia es leer de un fichero un el valor que escribe el programa hermano, y ver que, efectivamente, este valor va cambiando. Cuando está un rato sin cambiar considero que el hermano ha muerto (d.e.p.).
Para hacer el acceso al fichero "que vigilo", en la función que maneja SIGALRM hago un fork, de modo que se cree una hebra específica para hacer esa tarea (digamos que no solo tengo que relanzar el proceso hermano cuando veo que se ha caído, sino que tengo que hacer unas cuantas cosas más, por eso hago el fork()). Tengo varios problemas:
- En primer lugar, pese a lazar el setitimer en su versión REAL_TIME, veo que el tiempo entre señales SIGALRM no se ajusta "demasiado" a lo que le pido. Pongamos que le pido 25 segundo de timer. El salto de la señal se produce, variando cada vez, en torno a los 40 segundo o así. Y cada vez parece que tarda más. He de decir que lo que hago es, en una función de definición de señales, determino los signal_handler de las señales que me interesen, para, al final de esta función, iniciar el temporizador (sin valor de reactivación, sólo tocando el it_value) Depués, al final del signal_handler de SIGALRM vuelvo a lanzar el timer.
- Para hacer la asignación de los manejadores, he usado tanto signal como sigset para no tener que "recargar" el manejador. En ambos casos, veo que tras cierto número de señales capturadas correctamente, parece que deja de hacerlo (o no se reinicia el timer o no se captura la SIGALRM, pero dejan de hacerse accesos al fichero de vigilancia)
Os adjunto el código del definición de señales y el manejador de la señal de alarma, por si véis algo raro.
<code>
void signal_definitions(){
int i;
int error;
//memset(&sigTimerAction, 0, sizeof(sigTimerAction));
printf("Estoy en la definicion de señalesn");
for (i=1;i<NSIG;i++) {
if ((i==SIGKILL) || (i==SIGSTOP) || (i==SIGCHLD)) continue;
if ((i==SIGHUP) || (i==SIGINT) || (i==SIGQUIT) ||
(i==SIGTSTP) || (i==SIGCONT) || (i==SIGTTIN) ||
(i==SIGTTOU)) {
signal(i,SIG_IGN);
continue;
}
if (i==SIGALRM){
if (sigset(i,watchdogCheck) == SIG_ERR){
//if (signal(i,watchdogCheck) == SIG_ERR){
sprintf(msg_log, "Error al manejar señal SIGALARMn");
logError();
exit(-1);
}
continue;
}
if (signal(i,process_exit) == SIG_ERR) {
sprintf(msg_log, "Error al manejar señal de salida del programan");
logError();
exit(-1);
}
}
// Defino parametros de tiempo para temporizador
setvalortimer.it_interval.tv_sec = 0;
setvalortimer.it_interval.tv_usec = 0;
setvalortimer.it_value.tv_sec = 25;
setvalortimer.it_value.tv_usec = 0;
// Defino valores iniciales para variables de lectura y escritura del watchdog
num_escrito = 0;
num_leido = 0;
// Lanzo timer
setitimer(ITIMER_REAL,&setvalortimer,&ovalortimer);
//error = setitimer(ITIMER_VIRTUAL,&setvalortimer,&ovalortimer);
printf("Definicion: %dn",error);
//alarm(20);
}
void watchdogCheck(int signum){
int error;
int pid;
//signal(SIGALRM,watchdogCheck);
printf("Estoy en wdCheck antes del waitn");
wait(); //Soy el padre y espero a que acabe el hijo que lancé.
printf("Estoy en wdCheck despues del waitn");
pid = fork();
if (pid < 0){
sprintf(msg_log, "Watchdog: imposible crear hebra de vigilancia %d",nArmario);
logError();
}
else if (pid == 0){
printf("Soy el proceso hijon");
error = wd_escritura();
if (error < 0){
sprintf(msg_log, "Watchdog: no puede hacerse vigilancia sobre el armario %d",nArmario);
logError();
//exit(-1);
}
error = wd_lectura();
if (error < 0){
sprintf(msg_log, "Watchdog: no puede hacerse vigilancia sobre el armario %d",nArmario_otro);
logError();
//exit(-1);
}
exit(0);
}
else {
//sigemptyset( &sigTimerAction.sa_mask );
//sigTimerAction.sa_flags = 0;
//sigTimerAction.sa_handler = watchdogCheck;
//sigaction(SIGALRM, &sigTimerAction, NULL);
//signal(SIGALRM,watchdogCheck);
//if (signal(SIGALRM,watchdogCheck)==SIG_ERR)
// printf("Error en redefinicionn");
setvalortimer.it_interval.tv_sec = 0;
setvalortimer.it_interval.tv_usec = 0;
setvalortimer.it_value.tv_sec = 15;
setvalortimer.it_value.tv_usec = 0;
error = setitimer(ITIMER_REAL,&setvalortimer,&ovalortimer);
printf("WdCheck: %dn",error);
//setitimer(ITIMER_VIRTUAL,&setvalortimer,&ovalortimer);
//alarm(10);
}
}
</code>
Bueno, bonito chorizo el que acabo de escribir. Si alguien puede echarme una mano le estaré enormemente agradecido. Ya os digo que no controlo demasiado este tema; lo que sé lo sé por haber leído por la red en sitios como éste.
Muchas gracias de antemano.