LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   How to pass input to a signal handler ? (https://www.linuxquestions.org/questions/programming-9/how-to-pass-input-to-a-signal-handler-665810/)

vasanth2001 08-27-2008 11:11 AM

How to pass input to a signal handler ?
 
Hi all,
Iam using uclibc on uclinux and writing a timer application (where on expiry of timer, a user specified signal is generated). The possible signal handlers are

void func(int signal) and
void func(int signo ,siginfo_t* pInfo,void* context) depending whether or not SA_SIGINFO is reset ot not.

But the problem is that there is no way of passing a user input to the signal handler.

Any way of achieving this ?


Vasanth

Hko 08-27-2008 12:12 PM

The only way to do that would be assigning he user input to a global variable. But this can easily cause hard to solve problems, even if you're fully aware of all the dangers.

The thing with signals is that they really can occur any moment. Suppose the user input is short string: then a signal can occur even in the middle of writing the string to memory. In that case your signal handler is called when the string is half written and does not yet have a '\0' terminator! That would cause strange behaviour of your program once in 10 times, or once in 100 times, who knows... Whether, and how often, this will occur may even depend on things like the kernel version.

One way to solve this is to have a handler that only sets a global flag indicating that a (or which) signal was catched. The in the main loop of the program he flag is regularly checked, and then handled inside the normal program flow. That way you can use the variable containg the user input the normal way.

The global flag need to be so small that the operating system can garantee that it will be set in one single CPU instruction. On many systems a single <int> will do. The header files for the operating system will typedef the apropriate type for this to "sig_atomic_t". So it is safest to use that as the type for your global flag variable.

Here's avery simple example of this mechanism:
Code:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

sig_atomic_t volatile done = 0;

void handler(int num)
{
    done = 1;
}

int main(void)
{
    signal(SIGALRM, handler);
    alarm(10);

    while (!done)
        puts("Hello World");

    return 0;
}


David1357 08-27-2008 01:00 PM

Quote:

Originally Posted by vasanth2001 (Post 3261614)
But the problem is that there is no way of passing a user input to the signal handler.

Most people solve this problem using semaphores. Try "man -k semaphore". You can also use a pthread_mutex, but you have to include libpthread when you build your executable.

osor 08-27-2008 01:41 PM

I am unsure of uclinux, but in linux (and any POSIX operating system which supports the “realtime signals extension” to the POSIX standard), you can use sigqueue() to send a sigval along with a signal. You will need to use the second form of signal handler, and the value will be available as:
Code:

pInfo->si_value.sival_int

vasanth2001 08-28-2008 03:59 AM

The issue with using sigqueue is that the,In my case,signal is generated automatically on expiration of a timer. Otherwise that would have been a good solution.

The signal handlers at most give signal number, other signal info(through siginfo_t*) and user context (a void pointer).It looks like there is no provision for providing user input to signal handler.

Any more inputs are welcome.

Vasanth

David1357 08-28-2008 08:08 AM

Quote:

Originally Posted by vasanth2001 (Post 3262394)
The signal handlers at most give signal number, other signal info(through siginfo_t*) and user context (a void pointer). It looks like there is no provision for providing user input to signal handler.

You can use the "void pointer" to pass any pointer and cast it to a user defined type in the signal handler.

You can use shared data (using the method suggested by Hko) or protected by a semaphore (as suggested by me).

There are plenty of ways to pass user input to a signal handler. I think you are misreading the responses to your post.

osor 08-28-2008 02:49 PM

Quote:

Originally Posted by vasanth2001 (Post 3262394)
The issue with using sigqueue is that the,In my case,signal is generated automatically on expiration of a timer. Otherwise that would have been a good solution.

I don’t understand. How do you expect to provide “user input” to a signal which is automatically generated? What kind of input do you want to provide? Can we see some sample code?
Quote:

Originally Posted by David1357 (Post 3262596)
You can use the "void pointer" to pass any pointer and cast it to a user defined type in the signal handler.

I don’t think the user has any control over the contents of the context pointer (it is set by the kernel and holds the instruction address of where the process was interrupted by the signal).

vasanth2001 08-28-2008 11:10 PM

Hi,
I think i did not get the problem statement right. I will tell the original problem.

I am writing a C++ wrapper class for the software timer to support some legacy code written using proprietary OS.

So, each object of that class(timer class) will represent a timer.And the user will be providing a user defined function(void (*)(void*)) and a void* input to that function.

So each object of the timer will be having a separate timer function and input.

Glibc provides a functionality regarding timer where a timer function and a user specified input can be provided while creating a timer.(which will be run on expiration of the timer).

It also provides another facility where a signal can be generated on expiration of the timer.

Unfortunately, uclibc(which iam using) supports only the second method only(signals).

Since its wriiten in C++, the signal handling mechanism has to be dealt internally inside the class.(user need not know the internal implementation).

So if i make the signal handler as my class method, I cannot pass it to Linux as the method signatures will not match.

i.e int func (int,siginfo_t*,void* context) Vs

int (Timer::*)(int,siginfo_t,void* context)

So, i had to make the signal handler static. (I cannot even cast them)

So, the core question is that how do i call the user provided function along with its input from inside a class static signal handler.

One solution is using global variables,but its not practical for me.

If there was any way of passing input to the signal (generated on expiration of POSIX timer), then i could have used a void* to pass the address of my object,using which i can call user provided timer function
inside my class static signal handler.{As static function can only call other static/global functions and static variables and user provided timer function will be different for each object)

Hope this give a clearer picture regarding my original question.


Vasanth

David1357 08-29-2008 08:50 AM

Quote:

Originally Posted by vasanth2001 (Post 3263298)
I think i did not get the problem statement right. I will tell the original problem.

Now that we know what you are trying to do, we can recommend a better solution. Use a pthread to check for expiration of a timer then call the callback function for the timer. Most of the time, this pthread will be doing usleep(1) or something similar, so it should not be very resource intensive until it calls a timer callback.

You can pass a pointer to the list of timers using the "void *arg" parameter of pthread_create. This gets you around the problem of using a global variable.

The only optimization you might want to make is to spawn a separate each time the timer thread calls a callback function so that the timer thread does not block on a callback.


All times are GMT -5. The time now is 10:59 PM.