Thread: SIGALARM and sockets...

  1. #1
    Registered User
    Join Date
    Feb 2009
    Posts
    6

    SIGALARM and sockets...

    Hi all,

    I'm a bit newbie in C programming, and right now really stuck on the problem I'm trying to explain (sure u can help me!).

    My program communicates asynchronously via TCP with a server. It requests data and as soon as it is recieved, it processes the frame. I implemented the communication with sockets, using select to determine when there is data in the socket after my request.

    On the other hand, I want also my program to check if other process, let's say, the "brother process" is running. To perform so, the 'bro' writes in a file a number, which grow every time it writes it, and my program reads that number and consider the brother down when that number does not increase for a while.

    As I want to make that "watchdog" task synchronously, I have use the setitimer function to make the system "throw" the SIGALRM signal every period of time (around 30 seconds). The problem is that the first frames, the read file task is performed correctly (every, more or less, 5 seconds) But afterwards, it seems that the more frames are recieved, the more time is taken to do the watchdog task. I mean, the first 2 frames, it takes a bit more tahn 30 seconds to read the file. Then, it takes more, and finally the access to the file is never performed. Sometimes it accesses 13 times to the file, others 10, others 20, but it always get stuck.

    I define the signal_handler with sigaction. Here is the bit of code that concerns my problem (I think,...):
    Code:
    void signal_definitions(){
        int i;
        int error;
        //memset(&sigTimerAction, 0, sizeof(sigTimerAction));
        
        printf("Estoy en la definicion de señales\n");
        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 SIGALARM\n");
                    logError();
                    exit(-1);
                }
                continue;
            }
    */
    
            if (signal(i,process_exit) == SIG_ERR) { 
                sprintf(msg_log, "Error al manejar señal de salida del programa\n");
                logError();
                exit(-1);
            }
    
        }
        // Tratamiento de SIGALRM
        sigemptyset( &sigTimerAction.sa_mask );
        sigTimerAction.sa_flags = SA_RESTART|SA_NODEFER;
        sigTimerAction.sa_handler = watchdogCheck;
        sigaction(SIGALRM, &sigTimerAction, NULL);
        //if (signal(SIGALRM,watchdogCheck)==SIG_ERR)
        
        // Defino parametros de tiempo para temporizador
        setvalortimer.it_interval.tv_sec = 0;
        setvalortimer.it_interval.tv_usec = 0;
        setvalortimer.it_value.tv_sec = 30;
        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: %d\n",error);
        
        //alarm(20);
        
    }
    void watchdogCheck(int signum){
      
        int error; 
        int pid;
        
        //signal(SIGALRM,watchdogCheck);
        sigaction(SIGALRM, &sigTimerAction, NULL);
        printf("Estoy en wdCheck antes del wait\n");
        
        //wait(); //Soy el padre y espero a que acabe el hijo que lancé.
        printf("Estoy en wdCheck despues del wait\n");
        
        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 hijo\n");
            error = wd_escritura();
            printf("Escribo %d\n",num_escrito);
            if (error < 0){
                sprintf(msg_log, "Watchdog: no puede hacerse vigilancia sobre el armario %d",nArmario);
                logError();
                //exit(-1);
            }
            printf("Leo\n");
            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);
        }
    
        num_escrito++;
        setvalortimer.it_interval.tv_sec = 0;
        setvalortimer.it_interval.tv_usec = 0;
        setvalortimer.it_value.tv_sec = 30;
        setvalortimer.it_value.tv_usec = 0;
        error = setitimer(ITIMER_REAL,&setvalortimer,&ovalortimer);
        printf("WdCheck: %d\n",error);
        //setitimer(ITIMER_VIRTUAL,&setvalortimer,&ovalortimer); 
        //alarm(10);
      
    }
    I would appreciate any suggestion. Thanks a lot in advance!

    G.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,666
    5 Safe and Unsafe Interfaces (Multithreaded Programming Guide) - Sun Microsystems
    Your signal handler is calling a number of things which are NOT safe to call from signal handlers.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    You don't need a signal to do this...

    You know that you want to check something every 30 seconds. You are using select(), which allows you to provide a timeout. So just adjust this timeout so that it times out just as the 30 second period expires. In other words:

    Code:
    // Abstracted, as usual
    for( ;; )
    {
        now = GetCurrentTime();
        timeout = 30;
        while( timeout > 0 )
        {
            if( select( numFds, readFds, writeFds, NULL, &timeout ) > 0 )
                ProcessNetworkStuff();
            oldTime = now;
            now = GetCurrentTime();
            timeout = 30 + oldTime - now;
        }
        // 30 seconds have expired, go check your "thing"
    }
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

Popular pages Recent additions subscribe to a feed