I have a strange behavior where manpage and google didn't help out.
In my code I want to block / unblock SIGINT when SIGUSR2 is sent. For this I install the signal handler and prepare the set for mask in a function:
void installSignallHandler(){
sBlock.sa_handler = handleBlock;
sigemptyset(&sBlock.sa_mask);
sigaddset(&sBlock.sa_mask, SIGUSR2);
sBlock.sa_flags = 0;
sigaction(SIGUSR2, &sBlock, NULL);
sigemptyset(&signals_protected);
sigaddset(&signals_protected, SIGINT);
// For some reason sigprocmask only works if it is called here the first time
// sigprocmask(SIG_BLOCK, &signals_protected, NULL);
// sigintBlocked = true;
}
Then if SIGUSR2 is sent this function is called:
void handleBlock(int signal){
if(sigintBlocked){
printf("Unblocking SIGINT ...\n");
sigprocmask(SIG_UNBLOCK, &signals_protected, NULL);
sigintBlocked = false;
}
else{
printf("Blocking SIGINT ...\n");
sigprocmask(SIG_BLOCK, &signals_protected, NULL);
sigintBlocked = true;
}
}
For testing I called it like this:
int main(int argc, char **argv) {
installSignallHandler();
while(1){
printf("processing...\n");
sleep(1);
}
return EXIT_SUCCESS;
}
Now the problem: The way I posted the code, sigprocmask takes no effect. But if I uncomment the two lines above, it works. So my two questions:
Can you explain this behavior?
What can I do to solve it? - I don't want to start with blocked signal.
because it is race-condition. set sigintBlocked in sig_handler and then do validation in main function if it is set then mask the signal.
this link has more information
sigprocmask during signal's execution
Related
Since the examples for pthreads with pthread_cond_broadcast wakeup are sparse i wrote one, but are unsure if this is correctly synchronized and the way to do it:
do all threads share the same c and mtx variable?
is it necessary upon pthread_cond_wait return to test if some condition is actually met? in my case every call to broadcast should wake up every thread exactly once, but no-one else should do so. (do i prevent spurious wakeups?)
the program currently does not exit despite async cancel type. also no success with deferred cancellation tried in example code despite pthread_cond_wait being a cancellation point so.
overall does it work like i expect it to.
#include <pthread.h>
#include <iostream>
#include <unistd.h>
struct p_args{
int who;
};
pthread_cond_t c; //share between compilation units
pthread_mutex_t mtx;
void *threadFunc(void *vargs){
//pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
struct p_args * args = (struct p_args *) vargs;
while(true){
//wait for trigger one loop
pthread_mutex_lock(&mtx);
pthread_cond_wait(&c, &mtx);
pthread_mutex_unlock(&mtx);
//should be entangled output showing concurrent execution
std::cout << "t " << args->who << std::endl;
/* expensive work */
}
delete args;
}
int main(int argc, char* argv[])
{
pthread_cond_init(&c, NULL);
pthread_mutex_init(&mtx, NULL);
pthread_t thread_id[2];
struct p_args *args0 = new p_args();
struct p_args *args1 = new p_args();
args0->who = 0;
args1->who = 1;
pthread_create(&thread_id[0], NULL, threadFunc, args0);
pthread_create(&thread_id[1], NULL, threadFunc, args1);
sleep(3);
pthread_mutex_lock(&mtx);
pthread_cond_broadcast(&c);
pthread_mutex_unlock(&mtx);
sleep(3);//test if thread waits
pthread_cancel(thread_id[0]);
pthread_cancel(thread_id[1]);
pthread_join (thread_id[0], NULL);
pthread_join (thread_id[1], NULL);
//could perform cleanup here
return 0;
}
Regarding exiting deferred:
thread_id[0] exits fine and i am stuck in line `pthread_join (thread_id[1], NULL);`, it says (Exiting) but seems stuck on a lock, with debugger:
<br>
[![enter image description here][2]][2]
<br>
EDIT final solution i came up with:
#include <pthread.h>
#include <iostream>
#include <unistd.h>
struct p_args{
int who;
};
pthread_cond_t c;
pthread_mutex_t mtx;
bool doSome[2];
bool exitFlag;
void *threadFunc(void *vargs){
struct p_args * args = (struct p_args *) vargs;
while(true){
//wait for trigger one loop
pthread_mutex_lock(&mtx);
do {
pthread_cond_wait(&c, &mtx);
if(exitFlag) {
std::cout << "return " << args->who << std::endl;
delete args;
pthread_mutex_unlock(&mtx);
return NULL;
}
} while(doSome == false);
doSome[args->who] = false;
pthread_mutex_unlock(&mtx);
std::cout << "t " << args->who << std::endl;
}
}
int main(int argc, char* argv[])
{
pthread_cond_init(&c, NULL);
pthread_mutex_init(&mtx, NULL);
pthread_t thread_id[2];
struct p_args *args0 = new p_args();
struct p_args *args1 = new p_args();
args0->who = 0;
args1->who = 1;
doSome[0] = doSome[1] = true;
exitFlag = false;
pthread_create(&thread_id[0], NULL, threadFunc, args0);
pthread_create(&thread_id[1], NULL, threadFunc, args1);
doSome[0] = doSome[1] = true;
pthread_cond_broadcast(&c);
sleep(3);
doSome[0] = doSome[1] = true;
pthread_cond_broadcast(&c);
sleep(3);
exitFlag = true;
pthread_cond_broadcast(&c);
pthread_join (thread_id[0], NULL);
pthread_join (thread_id[1], NULL);
return 0;
}
do all threads share the same c and mtx variable?
Yes, just like any other global variable. You could print their addresses from each thread to confirm it.
is it necessary upon pthread_cond_wait return to test if some condition is actually met?
Yes, all wait interfaces are subject to spurious wakeups, and you're always responsible for checking your own predicate. See the documentation or a good book.
the program currently does not exit ...
pthread_cancel is uniformly horrible and should never be used. It's really hard to get right. If you want to tell your thread to exit, write a notification mechanism - build it into the existing predicate loop - and signal/broadcast to make sure all threads wake up and realize it's time to die.
Regarding exiting deferred: thread_id[0] exits fine and i am stuck in line pthread_join (thread_id[1], NULL);, it says (Exiting) but seems stuck on a lock
One of the hard things about pthread_cancel is cleanup. If cancellation occurs while you're holding a lock, you need to have used pthread_cleanup_push to emulate cancel-compatible RAII semantics. Otherwise the first thread may (and in this case, did) die with the mutex still locked.
In this case the second thread is trying to exit from pthread_const_wait due to cancellation, but it needs to regain the lock and can't.
The usual form of a condition variable loop is this (and a good reference book should show something similar):
void *thread(void *data)
{
struct Args *args = (struct Args *)data;
/* this lock protects both the exit and work predicates.
* It should probably be part of your argument struct,
* globals are not recommended.
* Error handling omitted for brevity,
* but you should really check the return values.
*/
pthread_mutex_lock(&args->mutex);
while (!exit_predicate(args)) {
while (!work_predicate(args)) {
/* check the return value here too */
pthread_cond_wait(&args->condition, &args->mutex);
}
/* work_predicate() is true and we have the lock */
do_work(args);
}
/* unlock (explicitly) only once.
* If you need to cope with cancellation, you do need
* pthread_cleanup_push/pop instead.
*/
pthread_mutex_unlock(&args->mutex);
return data;
}
where your custom code can just go in bool exit_predicate(struct Args*), bool work_predicate(struct Args*) and void do_work(struct Args*). The loop structure itself rarely needs much alteration.
I'm not new to programming, but pretty new to Linux. I'm trying to use signals to asynchronously catch a push on a button, like this:
Run a worker thread which raises SIGUSR1 when the button is pushed.
Run a loop (main thread) around sigtimedwait() that will rotate info every two seconds (as long as the button is not pushed) or break (when the button is pushed).
According to the notes on sigtimedwait(), one should block the signals you want to wait for, then call sigtimedwait(). But I never see sigtimedwait() catching the blocked signals. I have run the code below in a few ways to see what happens with different scenarios:
Call to pthread_sigmask() disabled, call to signal() disabled,
result: programs exits with message "User defined signal 1".
Call to pthread_sigmask() disabled, call to signal() enabled, result:
message "Button 1 pressed sync1 hit" appears, sigtimedwait() always
returns EAGAIN.
Call to pthread_sigmask() enabled, call to signal() disabled, result:
message "Button 1 pressed" appears, sigtimedwait() always returns
EAGAIN.
Call to pthread_sigmask() enabled, call to signal() enabled, result
of course same as previous because the handler will not be called.
All as expected, except for the fact that sigtimedwait() doesn't seem to catch the signal when it's pending.
I've looked into similar code, e.g. this. But I don't understand how that particular code could work: SIGUSR1 isn't blocked, so raising that should immediately terminate the program (the default action for SIGUSR1).
It looks like I'm missing something here. What am I doing wrong? Or is the whole idea of using raise() in a worker thread wrong? I'm running this on a Raspberry Pi 3 with Raspbian Stretch (Debian 9.1), could there be a problem in that?
[I know printf() shouldn't be used in a signal handler, but for this purpose it works]
Any help appreciated, thx!
#include <stdio.h>
#include <stdlib.h>
#include <bcm2835.h>
#include <signal.h>
#include <pthread.h>
#include <errno.h>
#define PIN_BUTTON1 RPI_V2_GPIO_P1_22 // GPIO #24
// Thread function
void* check_button1(void* param)
{
while (true)
{
if (bcm2835_gpio_lev(PIN_BUTTON1) == HIGH)
{
printf("Button 1 pressed ");
raise(SIGUSR1);
}
delay(250);
}
}
// Signal handler, if applied
volatile sig_atomic_t usr_interrupt = 0;
void sync1(int sig)
{
printf("sync1 hit ... ");
usr_interrupt = 1;
}
int main(int argc, char** argv)
{
if (!bcm2835_init())
{
printf("Failed to initialize BCM2835 GPIO library.");
return 1;
}
bcm2835_gpio_fsel(PIN_BUTTON1, BCM2835_GPIO_FSEL_INPT);
sigset_t sigusr;
sigemptyset(&sigusr);
sigaddset(&sigusr, SIGUSR1);
pthread_sigmask(SIG_BLOCK, &sigusr, NULL);
signal(SIGUSR1, sync1);
// Start the threads to read the button pin state
pthread_t th1;
pthread_create(&th1, NULL, check_button1, NULL);
// Create a two second loop
struct timespec timeout = { 0 };
timeout.tv_sec = 2;
usr_interrupt = 0;
int nLoopCount = 0;
while (true)
{
printf("Loop %d, waiting %d seconds ... ", ++nLoopCount, timeout.tv_sec);
int nResult = sigtimedwait(&sigusr, NULL, &timeout);
if (nResult < 0)
{
switch (errno)
{
case EAGAIN: printf("EAGAIN "); break; // Time out, no signal raised, next loop
case EINTR: printf("EINTR "); break; // Interrupted by a signal other than SIGCHLD.
case EINVAL: printf("EINVAL "); exit(1); // Invalid timeout
default: printf("Result=%d Error=%d ", nResult, errno); break;
}
printf("\n");
continue;
}
printf("Signal %d caught\n", nResult);
}
return 0;
}
ADDENDUM: In the meantime, I got this working by replacing raise(SIGUSR1) by kill(getpid(), SIGUSR1). Strange, because according to the manual raise(x) is equivalent to kill(getpid, x) in single-threaded programs and to pthread_kill(pthread_self(), x) in multi-threaded ones. Replacing raise(SIGUSR1) by pthread_kill(pthread_self, SIGUSR1) has no effect. If anyone could explain this to me ...
I want to handle the signal SIGTSTP (18) on Linux. This is my code:
void handler(int signum){
printf("Signal %d has tried to stop me.", signum);
}
int main(void){
struct sigaction act;
sigset_t mask;
act.sa_handler = handler;
act.sa_flags = 0;
sigemptyset(&mask);
sigaddset(&mask, SIGTSTP);
sigprocmask(SIG_SETMASK, &mask, NULL);
sigaction(SIGTSTP, &act, NULL);
pause();
}
When I send a signal from another terminal this way:
$ kill -18 PID
the handler() function does not run.
I've tried replacing SIGTSTP with 18 in the call to sigaction(). It does not work.
Any ideas?
Thanks for your time.
You are deliberately blocking delivery of SIGTSTP to your process by doing
sigaddset(&mask, SIGTSTP);
sigprocmask(SIG_SETMASK, &mask, NULL);
sigprocmask with SIG_SETMASK sets a mask to block signals. Remove the call to sigprocmask, and the signal should be delivered.
One other thing to do is to zero act before filling it in:
memset(&act, 0, sizeof(act));
The most likely reason is that you did not set your struct sigaction act to zero. It will be full of random stack values.
Fix it by using struct sigaction act = {}; or memset(&act, 0, sizeof(act))
Double check that I got the memset argument order right. I sometimes get it mixed up.
We are using a System V message queue with the msgrcv function being called in blocking mode. We want to implement a timer on the blocking msgrcv function so that when the timer expires and we have not received a message, we can unblock msgrcv and continue execution.
Do you have any suggestions on how we can achive this by programming?
I have solved this problem using alarm signal.
Please check the following program if it helps:
int msg_recv(int id, MSG_DATA *msgptr)
{
int n;
**alarm(2);** //After 2 second msg_recv interrupt and return errno "Interrupted system call"
n = msgrcv(id, (MSG_DATA *) msgptr, sizeof(MSG_DATA) , 0, 0);
perror("Return from msgrcv");
printf ("N = %d\n %d %s\n\n",n,errno,strerror(errno));
if ( n < 0) //goto LOOP; // This forces the interrupted msgrcv to repeat
return(n);
}
void sigalrm_handler()
{
printf("Alarm signal delivered !\n");
return;
}
int main();
int main()
{
//signal (SIGALRM, times_up); /* go to the times_up function */
/* when the alarm goes off. */
**signal(SIGALRM, sigalrm_handler);**
int msqid; /* return value from msgget() */
MSG_DATA msg_data;
msqid = 0;
printf("Ready to receive ... \n");
**msg_recv(msqid, &msg_data);**
printf("read message \n");
return 0;
}
signal handler has a int param:
void sigalrm_handler(int)
{
printf("Alarm signal delivered !\n");
return;
}
I am working in the Linux environment, and I have a C++ program, what I want is when I cancel the program with ctrl+c I would like that the program executes a function, to close some files and print some sutff, is there any way to do this?. Thank you.
signal() can be dangerous on some OSes and is deprecated on Linux in favor of sigaction(). "signal versus sigaction"
Here's an example that I ran across recently ("Tap the interrupt signal") and modified as I was playing around with it.
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<string.h>
struct sigaction old_action;
void sigint_handler(int sig_no)
{
printf("CTRL-C pressed\n");
sigaction(SIGINT, &old_action, NULL);
kill(0, SIGINT);
}
int main()
{
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_handler = &sigint_handler;
sigaction(SIGINT, &action, &old_action);
pause();
return 0;
}
For a full working example you can try the following code:
#include <signal.h>
#include <stdio.h>
#include <stdbool.h>
volatile bool STOP = false;
void sigint_handler(int sig);
int main() {
signal(SIGINT, sigint_handler);
while(true) {
if (STOP) {
break;
}
}
return 0;
}
void sigint_handler(int sig) {
printf("\nCTRL-C detected\n");
STOP = true;
}
Example run:
[user#host]$ ./a.out
^C
CTRL-C detected
You have to catch the SIGINT. Something like this:
void sigint_handler(int sig)
{
[do some cleanup]
signal(SIGINT, SIG_DFL);
kill(getpid(), SIGINT);
}
loads more detail here
Short answer: look into the signal function, specifically catching SIGINT. You write a callback function and pass it to the system via the signal function, then when that particular signal happens, the system calls your callback function. You can close files and do whatever other cleanup stuff you want in there.
Note to people who might stumble upon this question, looking for the answer in Windows instead:
Use the SetConsoleCtrlHandler API call to set a custom handler and watch for CTRL_C_EVENT, CTRL_BREAK_EVENT or CTRL_CLOSE_EVENT.