exit, signals and exceptions

S

Siemel Naran

(1) About std::exit. If I call this function, will the system call the
destructors of all objects in the call stack. Eg.

void f() { std::exit(1); }
void g() { X x; f(); }

Does the call in f() to std::exit invoke x.~X() in scope g()?


(2) About signals and exceptions. Is it possible to throw an exception from
a signal handler. On my compiler the program ends with the error in a
dialog box:

Project.exe faulted with message "application-defined exception". Process
Stopped. Use Step or Run to continue.


(3) So assuming that we can throw exceptions in signal handlers and that
exit does cleanup, is the following a good way to invoke cleanup when
either we exit normally, or throw an exception, or have a signal? My
instinct says something is wrong here:


int global_s = -1;


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

class CloseSockets
{
public:
CloseSockets() { }
~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;
std::signal(SIGINT , &closesockets); // are these even necessary?
std::signal(SIGTERM, &closesockets);
std::signal(SIGABRT, &closesockets);

sockaddr_in my_address;
my_address.sin_family = AF_INET;
my_address.sin_port = htons(1972);
my_address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
std::memset(my_address.sin_zero, 0, sizeof(my_address.sin_zero));

int b = bind(s, convert(&my_address), sizeof(sockaddr));
if (b == -1) throw std::runtime_error("fail bind"); // will call
_closesocket's destructor

int l = listen(s, 10);
if (l == -1) throw std::runtime_error("fail listen"); // will call
_closesocket's destructor

while (true)
{
...
}

// will call _closesocket's destructor
}
 
F

Fraser Ross

(1) About std::exit. If I call this function, will the system call the
destructors of all objects in the call stack. Eg.

void f() { std::exit(1); }
void g() { X x; f(); }

Does the call in f() to std::exit invoke x.~X() in scope g()?

std::exit does not do stack unwinding.

Fraser.
 
T

tom_usenet

(1) About std::exit. If I call this function, will the system call the
destructors of all objects in the call stack. Eg.

void f() { std::exit(1); }
void g() { X x; f(); }

Does the call in f() to std::exit invoke x.~X() in scope g()?

No. Objects of static storage duration are destructed ok, but those of
automatic storage duration are not. (3.6.1/4)
(2) About signals and exceptions. Is it possible to throw an exception from
a signal handler. On my compiler the program ends with the error in a
dialog box:

Project.exe faulted with message "application-defined exception". Process
Stopped. Use Step or Run to continue.

It's implementation defined. You can use common C/C++ subset stuff in
signal handlers, but if you try to use any C++ features such as RTTI
and exceptions, you're at the mercy of your implementation. (18.7/5)

Tom
 
D

Denis Remezov

Siemel said:
[snip]

(2) About signals and exceptions. Is it possible to throw an exception from
a signal handler. On my compiler the program ends with the error in a
dialog box:

Project.exe faulted with message "application-defined exception". Process
Stopped. Use Step or Run to continue.
[snip]

If some implementation allowed that in principle (or perhaps some does?),
all functions during whose execution an interrupt could occur, and which are
also called by any destructor for automatic objects from the point of an
interrupt up to the exception handler, would need to be reentrant.
That would probably be quite inconvenient to enforce. Memory management
functions, for example, are usually not reentrant.

Denis
 
D

Denis Remezov

Siemel said:
OK. 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 feeling was to establish a signal handler. If the signal handler does
nothing it seems 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 as
you point out, this does not work.

In my code posted for point (3) I assumed std::exit calls destructors of
local objects in all stacks, but this is also incorrect.

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

I would try to limit myself to simple things within a signal handler, such
as, for example, setting a global flag to indicate that a particular interrupt
has occured. This flag can be examined later in a synchronous way, within a
normal execution flow, when it is safe to throw an exception.
Granted, you could do more in some cases. For instance, there are a number
of POSIX functions that can be called asynchronously.

Denis
 
S

Siemel Naran

No. Objects of static storage duration are destructed ok, but those of
automatic storage duration are not. (3.6.1/4)


It's implementation defined. You can use common C/C++ subset stuff in
signal handlers, but if you try to use any C++ features such as RTTI
and exceptions, you're at the mercy of your implementation. (18.7/5)

OK. 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 feeling was to establish a signal handler. If the signal handler does
nothing it seems 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 as
you point out, this does not work.

In my code posted for point (3) I assumed std::exit calls destructors of
local objects in all stacks, but this is also incorrect.

So what else can we do? This seems to be a common problem, and I'm sure
people have put much thought into it.
 
S

Siemel Naran

