exit, signals and exceptions

S

Siemel Naran

Hi. I posted this question to comp.lang.c++, but am rephrasing it a bit
from what I learned and posting to comp.lang.c++.moderated for more insight.

So how do I solve my problem? I want it so that when the user presses
Ctrl-C or eds the task from task manager (or the kill command in UNIX) then
the system should shutdown gracefully. This means it should call the
destructors of all objects, which means freeing dynamic memory, closing
sockets, closing file handles, close SQL connections, etc.

My approach was to set up a signal handler using std::signal. If the signal
handler does nothing the program resumes execution at the point where the
signal was raised (kind of like the RESUME command in basic).

So one of my thoughts was to throw an exception in the signal handler, and
after returning control to the point in the function where the signal was
raised, the program would detect the exception and perform stack unwinding.
But we are not allowed to throw exceptions in signal functions. On my
compiler, Borland C++ 6 I get the message: << Project.exe faulted with
message "application-defined exception". Process Stopped. Use Step or Run to
continue. >>

My other thought was to call std::exit in the signal handler. But
unfortunately this function not destroy local objects in all stacks.

So what else can we do? This seems to be a common problem, and I'm sure
people have put much thought into it. Maybe some use of longjmp could help?

Here's my current solution, which seems to work in this special case in that
all sockets are closed, but there is no dynamic memory to release, file
handles to close, etc.


int global_s = -1;

void closesockets(int sig)
{
if (global_s != -1)
{
closesocket(global_s);
global_s = -1;
}
WSACleanup();
if (sig) exit(sig);
}

class CloseSockets
{
public:
CloseSockets() { WSADATA wsa; WSAStartup(MAKEWORD(1, 1), &wsa); }
~CloseSockets() { closesockets(0); }
private:
CloseSockets(const CloseSockets&); // not implemented
CloseSockets& operator=(const CloseSockets&); // not implemented
};


void server()
{
CloseSockets _closesockets;

int s = socket(AF_INET, SOCK_STREAM, 0);
if (s == -1) throw std::runtime_error("fail socket");

global_s = s;
signal(SIGINT , &closesockets);
signal(SIGTERM, &closesockets);
signal(SIGABRT, &closesockets);

char myname[256];
int m = gethostname(myname, sizeof(myname));

hostent * myhost = gethostbyname(myname);
if (!myhost) throw std::runtime_error("no host");

// call to bind
// call to listen

while (true)
{
/* call to accept which creates a new socket */

while (true)
{
/* call to recv */
}

// call to closesocket
}
}
 
?

=?iso-8859-1?q?Markus_B._Kr=FCger?=

Siemel Naran said:
I want it so that when the user presses Ctrl-C or eds the task from
task manager (or the kill command in UNIX) then the system should
shutdown gracefully. This means it should call the destructors of
all objects, which means freeing dynamic memory, closing sockets,
closing file handles, close SQL connections, etc.

My approach was to set up a signal handler using std::signal. If
the signal handler does nothing the program resumes execution at the
point where the signal was raised (kind of like the RESUME command
in basic).

So one of my thoughts was to throw an exception in the signal
handler, [...] But we are not allowed to throw exceptions in signal
functions. [...]

My other thought was to call std::exit in the signal handler. But
unfortunately this function not destroy local objects in all stacks.

So what else can we do? This seems to be a common problem, and I'm
sure people have put much thought into it. Maybe some use of
longjmp could help?

Signal handlers need to use the POSIX functions sigsetjmp() and
siglongjmp() instead of setjmp() and longjmp(). Even so, destructors
for local instances won't be called. Mixing longjmp() and RAAI is
generally a bad idea.

One solution is to let the signal handler set a global variable
(declared as volatile sig_atomic_t), and check this variable regularly
inside all loops of long duration. If the variable is set, shutdown
can be initialized by throwing an exception or stopping the loop
normally. The disadvantage of this approach is that you have to do it
in *every* loop that might hang for some time, e.g. socket-reading
loops; you cannot restrict the shutdown implementation to the signal
handler. Also, you must be able to asynchronously stop or specify
timeouts for third-party functions that may be running when the signal
is received, since you probably won't be able to add shutdown checks
to loops contained in them.

