call a function when the program is finished with ctrl c - linux

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.

Related

SIGFPE handler loop call

Look at this Unix C program:
#include <stdio.h>
#include <signal.h>
void handler(int signum)
{
printf("Handler signum=%d\n",signum);
}
int main(int argc, char *argv)
{
printf("Start\n");
signal(SIGFPE, handler);
int i=10/0;
printf("Next\n");
return 0;
}
As you can see, i am connecting SIGFPE to an handler.
Then, i make a DIV0 erreur.
The handler is fired, that is great.
But, this handler is called in loop !
Why ?
Thanks
If you simply return from your handler, execution resumes at the point where the signal was thrown, which results in another divide by zero error, which results in the handler being called again, and so on. You need to arrange for execution to continue at some other point in the code. The traditional approach is to use setjmp/longjmp, something like this
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
jmp_buf buf;
void handler(int signum)
{
longjmp(buf, signum);
}
int main(int argc, char *argv)
{
int rc = setjmp(buf);
if (rc == 0) {
printf("Start\n");
signal(SIGFPE, handler);
int i=10/0;
}
printf("Handler signum=%d\n", rc);
printf("Next\n");
return 0;
}
Note: this approach is very old school, and probably someone can suggest a better way to handle it. Also, you are probably better off calling sigaction rather than signal, as the semantics of signal are not consistent across different versions of Unix.

Catching SIGUSR1 with sigtimedwait()

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 ...

need to know how to interrupt all pthreads

In Linux, I am emulating an embedded system that has one thread that gets messages delivered to the outside world. If some thread detects an insurmountable problem, my goal is to stop all the other threads in their tracks (leaving useful stack traces) and allow only the message delivery thread to continue. So in my emulation environment, I want to "pthread_kill(tid, SIGnal)" each "tid". (I have a list. I'm using SIGTSTP.) Unfortunately, only one thread is getting the signal. "sigprocmask()" is not able to unmask the signal. Here is my current (non-working) handler:
void
wait_until_death(int sig)
{
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, sig);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
for (;;)
pause();
}
I get verification that all the pthread_kill()'s get invoked, but only one thread has the handler in the stack trace. Can this be done?
This minimal example seems to function in the manner you want - all the threads except the main thread end up waiting in wait_until_death():
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
#define NTHREADS 10
pthread_barrier_t barrier;
void
wait_until_death(int sig)
{
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, sig);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
for (;;)
pause();
}
void *thread_func(void *arg)
{
pthread_barrier_wait(&barrier);
for (;;)
pause();
}
int main(int argc, char *argv[])
{
const int thread_signal = SIGTSTP;
const struct sigaction sa = { .sa_handler = wait_until_death };
int i;
pthread_t thread[NTHREADS];
pthread_barrier_init(&barrier, NULL, NTHREADS + 1);
sigaction(thread_signal, &sa, NULL);
for (i = 0; i < NTHREADS; i++)
pthread_create(&thread[i], NULL, thread_func, NULL);
pthread_barrier_wait(&barrier);
for (i = 0; i < NTHREADS; i++)
pthread_kill(thread[i], thread_signal);
fprintf(stderr, "All threads signalled.\n");
for (;;)
pause();
return 0;
}
Note that unblocking the signal in the wait_until_death() isn't required: the signal mask is per-thread, and the thread that is executing the signal handler isn't going to be signalled again.
Presumably the problem is in how you are installing the signal handler, or setting up thread signal masks.
This is impossible. The problem is that some of the threads you stop may hold locks that the thread you want to continue running requires in order to continue making forward progress. Just abandon this idea entirely. Trust me, this will only cause you great pain.
If you literally must do it, have all the other threads call a conditional yielding point at known safe places where they hold no lock that can prevent any other thread from reaching its next conditional yielding point. But this is very difficult to get right and is very prone to deadlock and I strongly advise not trying it.

linux: alarm function doesn't work sometimes?

