LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   Problems designing a signal handler in UNIX (https://www.linuxquestions.org/questions/linux-newbie-8/problems-designing-a-signal-handler-in-unix-783340/)

19bernardo87 01-19-2010 08:16 PM

Problems designing a signal handler in UNIX
 
I'm trying to create a signal handler thread to handle SIGALRM signals.

The main thread calls the following function before creating any other threads

Code:

pthread_t Timer::Init(long _clock_interval_musec)
{
        // Set interval.
        clock_interval = _clock_interval_musec;
        // This is called while in a single threaded environment.
        // Main thread masks alarm.
        sigset_t alarm_off_mask;
        if ((sigemptyset(&alarm_off_mask) == -1) || (sigaddset(&alarm_off_mask, SIGALRM) == -1))
          perror("Failed to initialize the signal set");
        if (pthread_sigmask(SIG_BLOCK, &alarm_off_mask, NULL) == -1)
          perror("Failed to block SIGALRM");
        // Now call a new thread which handles alarm signals.
        pthread_t retID;
        pthread_create(&retID, NULL, TimerHandlerThread, NULL);
        // Return id of thread responsible for managing alarm signals.
        return retID;
}

As you can see, I block the alarm signal.

The spawned signal handler thread has the following Run function

Code:

void* Timer::TimerHandlerThread(void* args)
{
        // Change granualirity of alarm.
        itimerval tv;
        tv.it_interval.tv_sec  = clock_interval / USECS_IN_SECS;
        tv.it_interval.tv_usec = clock_interval % USECS_IN_SECS;

        setitimer(ITIMER_REAL, &tv, NULL);
        // Unmask alarm signals in this thread.
        sigset_t sigset;
        if ((sigemptyset(&sigset) == -1) || (sigaddset(&sigset, SIGALRM) == -1))
        perror("Failed to add signal to wait for");

        Timer currentTime;
        int sig;
        while (1)
        {
                /* wait for a signal to arrive */
                sigwait(&sigset, &sig);
              std::cout << "we are here\n";
                if (sig == SIGALRM && g_timerQueue.size() > 0)
                {
                        currentTime.Set(0);
                        // Handle if needed
                        g_mutex.P();
                        if (*(g_timerQueue.front()) < currentTime)
                        {
                                g_timerQueue.front()->Event_Handler();
                                std::pop_heap(g_timerQueue.begin(), g_timerQueue.end());
                                g_timerQueue.pop_back();
                        }
                        g_mutex.V();
                }
        }

        return NULL;
}

Sigwait never returns ("we are here" never prints).

clock_interval is 50.

Is the timer not firing?
Did I not set my interval correctly?
Did I not proper block the signals ensuring the that the default handler would not take care of them?

Any help is welcome. :)

chrism01 01-19-2010 09:46 PM

I'd suggest you ask the mods (via the report button) to move this to the Programming section for better/faster help.

19bernardo87 01-20-2010 01:03 AM

Quote:

Originally Posted by chrism01 (Post 3832946)
I'd suggest you ask the mods (via the report button) to move this to the Programming section for better/faster help.

I wouldn't mind that at all. I just figured the newbie section was proper for me since I've only started reading, nevermind programming, on Unix a week ago. Here is the code as it stands now by the way

Code:

void* Timer::TimerHandlerThread(void* args)
{
        // Change granualirity of alarm.
        itimerval tv;
        tv.it_value.tv_sec  = tv.it_interval.tv_sec  = clock_interval / USECS_IN_SECS;
        tv.it_value.tv_usec = tv.it_interval.tv_usec = clock_interval % USECS_IN_SECS;
        if (setitimer(ITIMER_REAL, &tv, NULL) == -1)
                perror("Failed to set timer interval");
       
        Timer currentTime;
        int sig;
        while (1)
        {
                /* wait for a signal to arrive */
                sigwait((const sigset_t*)args, &sig);

                if (sig == SIGALRM && g_timerQueue.size() > 0)
                {exit(0);
                        currentTime.Set(0);
                        // Handle if needed
                        g_mutex.P();
                        if (*(g_timerQueue.front()) < currentTime)
                        {
                                g_timerQueue.front()->Event_Handler();
                                std::pop_heap(g_timerQueue.begin(), g_timerQueue.end());
                                g_timerQueue.pop_back();
                        }
                        g_mutex.V();
                }
        }

        return NULL;
}