Also, some Unix systems automatically restart interrupted system calls
if the signal handler returns. You can disable this behaviour by
using sigaction() instead of signal() and clearing the SA_RESTART
flag, in order to avoid that the system hangs in a restarted read()
call it was processing when Ctrl-C was received.
 
J

Jeff Schwab

Siemel Naran wrote:

<summary>

When my program receives a KILL signal from the environment, how do I
make sure all "live" objects are destructed properly?

When the signal arrives, my handler function is entered. If I don't
exit the program explicitly from the handler, program execution will
resume wherever it was interrupted. I can't throw an exception from
the handler.

</summary>

The most common idiom seems to be the setting of a global variable,
which is then checked at strategic points in your program. Of course,
this is royally painful. An alternative would be having every resource
in the program allocated in a way that would allow explicit deallocation
from the signal handler; for example, there could be custom allocators
for memory, and factories for objects managing other resources.
 
V

Volker Glave

Siemel Naran said:
Hi. I posted this question to comp.lang.c++, but am rephrasing it a bit
from what I learned and posting to comp.lang.c++.moderated for more insight.

So how do I solve my problem? I want it so that when the user presses
Ctrl-C or eds the task from task manager (or the kill command in UNIX) then
the system should shutdown gracefully. This means it should call the
destructors of all objects, which means freeing dynamic memory, closing
sockets, closing file handles, close SQL connections, etc.

My approach was to set up a signal handler using std::signal. If the signal
handler does nothing the program resumes execution at the point where the
signal was raised (kind of like the RESUME command in basic).

So one of my thoughts was to throw an exception in the signal handler, and
after returning control to the point in the function where the signal was
raised, the program would detect the exception and perform stack unwinding.
But we are not allowed to throw exceptions in signal functions. On my
compiler, Borland C++ 6 I get the message: << Project.exe faulted with
message "application-defined exception". Process Stopped. Use Step or Run to
continue. >>

My other thought was to call std::exit in the signal handler. But
unfortunately this function not destroy local objects in all stacks.

So what else can we do? This seems to be a common problem, and I'm sure
people have put much thought into it. Maybe some use of longjmp could help?

Here's my current solution, which seems to work in this special case in that
all sockets are closed, but there is no dynamic memory to release, file
handles to close, etc.


int global_s = -1;

void closesockets(int sig)
{
if (global_s != -1)
{
closesocket(global_s);
global_s = -1;
}
WSACleanup();
if (sig) exit(sig);
}

class CloseSockets
{
public:
CloseSockets() { WSADATA wsa; WSAStartup(MAKEWORD(1, 1), &wsa); }
~CloseSockets() { closesockets(0); }
private:
CloseSockets(const CloseSockets&); // not implemented
CloseSockets& operator=(const CloseSockets&); // not implemented
};


void server()
{
CloseSockets _closesockets;

int s = socket(AF_INET, SOCK_STREAM, 0);
if (s == -1) throw std::runtime_error("fail socket");

global_s = s;
signal(SIGINT , &closesockets);
signal(SIGTERM, &closesockets);
signal(SIGABRT, &closesockets);

char myname[256];
int m = gethostname(myname, sizeof(myname));

hostent * myhost = gethostbyname(myname);
if (!myhost) throw std::runtime_error("no host");

// call to bind
// call to listen

while (true)
{
/* call to accept which creates a new socket */

while (true)
{
/* call to recv */
}

// call to closesocket
}
}

Maybe I miss something, but I do not see the need for
exceptions or the need for exit().

static bool return_from_server = false;

extern "C" void signalhandler(int) {
return_from_server = true;
}

struct WSASystem {
WSASystem() { WSADATA wsa; WSAStartup(MAKEWORD(1, 1), &wsa); }
~WSASystem() { WSACleanup(); }
};

