When sending a signal from one process to another, I also want to send a value of type long. Is that possible? I am using SIGUSR1.
Sure you can, but you'll have to send it with sigqueue(2) instead of kill(2). And you can send an int or a sival_ptr.
union sigval {
int sival_int;
void *sival_ptr;
};
Establish the handler
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = handler;
sa.sa_flags = SA_SIGINFO; /* Important. */
sigaction(SIGUSR1, &sa, NULL);
The handler for a signal established using SA_SIGINFO
static void
handler(int sig, siginfo_t *si, void *ucontext)
{
si->si_value; /* This is what you're looking for. */
}
Sending an integer
union sigval sv;
sv.sival_int = 42;
sigqueue(pid, SIGUSR1, sv);
Related
I am currently learning about signals in C and have a small program, that is supposed to not terminate upon receiving the SIGINT signal using sigaction().
The code written below however does terminate, even though it looks fine to me. Maybe I am something missing. Does someone see, why it still terminates?
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void handle() { printf("%s%d%s", "I won't die....: ", getpid(), "\n"); }
int main() {
struct sigaction sa;
sa.sa_handler = handle;
int k = 0;
sigaction(SIGINT, &sa, NULL);
// signal(SIGINT, handle); //signal works just fine
while (k < 60) {
printf("%s", "sleeping... \n");
sleep(1);
k = k + 1;
}
}
Additional info: My OS is Windows, however I compile and execute the program in the Bash of a Linux subsystem.
Open the manual page of sigaction() and understand all the members of struct sigaction and fill all the members of struct sigaction.
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
Here
struct sigaction sa;
As pointed by #AnttiHaapala here sa is a variable of automatic storage duration and you didn't initialize its members, it invokes undefined behavior as all the other fields contain garbage except sa.sa_handler
So you need to fill the other members of struct sigaction like
sa.sa_handler = handle;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
Or initialize sa itself like
struct sigaction sa = {0};
Also it's not a good practice to write printf() statement inside signal handler, read here How to avoid using printf in a signal handler? .
I am developing a small application where in I want to call a function every 1 second. This is how I implemented
Timerspec.it_interval.tv_sec=1;
Timerspec.it_interval.tv_nsec=0;
Timerspec.it_value.tv_sec=1;
Timerspec.it_value.tv_nsec=0;
timer_t timerId;
struct sigaction sa;
sa.sa_handler=&TimerFn;
sa.sa_flags=0;
sigemptyset(&sa.sa_mask);
sigaction(SIGALRM,&sa,NULL);
timer_create(CLOCK_REALTIME,NULL,&timerId);
timer_settime(timerId,0,(const itimerspec*)Timerspec,NULL);
But I want to run the TimerFn function in a separate pthread(basically a timer for pthread function). Can somebody please tell how to do this?
If you can accept the creation of a new thread for every timer tick, you can use SIGEV_THREAD:
struct sigevent evp;
memset((void *)&evp, 0, sizeof(evp));
evp.sigev_notify = SIGEV_THREAD;
evp.sigev_notify_function = &sig_alrm_handler;
evp.sigev_signo = SIGALRM;
evp.sigev_value.sigval_ptr = (void *)this;
int ret = timer_create(CLOCK_REALTIME, &evp, &_timerId);
This will create a new thread for every tick.
If you need to handle the signal in a specific thread, a little more work is required:
static void *
sig_threadproc(void *thrarg)
{
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGALRM);
/* endless loop to wait for and handle a signal repeatedly */
for (;;) {
int sig;
int error;
error = sigwait(&sigset, &sig);
if (error == 0) {
assert(sig == SIGALRM);
printf("got SIGALRM\n");
} else {
perror("sigwait");
}
}
return NULL;
}
static void
sig_alrm_handler(int signo)
{
/**
* dummy signal handler,
* the signal is actually handled in sig_threadproc()
**/
}
int
main(int argc, char *argv[])
{
sigset_t sigset;
struct sigaction sa;
pthread_t sig_thread;
struct itimerspec tspec;
timer_t timer_id;
/* mask SIGALRM in all threads by default */
sigemptyset(&sigset);
sigaddset(&sigset, SIGALRM);
sigprocmask(SIG_BLOCK, &sigset, NULL);
/* we need a signal handler.
* The default is to call abort() and
* setting SIG_IGN might cause the signal
* to not be delivered at all.
**/
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sig_alrm_handler;
sigaction(SIGALRM, &sa, NULL);
/* create SIGALRM looper thread */
pthread_create(&sig_thread, NULL, sig_threadproc, NULL);
/* setup timer */
tspec.it_interval.tv_sec = 1;
tspec.it_interval.tv_nsec = 0;
tspec.it_value.tv_sec = 1;
tspec.it_value.tv_nsec = 0;
timer_create(CLOCK_REALTIME, NULL, &timer_id);
timer_settime(timer_id, 0, &tspec, NULL);
/**
* this might return early if usleep() is interrupted (by a signal)
* It should not happen, since SIGALRM is blocked on the
* main thread
**/
usleep(10000000);
return 0;
}
You might get away with selectively unblocking SIGARLM only in the signal handler thread, causing it the only thread to be eligible to handle that signal, but that may not be portable across systems.
Other versions (including use of pthread_cond_signal()) are already discussed in this answer.
If you just want to call a function every second, here's a simple solution:
#include <pthread.h>
#include <unistd.h>
void TimerFn(void)
{
...
}
void* timer(void* arg)
{
for (;;) {
TimerFn();
sleep(1);
}
return NULL;
}
...
pthread_t timerThread;
pthread_create(&timerThread, NULL, timer, NULL);
Is there some reason this wouldn't suffice?
I have two shared libraries linked to my test application. Both of the libraries have signal handlers for SIGINT.
Is it valid to have multiple signal handlers for same signal? Which order the handlers will execute when I generate a SIGINT signal?
As said by others, only one signal handler can be set, which is the last one. You would then have to manage calling two functions yourself. The sigaction function can return the previously installed signal handler which you can call yourself.
Something like this (untested code):
/* other signal handlers */
static void (*lib1_sighandler)(int) = NULL;
static void (*lib2_sighandler)(int) = NULL;
static void aggregate_handler(int signum)
{
/* your own cleanup */
if (lib1_sighandler)
lib1_sighandler(signum);
if (lib2_sighandler)
lib2_sighandler(signum);
}
... (later in main)
struct sigaction sa;
struct sigaction old;
lib1_init(...);
/* retrieve lib1's sig handler */
sigaction(SIGINT, NULL, &old);
lib1_sighandler = old.sa_handler;
lib2_init(...);
/* retrieve lib2's sig handler */
sigaction(SIGINT, NULL, &old);
lib2_sighandler = old.sa_handler;
/* set our own sig handler */
memset(&sa, 0, sizeof(sa));
sa.sa_handler = aggregate_handler;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, NULL);
Only one signal handler can be installed per signal. Only the latest installed handler will be active.
we can handle multiple signal with single signal handler but
but its is not possible to have multiple signal handler for same signal.
void sig_handler(int signo)
{
if (signo == SIGINT)
printf("received SIGINT 1\n");
}
void sig(int signo)
{
if (signo == SIGINT)
printf("received SIGINT 2\n");
}
int main(void)
{
if(signal(SIGINT, sig_handler) == SIG_ERR)
printf("\ncan't catch SIGINT\n");
if (signal(SIGINT, sig) == SIG_ERR)
printf("\ncan't catch SIGINT\n");
// A long long wait so that we can easily issue a signal to this process
while(1)
sleep(1);
return 0;
}
if u try to run this code u will find that the last assigned signal handler is set for that signal.
i think it is not possible to have a multiple signal handler for same signal.
As you could see in the man page for sigaction, the new signal handler replaces the old one and the old one is returned.
If you have two unused signals (say SIGUSR1 and SIGUSR2), assign those signals the two signal handlers for SIGINT. Then you may write your own Signal Handler for SIGINT and from that, you may raise the needed unused signal as per you want.
Shabaz hit the nail on the head. However, if you're looking for something all your libraries could use (provided you have access to the source code), you could do something along the following lines:
linked_list* sigint_handlers = NULL;
void sighand_init(sighand_config_t* config) {
struct sigaction action;
memset(&signalaction, 0, sizeof(signalaction));
action.sa_handler = &sighand_main;
// Order is important, in case we get a signal during start-up
sigint_handlers = linked_list_new();
sigaction(SIGINT, &action);
}
void sighand_main(int signum) {
if (signum == SIGINT) {
linked_list_node* node = linked_list_head(sigint_handlers);
while ((node = node->next) != NULL) {
node->object(signum);
}
if (sighand_config.exitonint) {
app_exit(0);
}
}
}
void sighand_add_int_handler(void (*handler)(int)) {
if (handler == NULL) return;
linked_list_add(sigint_handlers, handler);
}
void sighand_destroy() {
...
linked_list_destroy(signint_handlers);
...
}
Or, you could use this yourself, and after loading each library, get the handler and later call add_handler. Something along the lines of:
loadlibrary(lib1.so);
sigaction1 = signalget(SIGINT);
loadlibrary(lib2.so);
sigaction2 = signalget(SIGINT);
sighand_init(...);
sighand_add_int_handler(sigaction1.sa_handler);
sighand_add_int_handler(sigaction2.sa_handler);
Just some thoughts,
Anthony
Suppose, i know the process of my parent id and would like to
kill(my_parent_id, SIGTERM)
As a parent process, how can i catch this signal?
Register to catch the signal:
void termination_handler(int sig)
{
/* do something */
}
struct sigaction handler;
handler.sa_handler = termination_handler;
sigemptyset (&handler.sa_mask);
handler.sa_flags = SA_RESTART;
sigaction(SIGTERM, &handler, NULL);
Here is a good example page.
You could use the old style, but it is not suggested:
void termination_handler()
{
/* do something */
}
signal(SIGTERM, termination_handler);
How do I receive receive a signal sent with sigqueue in a c program (on linux)?
If just use kill to send a signal I just add a receiver with something like this
signal(SIGUSR1, sigusr1);
that point to a simple function like this:
void sigusr1()
{
signal(SIGUSR1,sigusr1);
printf("SIGUSR1 ....\n");
}
But if I send a signal with sigqueue, how would I do then?
Thanks
Johan
Add a sigaction:
struct sigaction action;
action.sa_flags = SA_SIGINFO;
action.sa_sigaction = &sigusr2;
if (sigaction(SIGUSR2, &action, NULL) == -1) {
perror("sigusr: sigaction");
_exit(1);
}
Where sigusr2 would look something like this:
void sigusr2(int signo, siginfo_t *info, void *extra)
{
void *ptr_val = info->si_value.sival_ptr;
int int_val = info->si_value.sival_int;
printf("Signal %d, value %d \n", signo, int_val);
}
And just for ref a sigqueue example
sigval value;
for(int i=10;i<20;i++)
{
value.sival_int = i;
sigqueue(pid,SIGUSR2, value);
}
Use sigaction.