My code is as follows,The first time ,alarm works very well and handler2() function can work. however, the alarm doesn't work after it implement "doMain()" in the "handler2()".
I mean after the second time print ""In main Pleasae input: \n"", handler2() doesn't wrok anymore.
I don't know why? My code as follows:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <setjmp.h>
#define MAX_LEN_COMM 64
jmp_buf jumper;
int stop =0; //o is not stop ,otherwise is stop;
void hanlder2();
void doMain();
void handler2()
{
int len_command = 0;
char character;
char commandStr[60];
printf("******************************\n");
printf("In Alarm Pleasae input: \n");
while((character=getchar())!='\n')
{
commandStr[len_command]=character;
len_command++;
}
commandStr[len_command]='\0';
printf("In Alarm input is %s\n",commandStr);
if (strcmp(commandStr,"N")==0||strcmp(commandStr,"n")==0){
printf("In Alarm You put no, we will stop alarm \n");
stop=1;
longjmp(jumper, 2);
}
else if(strcmp(commandStr,"Y")==0||strcmp(commandStr,"y")==0){
printf("In Alarm You put yes, we will continue alarm \n");
signal(SIGALRM, handler2);
alarm(5);
doMain();
}
}
void doMain(){
while(1){
setjmp(jumper);
if(stop==0){
signal(SIGALRM, handler2);
printf("return time %d\n",alarm(5));
}
int len_command = 0;
char character;
char commandStr[60];
printf("In main Pleasae input: \n");
while((character=getchar())!='\n')
{
commandStr[len_command]=character;
len_command++;
}
commandStr[len_command]='\0';
printf("In main input is %s\n",commandStr);
if (strcmp(commandStr,"N")==0||strcmp(commandStr,"n")==0){
printf("In main You put no\n");
}
else if(strcmp(commandStr,"Y")==0||strcmp(commandStr,"y")==0){
printf("In main You put yes\n");
}
}
}
void main()
{
doMain();
}
What you are doing is very wrong.
First, the signature of the handler should be void handler(int sig).
Second, there are very few functions that are safe to use within a handler so you should try to get out of a handler as quickly as possible and definitely not doing console i/o. You are using several unsafe library functions.
Lastly a signal handler is a function. It runs and returns to where your program was interrupted by the signal. During the time a handler runs signals of the same type are not deliverd. By calling doMain() from the handler - which is crazy - the handler never ends. Because it doesn't end you won't see any more alarm signals.

GTK+ Thread safety

I'm trying to use threads to manage several things in GTK+, however, as soon as I try to use any GUI function in the new thread, it locks up the GUI and this makes sense since GTK+ is not thread safe. Is there anyway around this?
Here's my code:
int main(int argc, char *argv[])
{
GError *error = NULL;
/* init threads */
g_thread_init(NULL);
gdk_threads_init();
/* init gtk */
gtk_init(&argc, &argv);
....
//Multithreaded functions
g_thread_create(argument_thread, (gpointer)label7, FALSE, &error );
gdk_threads_enter();
gtk_main();
gdk_threads_leave();
return 0;
}
void *argument_thread(void *args)
{
while(1)
{
gdk_threads_enter();
gtk_entry_set_text(entry2,"random stuff");
gdk_threads_leave();
}
}
Not sure if this could be an issue (don't know GTK) but maybe there is a race condition if the thread acquires the lock before the gtk_main has started.
Then you could try:
gdk_threads_enter();
//Multithreaded functions
g_thread_create(argument_thread, (gpointer)label7, FALSE, &error );
gtk_main();
gdk_threads_leave();
Moreover you should temporize your loop:
void *argument_thread(void *args)
{
while(1)
{
gdk_threads_enter();
gtk_entry_set_text(entry2,"random stuff");
gdk_threads_leave();
sleep(10);
}
}
I have resolved the problem using g_timeout e gthread:http://www.freemedialab.org/wiki/doku.php?id=programmazione:gtk:gtk_e_i_thread
Basically I use 3 functions, one that launches the thread, one that does the job without manipulating widgets (thread) and a third type that serves as a timeout timer checking every n seconds certain values ​​written by the thread and updates the ' graphic interface.
Or you can use "g_idle_add" : http://www.freemedialab.org/wiki/doku.php?id=programmazione:gtk:gtk_e_i_thread#versione_con_g_idle_add
gdk_threads_enter() and gdk_threads_leave() are deprecated from 3.6 version of Gtk.

Resources