class Socket {
const int x_;
public:
Socket(int x) : x_(x) {}
~Socket() { if (x_ != -1) closesocket(x_); }
int c_int() const { return x_; }
};

void server() {
const WSASystem wsa;

const Socket s(socket(AF_INET, SOCK_STREAM, 0));
if (s.c_int() == -1) {
/* TODO: Give notice "fail socket" to some appropriate
information channel or up to the caller.
Although socket() claims it to be an error, for us the
situation is quite normal - we expect it to happen now
and then -, it is not an error nor an exception. */
return;
}

std::signal(SIGINT, &signalhandler);
std::signal(SIGTERM, &signalhandler);
std::signal(SIGABRT, &signalhandler);

char myname[256];
const int m(gethostname(myname, sizeof(myname)));

hostent* const myhost(gethostbyname(myname));
if (myhost == 0) {
/* TODO: Give notice "no host" to some appropriate
information channel or up to the caller.
This situation is quite normal - we expect it to happen
now and then -, it is not an error nor an exception. */
return;
}

// call to bind
// call to listen

for (;;) {
if (return_from_server) {
return;
}
/* call to accept which creates a new socket */

for (;;) {
if (return_from_server) {
return;
}
/* call to recv */
}
}
}

Of course it is not complete at all (restoration of
signal handlers missing, ...).

Volker
 
B

Ben Hutchings

Siemel said:
Hi. I posted this question to comp.lang.c++, but am rephrasing it a bit
from what I learned and posting to comp.lang.c++.moderated for more insight.

So how do I solve my problem? I want it so that when the user presses
Ctrl-C or eds the task from task manager (or the kill command in UNIX) then
the system should shutdown gracefully. This means it should call the
destructors of all objects, which means freeing dynamic memory, closing
sockets, closing file handles, close SQL connections, etc.

My approach was to set up a signal handler using std::signal. If the signal
handler does nothing the program resumes execution at the point where the
signal was raised (kind of like the RESUME command in basic).

std::signal is not very useful due to the implementation-defined
behaviour when a second signal arrives, and IIRC "End Process" in
Windows does not cause a SIGINT. Look at the POSIX sigsetaction and
Win32 SetConsoleCtrlHandler functions instead. Note that console
handlers run in a separate thread, unlike signal handlers.
So one of my thoughts was to throw an exception in the signal handler, and
after returning control to the point in the function where the signal was
raised, the program would detect the exception and perform stack unwinding.
But we are not allowed to throw exceptions in signal functions.

Correct. Signals are in general *asynchronous*; they can interrupt
anything, just like a switch to another thread.

My other thought was to call std::exit in the signal handler. But
unfortunately this function not destroy local objects in all stacks.
<snip>

It also results in undefined behaviour.

However, since you're writing a network server which waits on
accept(), there is a solution - or rather, two similar solutions for
the two platforms I know. In the signal handler, you set a flag (of
type volatile sig_atomic_t under Unix, or using one of the interlocked
functions under Windows) and close() or closesocket() the listening
socket, causing accept() to fail. In error-handling for accept() you
check this flag (using an interlocked function under Windows). POSIX
guarantees that close() is safe in a signal handler (usually it is a
system call and so atomic w.r.t. signals). Under Windows I believe
the WinSock functions are all thread-safe.
 
S

Siemel Naran

One solution is to let the signal handler set a global variable
(declared as volatile sig_atomic_t), and check this variable regularly
inside all loops of long duration. If the variable is set, shutdown
can be initialized by throwing an exception or stopping the loop
normally. The disadvantage of this approach is that you have to do it
in *every* loop that might hang for some time, e.g. socket-reading
loops; you cannot restrict the shutdown implementation to the signal
handler.

Yes, this was the advice I received in my original post to comp.lang.c++.
It's quite error-prone though because you might forget to put these checks
as you write the code. As you write your code, you add new loops,
re-arrange code, etc, and inserting these checks is the last thing on your
mind.

Perhaps one could use macros

#define } if (g_signal) throw Signal(__FILE__, __LINE__); }