Denis Remezov said:
Siemel Naran wrote:
(2) About signals and exceptions. Is it possible to throw an exception from
a signal handler. On my compiler the program ends with the error in a
dialog box:

Project.exe faulted with message "application-defined exception". Process
Stopped. Use Step or Run to continue.
[snip]

If some implementation allowed that in principle (or perhaps some does?),
all functions during whose execution an interrupt could occur, and which are
also called by any destructor for automatic objects from the point of an
interrupt up to the exception handler, would need to be reentrant.
That would probably be quite inconvenient to enforce. Memory management
functions, for example, are usually not reentrant.

Sorry, I'm not too familiar with this concept of re-entrant. Did a search
on google, and found statements about it like it allows two processes to
call the same function. But you can do this anyway! Do they mean that the
function instances share the same local variables?

So assuming these re-entrant functions were to become standard in C++, how
would you write the code using re-entrant functions, and satisying the
conditions in my response to tom_usenet?

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

....

Thanks.
 
S

Siemel Naran

Denis Remezov said:
Siemel Naran wrote:
I would try to limit myself to simple things within a signal handler, such
as, for example, setting a global flag to indicate that a particular interrupt
has occured. This flag can be examined later in a synchronous way, within a
normal execution flow, when it is safe to throw an exception.
Granted, you could do more in some cases. For instance, there are a number
of POSIX functions that can be called asynchronously.

Yes, this came to mind too, but it means that in the main code I have to
have these if statements all over the place to check if the global flag is
set. Like in the code

connect;
while (true) {
receive from socket;
}
return;

that might have to become

connect;
while (true) {
if (g_sigint) throw SigInt();
receive from socket;
}
if (g_sigint) throw SigInt();
return;

etc, etc. Maybe need even more throw SigInt expressions.

Perhaps there is some longjmp thing that can do it for me?
 
D

Denis Remezov

Siemel said:
Denis Remezov said:
Siemel Naran wrote:
(2) About signals and exceptions. Is it possible to throw an exception from
a signal handler. On my compiler the program ends with the error in a
dialog box:

Project.exe faulted with message "application-defined exception". Process
Stopped. Use Step or Run to continue.
[snip]

If some implementation allowed that in principle (or perhaps some does?),
all functions during whose execution an interrupt could occur, and which are
also called by any destructor for automatic objects from the point of an
interrupt up to the exception handler, would need to be reentrant.
That would probably be quite inconvenient to enforce. Memory management
functions, for example, are usually not reentrant.

Sorry, I'm not too familiar with this concept of re-entrant. Did a search
on google, and found statements about it like it allows two processes to
call the same function. But you can do this anyway! Do they mean that the
function instances share the same local variables?

What I meant was well-definedness of concurrent invocations within one process.
A pure function will be reentrant (i.e. on the systems that you are probably
interested in).
A function that uses a global variable, obviously, may well not be (but still
can in specific cases).

The term is often used in regards to multithreading. There, reentrancy can
often be achieved by associating a required global state with a thread.

Signal handling [back on topic] is different. On the system that I'm working
with, a handler will have the context of the thread in which it was registered.
I am under the impression that functions that use a per-thread global state
(e.g. malloc()) are often not reentrant in regards to asynchronous signal
handler invocations.

Denis
 
P

Paavo Helde

Siemel Naran said:
OK. 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.

Have you considered to use _exit() instead of exit()? The exit()
function will call destructors for static objects (and other
atexit/onexit things), which might lead to errors if the program state
is not what these destructors expect. _exit() does not call anything
and shuts down your program very gracefully and very fast. The
operating system (MS-DOS not counted ;-) will release the dynamic
memory, close sockets, close file handles (buffers not flushed) and
other OS-allocated resources, so that's about what you asked for :)

If you need a specific cleanup for some sort of resource (SQL
connections?) then you can't use _exit(). But you can register these
resources (and only these!) by some static manager object and rely on
exit() to call it's dtor.

Regards
Paavo
 
S

Siemel Naran

Paavo Helde said:
Have you considered to use _exit() instead of exit()? The exit()

Is this in the standard? Since it begins with an underscore, probably not.
 
T

tom_usenet

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

I think you need to register some cleanup handlers with atexit, or use
objects of static storage duration (such as singletons). It's a pain,
but it works. Remember, the OS will release almost everything for you
on a modern OS, so you only need handlers for certain things.

Tom
 
P

Paavo Helde

Siemel Naran said:
Is this in the standard? Since it begins with an underscore, probably not.

You are right, _exit() is not in ANSI/ISO C, but it's in POSIX which
for most applications is portable enough IMHO. Of course your mileage
may vary.

Regards
Paavo
 

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

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top