I have two program running on my Raspberry Pi. One interfaces with a user, the other listens for messages and updates a message file when directed. I want the other to signal to the first that the messages have been updated so the first can reload the message file. I though a SIGUSR1 signal would do what I need. However, when I raise the signal, it terminates my program, which still needs to continue listening for new messages. I therefore constructed the test case program "test_raise.cpp":
#include <iostream>
#include <csignal>
int main(){
std::cout << "Ready to raise SIGUSR1." << std::endl;
std::raise(SIGUSR1);
std::cout << "SIGUSR1 has been raised." << std::endl;
}
I am using this compiler:
gcc version 6.3.0 20170516 (Raspbian 6.3.0-18+rpi1+deb9u1)
which generates the following output
pi#raspberrypi:~$./test_raise
Ready to raise SIGUSR1.
User defined signal 1
pi#raspberrypi:~$
Note that the 2nd text output is not produced. None of the documentation I have looked at indicates that raise terminates the issuing program. (Have I missed something?)
Is this a normal function of raise? Is there a way to do signals without terminating the program? What is my better alternative?
Thanks...
Based on a response, I have a program (invoked prior to the raise program) which has a handler for the USR1 signal:
#include <iostream>
#include <csignal>
#include <unistd.h>
bool flag;
void signalHandler( int signum ) {
std::cout << "Interrupt signal (" << signum
<< ") received." << std::endl;
flag = true;
exit(signum);
}
int main () {
signal(SIGUSR1, signalHandler);
flag = false;
while(1) {
std::cout << "Sleeping...." << std::endl;
if (flag){
std::cout << "SIGUSR1 reception noted by main. "
<< std::endl;
flag = false;
}
sleep(1000*1000); // sleep 1 second
}
return 0;
}
Now there is a handler, but the messages was never received and the raise program still terminates prior to the final message. What am I missing here?
If you haven't installed a signal handler to catch and deal with SIGUSR1 then the default behaviour is to terminate the process.
If you intend to handle the signal, then install an appropriate signal handler and do what you need to do to handle the signal. (Remember that there are very few things you are allowed to do in a signal handler).
Related
I have a program and would like to stop it by sending SIGINT for writing some data to a file instead of exiting immediately. However, if the user of the program sends SIGINT again, then the program should quit immediately and forget about writing data to a file.
For portability reason I would like to use boost::asio for this purpose.
My initial (simplified) approach (see below) did not work. Is this not possible or am I missing something?
The handler seems to be called only once (printing out the message) and the program always stops when the loop has reached the max iteration number.
void handler(
const boost::system::error_code& error,
int signal_number) {
if (!error) {
static bool first = true;
if(first) {
std::cout << " A signal(SIGINT) occurred." << std::endl;
// do something like writing data to a file
first = false;
}
else {
std::cout << " A signal(SIGINT) occurred, exiting...." << std::endl;
exit(0);
}
}
}
int main() {
// Construct a signal set registered for process termination.
boost::asio::io_service io;
boost::asio::signal_set signals(io, SIGINT);
// Start an asynchronous wait for one of the signals to occur.
signals.async_wait(handler);
io.run();
size_t i;
for(i=0;i<std::numeric_limits<size_t>::max();++i){
// time stepping loop, do some computations
}
std::cout << i << std::endl;
return 0;
}
When your first event is handled, you don't post any new work on the service object, so it exits.
This means that then (after the ioservice exited) the tight loop is started. This may not be what you expected.
If you want to listen for SIGINT again, you have to wait for the signal set again from the handler:
#include <boost/asio.hpp>
#include <boost/asio/signal_set.hpp>
#include <boost/bind.hpp>
#include <boost/atomic.hpp>
#include <iostream>
void handler(boost::asio::signal_set& this_, boost::system::error_code error, int signal_number) {
if (!error) {
static boost::atomic_bool first(true);
if(first) {
// do something like writing data to a file
std::cout << " A signal(SIGINT) occurred." << std::endl;
first = false;
this_.async_wait(boost::bind(handler, boost::ref(this_), _1, _2));
}
else {
std::cout << " A second signal(SIGINT) occurred, exiting...." << std::endl;
exit(1);
}
}
}
int main() {
// Construct a signal set registered for process termination.
boost::asio::io_service io;
boost::asio::signal_set signals(io, SIGINT);
// Start an asynchronous wait for one of the signals to occur.
signals.async_wait(boost::bind(handler, boost::ref(signals), _1, _2));
io.run();
return 2;
}
As you can see I bound the signal_set& reference to the handler in order to be able to async_wait on it after receiving the first signal. Also, as a matter of principle, I made first an atomic (although that's not necessary until you run the io_service on multiple threads).
Did you actually wish to run the io_service in the background? In that case, make it look like so:
signals.async_wait(boost::bind(handler, boost::ref(signals), _1, _2));
boost::thread(boost::bind(&boost::asio::io_service::run, boost::ref(io))).detach();
while (true)
{
std::cout << "Some work on the main thread...\n";
boost::this_thread::sleep_for(boost::chrono::seconds(1));
}
With typical output:
Some work on the main thread...
Some work on the main thread...
Some work on the main thread...
^CSome work on the main thread...
A signal(SIGINT) occurred.
Some work on the main thread...
Some work on the main thread...
^CSome work on the main thread...
A second signal(SIGINT) occurred, exiting....
I need to disable SIGPIPE on CentOS application, because this signal crashes my application when it works with unstable Internet connection.
I use following code in main function:
signal(SIGPIPE, SIG_IGN);
However, program still crashes with SIGPIPE. What is the reason? Have I to call this function on each thread, or it is enough to call in main function, and program will ignore SIGPIPE globally? And if it is not required to be called on each thread, why SIGPIPE still crashes program if it is supposed to ignore the signal?
Here it is a code sample that let you set up your own signal handler on linux, catch SIGPIPE and do something with that.
#include <signal.h>
#include <unistd.h>
#include <cerrno>
#include <system_error>
#include <iostream>
static sigset_t theMask;
static int count = 0;
static void
signalWrapper(
int theSignalNumber,
siginfo_t* theSignalDescription,
void* theUserContext)
{
// Do something here as reaction to you SIGPIPE
// This is better way to react on such things
std::cout << "Got signal " << theSignalNumber << std::endl;
// Reinstall handler
struct ::sigaction sa;
sa.sa_sigaction = &signalWrapper;
sa.sa_mask = theMask;
sa.sa_flags = SA_SIGINFO;
try
{
if (::sigaction(theSignalNumber, &sa, NULL) == -1)
throw std::error_code(errno, std::system_category());
}
catch (const std::error_code& ec)
{
std::cerr << ec << std::endl;
}
count++;
}
void
setupSignalHandlers()
{
struct ::sigaction sa;
// Prepare mask
sigemptyset(&theMask);
sigaddset(&theMask, SIGPIPE);
// Add some more if you need it to process
sa.sa_mask = theMask;
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = &signalWrapper;
// Perform setup
try
{
if (::sigaction(SIGPIPE, &sa, NULL) == -1)
throw std::error_code(errno, std::system_category());
}
catch (const std::error_code& ec)
{
std::cerr << ec << std::endl;
}
}
int
main()
{
std::cout << "Set handler!" << std::endl;
setupSignalHandlers();
std::cout << "Emit 5 SIGPIPE signals" << std::endl;
while (count < 5)
{
kill(getpid(), SIGPIPE);
usleep(100);
}
return 0;
}
and output:
Set handler!
Emit 5 SIGPIPE signals
Got signal 13
Got signal 13
Got signal 13
Got signal 13
Got signal 13
I provide signal handler since it is more correct to process signal that breaks your application than ignore it. Perhaps you need to reestablish connection or do some other stuff.
According to the man page for Signal(2), "The Effects of signal() in a multithreaded process are unspecified." You might try making sure to call signal() in the main thread before creating any other threads, but it's not guaranteed to work.
In any case signal() is deprecated, so I would suggest switching to sigaction(). I use it in multithreaded applications all the time without any problems.
I want to write a few extra lines to a file when interrupted with ctrl-c before the program dies. However the location of the file is not hard coded so I need something more than normal interrupt handling as explained here. What is the best way to do this?
Motivation:
I'm doing time dependent finite element simulations. Sometimes I forget or mis-estimate a reasonable tmax and the simulation would take a very long time to complete, so I interrupt it with ctrl-c. However I still want to use the data generated up to that point. In particular there's an xml file which needs a few lines appended after the simulation is finished to close the tags. Of course it's possible to do this by hand but it's a pain, so I'm try to automate it.
Based on the answer to "How can I catch a ctrl-c event? (C++)" we can install a signal handler that simply raises an exception. Then we can catch the exception and run whatever standard c++ code we like.
Here's a working example:
#include <iostream>
#include <exception>
#include <signal.h>
#include <stdlib.h>
class InterruptException : public std::exception
{
public:
InterruptException(int s) : S(s) {}
int S;
};
void sig_to_exception(int s)
{
throw InterruptException(s);
}
int main()
{
// Taken from answer to "How can I catch a ctrl-c event? (C++)"
struct sigaction sigIntHandler;
sigIntHandler.sa_handler = sig_to_exception;
sigemptyset(&sigIntHandler.sa_mask);
sigIntHandler.sa_flags = 0;
sigaction(SIGINT, &sigIntHandler, NULL);
try
{
std::cout << "Inside try" << std::endl;
// Do something with output so the loop doesn't get optimised out
double i = 0;
while(i < 1e30) {i++;} // loop until interrupted
std::cout << i << std::endl;
}
catch(InterruptException& e)
{
std::cout << "Write something to file" << std::endl;
std::cout << "Caught signal " << e.S << std::endl;
return 1;
}
return 0;
}
This approach does have at least one downside: we have to wrap everything after the handler is installed in a try, otherwise interrupt signals would cause an abort().
One common scheme for loop-based scientific code is to have a global volatile sig_atomic_t boolean indicating whether a signal was caught and add it to the loop condition.
e.g.
volatile sig_atomic_t interrupted=false;
...
void signal_handler(int s)
{
// ...
interrupted=true;
}
...
while (!converged && !interrupted)
{
// Perform computations
}
// Save file properly
This question is based on the following question: Handle CTRL+C on Win32
I'm working on a multithread server, running on Linux and Windows. I can't use boost or other frameworks, only std c++.
I have a problem with the cleanup code on the win32 side. The linux side is working fine: when I want to shutdown the server, I send SIGINT (with CTRL+C), the signal handler sets a global variable and the main pthread executes the cleanup instructions (joining other pthreads, freeing heap memory, etc.).
On windows it looks not so simple to get the same behavior.
I have written a simple test program to understand how the signal handlers works in windows.
#include <iostream>
#include <windows.h>
bool running;
BOOL WINAPI consoleHandler(DWORD signal) {
if (signal == CTRL_C_EVENT) {
running = false;
std::cout << "[CTRL+C]\n";
return TRUE;
}
return FALSE;
}
int main(int argc, char **argv) {
running = true;
if (!SetConsoleCtrlHandler(consoleHandler, TRUE)) {
std::cerr << "Error: " << GetLastError() << '\n';
return -1;
}
std::cout << "Main thread working hard...\n";
while (running) { ; }
for (int i = 0; i < 20; i++)
std::cout << "This is the " << i << "th fake cleanup instruction\n";
return 0;
}
The output is the following:
$ test.exe
Main thread working hard...
[CTRL+C]
This is the 0th fake cleanup instruction
This is the 1th fake cleanup instruction
So the main thread is killed quickly, only after two instruction. In the previous question one of the suggestion was to move the cleanup code in the handler, but is not really helping:
suppose that the handler function looks like this:
BOOL WINAPI consoleHandler(DWORD signal) {
if (signal == CTRL_C_EVENT) {
running = false;
std::cout << "[CTRL+C]\n";
for (int i = 0; i < 20; i++)
std::cout << "This is the " << i << "th fake cleanup instruction\n";
return TRUE;
}
return FALSE;
}
Now the behavior is even worse! The output is:
$ test.exe
Main thread working hard...
[CTRL+C]
This is the
According to MSDN, it seems that the process is always killed:
A HandlerRoutine can perform any necessary cleanup, then take one of
the following actions:
Call the ExitProcess function to terminate the process.
Return FALSE. If none of the registered handler functions returns TRUE, the default handler terminates the process.
Return TRUE. In this case, no other handler functions are called and the system terminates
the process.
Am I missing something obvious?
What's the proper way to terminate a win32 console process and executes its cleanup code?
This is one way to do it, though I would suggest you use an event HANDLE and WaitForSingleObject, as it would tend to be considerably more "yielding". I left the high velocity spin-loop in this just for you to peg one of your cores while still seeing the handler is intercepted.
I took the liberty of modifying your running state to be atomically evaluated and set respectively, as I didn't want the optimizer throwing out the eval in the main loop.
#include <iostream>
#include <cstdlib>
#include <windows.h>
// using an event for monitoring
LONG running = 1;
BOOL WINAPI consoleHandler(DWORD signal)
{
if (signal == CTRL_C_EVENT)
{
std::out << "Received Ctrl-C; shutting down..." << std::endl;
InterlockedExchange(&running, 0);
return TRUE;
}
return FALSE;
}
int main(int argc, char **argv)
{
if (!SetConsoleCtrlHandler(consoleHandler, TRUE))
{
std::cerr << "Error: " << GetLastError() << '\n';
return EXIT_FAILURE;
}
std::cout << "Main thread working hard...\n";
while (InterlockedCompareExchange(&running, 0, 0) == 1);
std::cout << "Graceful shutdown received. Shutting down now." << std::endl;
return 0;
}
Output (note: I pressed ctrl-C, in case it wasn't obvious)
Main thread working hard...
Received Ctrl-C; shutting down...
Graceful shutdown received. Shutting down now.
Note: I tested this in debug and release in both 64 and 32 bit processes, no issues. And you can run it from the VS debugger. Just select "Continue" when informed you can continue if you have a handler installed, which you do.
On Windows you can use a signal handler as well:
static void shutdown(int signum)
{
printf("got signal #%d, terminating\n", signum);
// cleanup
_exit(1);
}
signal(SIGINT, shutdown);
signal(SIGTERM, shutdown);
signal(SIGSEGV, shutdown);
Ctrl-C is mapped to SIGINT just like on Linux.
This won't handle the user closing the console window using mouse, however.
Here is the code on which I set my handler for SIGABRT signal then I call abort() but handler does not get trigered, instead program gets aborted, why?
#include <iostream>
#include <csignal>
using namespace std;
void Triger(int x)
{
cout << "Function triger" << endl;
}
int main()
{
signal(SIGABRT, Triger);
abort();
cin.ignore();
return 0;
}
PROGRAM OUTPUT:
As others have said, you cannot have abort() return and allow execution to continue normally. What you can do however is protect a piece of code that might call abort by a structure akin to a try catch. Execution of the code will be aborted but the rest of the program can continue. Here is a demo:
#include <csetjmp>
#include <csignal>
#include <cstdlib>
#include <iostream>
jmp_buf env;
void on_sigabrt (int signum)
{
signal (signum, SIG_DFL);
longjmp (env, 1);
}
void try_and_catch_abort (void (*func)(void))
{
if (setjmp (env) == 0) {
signal(SIGABRT, &on_sigabrt);
(*func)();
signal (SIGABRT, SIG_DFL);
}
else {
std::cout << "aborted\n";
}
}
void do_stuff_aborted ()
{
std::cout << "step 1\n";
abort();
std::cout << "step 2\n";
}
void do_stuff ()
{
std::cout << "step 1\n";
std::cout << "step 2\n";
}
int main()
{
try_and_catch_abort (&do_stuff_aborted);
try_and_catch_abort (&do_stuff);
}
Although you can replace handler for SIGABRT and abort() will pay attention to the handler, the abort is only inhibited if the signal handler does not return. The relevant quote in C99 is in 7.20.4.1 paragraph 2:
The abort function causes abnormal program termination to occur, unless the signal SIGABRT is being caught and the signal handler does not return. ...
Your signal handler does return and thus the program is aborted.
You get those symptoms i.e. the popup debug dialog, when you have a debug build (with windows and Visual Studio- I'm testing with 2012 version), since it sets a debug break, in the debug implementation of abort() ).
If you pick "ignore" you get that message "Function triger"
If you do a release build, then you don't get the debug popup dialog, and you get the message, as expected