The above tells the pre-processor that it should replace } with a check on
the global variable followed by the real }. But could this be a misuse of
macros? Anyway, not sure if the macro expansion is legal -- ie. not sure if
we can #define } or {. We could always use

#define END if (g_signal) throw Signal(__FILE__, __LINE__); }

Second, what is the deal with sig_atomic_t? What's so special about it?
Also, you must be able to asynchronously stop or specify
timeouts for third-party functions that may be running when the signal
is received, since you probably won't be able to add shutdown checks
to loops contained in them.

Sorry, I don't understand. Can you elaborate?
Also, some Unix systems automatically restart interrupted system calls
if the signal handler returns. You can disable this behaviour by
using sigaction() instead of signal() and clearing the SA_RESTART
flag, in order to avoid that the system hangs in a restarted read()
call it was processing when Ctrl-C was received.

What do you mean by "interrupted system calls"? Also, my signal.h does not
have sigaction and SA_RESTART.
Signal handlers need to use the POSIX functions sigsetjmp() and
siglongjmp() instead of setjmp() and longjmp(). Even so, destructors
for local instances won't be called. Mixing longjmp() and RAAI is
generally a bad idea.

Why is mixing longjmp and RAAI bad? In C++ style we usually declare
variables as we need them, initializing them at the same time. So a call to
longjmp may skip the initialization of objects or initialize the same object
twice. As long as we declare all variables at the top of the function and
then call setjmp, as in the C style, it should be fine to use longjmp. Is
this correct?
 
S

Siemel Naran

The most common idiom seems to be the setting of a global variable,
which is then checked at strategic points in your program. Of course,
this is royally painful. An alternative would be having every resource
in the program allocated in a way that would allow explicit deallocation
from the signal handler; for example, there could be custom allocators
for memory, and factories for objects managing other resources.

This idea of overloading new operators is very interesting. So then you'd
store the address of the object in a global registry, and at program
termination you free the objects in the registries? Maybe you could
register the registries with atexit (or with an object that is registered
with atexit). (For DLLs you could register with DLLMain where the reason is
DLL_PROCESS_DETACH.)

Has anyone actually done this? What is involved, how difficult is it to
implement, what burderns does it impose on developers using the framework,
what are the performance costs?

As QoI, we'd expect the compiler implementation to free all dynamic memory
at program termination. How many actually do this? And how many close file
handles and sockets?

Anyway, we could for example overload global operator new and delete, and
force users to use these functions to acquire and free memory. They
shouldn't use std::malloc directly as this is not overloadable. Right?

Similarly we could overload FileStream::eek:perator new to get memory and store
this memory in the registry. In FileStream::eek:perator delete we free the
memory and remove it from the registry.

But what if someone creates a Fuile


class FileStream {
public:
class FailOpen;
FileStream(const char * filename) { d_file = fopen(filename); if (!file)
throw FailOpen(); }
virtual ~FileStream() { fclose(d_file); }
static void * operator new(size_t n) {
s_list.push_back(NULL); // create space in list first, as this itself
may throw
FileStream * ptr = std::malloc(n); // create memory
d_list.back() = ptr; // store memory in list
}
static void operator delete(void * v, size_t n) {
find 'v' in s_list;
erase from s_list;
}
private:
FILE * d_file;
static std::list<FileStream *> s_list;
static void cleanup() {
for (each element in s_list) delete element;
s_list.clear();
}
FileStream(const FileStream&);
FileStream& operator=(const FileStream&);
};

std::atexit(&FileStream::cleanup);
 
K

kanze

Jeff Schwab said:
Siemel Naran wrote:

When my program receives a KILL signal from the environment, how do
I make sure all "live" objects are destructed properly?
When the signal arrives, my handler function is entered. If I
don't exit the program explicitly from the handler, program
execution will resume wherever it was interrupted. I can't throw
an exception from the handler.

The most common idiom seems to be the setting of a global variable,
which is then checked at strategic points in your program. Of course,
this is royally painful. An alternative would be having every
resource in the program allocated in a way that would allow explicit
deallocation from the signal handler; for example, there could be
custom allocators for memory, and factories for objects managing other
resources.