pthread_t Timer::Init(long _clock_interval_musec)
{
        // Set interval.
        clock_interval = _clock_interval_musec;
        // This is called while in a single threaded environment.
        // Main thread masks alarm.
        sigset_t sigset;
        if (sigemptyset(&sigset) == -1)
        perror("Failed to add signal to block");
        if (sigaddset(&sigset, SIGALRM) == -1)
        perror("Failed to add signal to block");
        if (sigprocmask(SIG_BLOCK, &sigset, NULL) == -1)
            perror("Failed to block SIGALRM");
        // Now call a new thread which handles alarm signals.
        pthread_t retID;
        pthread_create(&retID, NULL, TimerHandlerThread, (void*)&sigset);
        // Return id of thread responsible for managing alarm signals.
        return retID;
}

It still gives me simillar problems.
Timer::Init is the first thing called in main.

neonsignal 01-20-2010 09:01 AM

Quote:

Is the timer not firing?
Did I not set my interval correctly?
Did I not proper block the signals ensuring the that the default handler would not take care of them?
I cannot repeat the problem (ie it works here). Perhaps look at the following:

1. print out the values you are storing in the timing counters tv_sec/tv_usec
2. make sure that the main thread is not exiting (since its return will end the program)
3. it isn't clear why you are creating the currentTime object on the stack inside the TimerHandlerThread member function

19bernardo87 01-21-2010 11:58 PM

Quote:

Originally Posted by neonsignal (Post 3833531)
I cannot repeat the problem (ie it works here). Perhaps look at the following:

1. print out the values you are storing in the timing counters tv_sec/tv_usec
2. make sure that the main thread is not exiting (since its return will end the program)
3. it isn't clear why you are creating the currentTime object on the stack inside the TimerHandlerThread member function

1. They are fine.
2. It's exiting gracefully, the threads run just fine in the background. In fact, the thread runs, it just blocks in sigwait.
3. It doesn't matter.

I implemented the same signal handling technique with sigaction and it works. It's just more writing and less elegant. =/

neonsignal 01-22-2010 12:15 AM

Quote:

It's exiting gracefully, the threads run just fine in the background
My point was that the threads will die if the code exits from main. Since you didn't include that bit of the code, it wasn't clear. It also isn't clear how you have declared the member functions (I'm assuming the thread function must be static).

I have only tested your code under Linux and it works okay (ie, the signal is caught by the sigwait and it reaches the next lines). You might be on a different system (BSD?).

19bernardo87 01-23-2010 06:11 AM

Quote:

Originally Posted by neonsignal (Post 3836055)
My point was that the threads will die if the code exits from main. Since you didn't include that bit of the code, it wasn't clear. It also isn't clear how you have declared the member functions (I'm assuming the thread function must be static).

I have only tested your code under Linux and it works okay (ie, the signal is caught by the sigwait and it reaches the next lines). You might be on a different system (BSD?).

I was running under BSD first, but I wasn't aware it would have not worked. But like I said... the sigaction "version" works perfectly. =/

I'll try running under Linux.

neonsignal 01-23-2010 05:08 PM

I suspect that your main code is making use of sleep/usleep. These calls also make use of SIGALRM, which will cause undefined behaviour.

If you use pthread_sigmask instead of sigprocmask (both the main and the handler thread need to block the signal), this may help.


All times are GMT -5. The time now is 06:02 PM.