This isn't usually possible. You cannot call free() in a signal
handler, for example. Nor fclose, nor I would imagine
std::eek:fstream::close(). Nor exit(). According to the standard, you can
in fact do very little. Most implementations guarantee more, but the
examples I just gave are forbidden by Posix as well.

In a multithreaded application under Unix, you can set things up so that
the signal is handled by a special thread, rather than in a traditional
signal handler. This thread can then call pthread_cancel on the other
threads; on some implementations, at least, this does do a stack
walkback on the thread.

But that it is all very system specific.
 
?

=?iso-8859-1?q?Markus_B._Kr=FCger?=

Siemel Naran said:
Markus B. Krüger said:
One solution is to let the signal handler set a global variable
(declared as volatile sig_atomic_t), and check this variable
regularly inside all loops of long duration. [...]

Yes, this was the advice I received in my original post to
comp.lang.c++. It's quite error-prone though because you might
forget to put these checks as you write the code. As you write your
code, you add new loops, re-arrange code, etc, and inserting these
checks is the last thing on your mind.

Perhaps one could use macros

#define } if (g_signal) throw Signal(__FILE__, __LINE__); }

This makes it impossible to write loops that *shouldn't* be
interrupted by shutdown. Perhaps a solution would be a couple of
macros

#define BEGIN_INTERRUPTABLE {
#define END_INTERRUPTABLE } \
if (g_signal) throw Signal(__FILE__, __LINE__);

and use these macros to start and end blocks that should be
interruptable by shutdown.
[...] what is the deal with sig_atomic_t? What's so special about
it?

Since a signal might arrive while you're reading from or writing to a
variable, you need a type that is guaranteed to be atomic with regard
to signal processing, so that you do not read partially updated data.
Sorry, I don't understand. Can you elaborate?

Let's say you're using a third party library for retrieving URLs, and
that you call a function getUrl(). This function would then wrap up
the connection to the web server and reading from the socket. If a
signal arrives while getUrl() is running, you need a way to make the
third party library aware that it should stop processing, since you
cannot insert the shutdown checks into the third party library
yourself. (Unless, of course, you have access to the source code, or
want to dabble with reverse engineering.)
What do you mean by "interrupted system calls"?

If a signal arrives while the system is processing a system call, such
as connect() or read(), the signal may interrupt the system call,
depending on your operating system. When this happens, your operating
system might restart the system call, return a partial success (for
instance, if some data had been read by read() when the signal
arrived), or let the system call return an error code and set errno to
EINTR.
Also, my signal.h does not have sigaction and SA_RESTART.

sigaction() is part of POSIX.1. If your platform is not POSIX.1
compatible, this function might not be available to you.
Why is mixing longjmp and RAAI bad?

Because destructors for objects currently on the stack will not be
called when you longjmp(). Simple code to illustrate the problem
follows; note that the destructor of instance a is not called as it
should be.

#include <csetjmp>
#include <iostream>

using namespace std;

class A
{
public:
A() { cout << "A::A() called" << endl; }
~A() { cout << "A::~A() called" << endl; }
};

int main(int argc, char **argv)
{
jmp_buf env;
if (setjmp(env)) {
cout << "longjmp() called, terminating" << endl;
return 0;
}

// The destructor of the following instance should be called,
// but it isn't.
A a;

longjmp(env, 1);
}
 
L

llewelly

Siemel Naran said:
Why is mixing longjmp and RAAI bad?
RAII.

In C++ style we usually declare
variables as we need them, initializing them at the same time. So a call to
longjmp may skip the initialization of objects or initialize the same object
twice. As long as we declare all variables at the top of the function and
then call setjmp, as in the C style, it should be fine to use longjmp. Is
this correct?

longjmp does not call destructors.
 
D

David Olsen

Siemel said:
Yes, this was the advice I received in my original post to comp.lang.c++.
It's quite error-prone though because you might forget to put these checks
as you write the code. As you write your code, you add new loops,
re-arrange code, etc, and inserting these checks is the last thing on your
mind.

If you want to guarantee that all resources get cleaned up properly,
then you really don't have much choice. You can't throw an exception
from an asynchronous signal handler. In the worst case, you may be in
the middle of a function prologue or epilogue, and the stack may be in
an inconsistent state such that it can't be unwound. Or the signal
could come at just the right time to cause a resource leak. For example:
std::auto_ptr<Foo> p(new Foo());
If the signal (and the resulting exception) happen after the Foo object
has been allocated and constructed, but before the auto_ptr constructor
gets started, then the Foo object will never be destroyed and its
resources will be leaked.

You need the global variable to translate an asynchronous signal into a
synchronous exception.
Perhaps one could use macros

#define } if (g_signal) throw Signal(__FILE__, __LINE__); }

No. You can only #define identifiers (with a few caveats and
exceptions). You cannot #define arbitrary symbols.
Why is mixing longjmp and RAAI bad?

Because destructors of objects will not be called when they go out of
scope as the result of a longjmp call.
 
S

Siemel Naran

However, since you're writing a network server which waits on
accept(), there is a solution - or rather, two similar solutions for
the two platforms I know. In the signal handler, you set a flag (of
type volatile sig_atomic_t under Unix, or using one of the interlocked
functions under Windows) and close() or closesocket() the listening
socket, causing accept() to fail. In error-handling for accept() you
check this flag (using an interlocked function under Windows). POSIX
guarantees that close() is safe in a signal handler (usually it is a
system call and so atomic w.r.t. signals). Under Windows I believe
the WinSock functions are all thread-safe.

Yes, I discovered this feature by accident. If you open a socket, then
close it, then bind it the bind fails by returning -1 -- and my original
code throws an exception in this case.

int b = bind(...);
if (b == -1) throw ...;

Similarly recv and all other functions fail by returning -1.

So in my signal handler it is sufficient to just close the socket!

I think this idea is similar to the other one of setting a global variable
and then testing it throughout the code, except this time the global
variable is the socket state.

So for example if we wrote a program that outputted to cout a lot, then to
exit gracefully we could in the signal handler set cout to the failstate and
set it up to throw exceptions. Then return control to the caller, and at
the next cout << x the system will throw. Something like this:

void signal_handler(iint sig) {
cout.exceptions(0);
cout.clear(ios::failbit);
cout.exceptions(all the flags);
}
 
I

Ingolf Steinbach

Hi,

Jeff said:
An alternative would be having every resource
in the program allocated in a way that would allow explicit deallocation
from the signal handler; for example, there could be custom allocators
for memory, and factories for objects managing other resources.

You typically cannot do fancy things within the signal
handler as the interrupted program might not be in a consistent
state when the handler is invoked. For instance, the program
might be in the middle of memory allocation, so the allocator
cannot be used. Or think of the following:

MyArray::MyArray(int size)
: array_(new int[size]), // signal occurs after this line
size_(size)
{
}
MyArray::~MyArray()
{
delete [] array_;
}

If the signal occurs after array_ is initialized (array_
being of type int*) but before the constructor has completed,
you would encounter a memory leak as the destructor won't
be called (even if throwing an exception from the signal
handler were supported).

Kind regards
Ingolf
 
I

Ingolf Steinbach

Hi,

Siemel said:
So for example if we wrote a program that outputted to cout a lot, then to
exit gracefully we could in the signal handler set cout to the failstate
and
set it up to throw exceptions. Then return control to the caller, and at
the next cout << x the system will throw. Something like this:

void signal_handler(iint sig) {
cout.exceptions(0);
cout.clear(ios::failbit);
cout.exceptions(all the flags);
}

Again, I think that this won't work reliably as none of the
operations are guarantieed to be atomic (and probably for
other reasons aswell). Think of, for instance, the clear()
call which has to read, modify and write the bits. The
program might just run cout.clear(....) itself when the
signal is raised. So the change within the signal handler
will probably be immediately reset by the program.

Kind regards
Ingolf
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top