I have a simple program which uses select and stuff like that for multiplexing IO.
To interrupt the "server" process, I integrated a sig_handler which reacts on SIGINT.
Each time when memory is allocated, the containing method does the free itself or the calling method.
Using valgrind shows up, that there are some allocation aren't freed up.
Perhaps there is no need for it, but I want to learn what would be the best way to handle the signal.
It seems that the free calls aren't invoked when pressing STRG + C.
So it would be senseless to quit loops with a break condition, which was my first approach.
Is there any possibility to clean every thing up, before closing the whole program?
Thanks for any hints and advices.
Valgrind is just a tool for finding memory leaks, not an oracle whose advice must be heeded. Making a program "Valgrind-clean" is a worthy goal but don't let it get out of hand. Ask yourself some questions about the program.
Does the program need to do anything when it receives a SIGINT or SIGQUIT or whatever? Does it need to do some kind of clean shutdown? For example, a server might decide to finish handling all open requests, or at least send a shutdown message to connected clients.
Does a sudden termination always leave behind certain blocks? Then you can just quash those reports from Valgrind, without having to spend extra time freeing memory that's already going to be freed.
In simple terms, there are only two reasons to call free in a program that is about to exit.
If it's the easiest way to quash Valgrind messages (that is, without reading the Valgrind manual)
If it makes your code simpler.
Otherwise, just don't call free during program exit, since all it will do is burn CPU cycles.
Handling SIGINT: I can think of four common ways to handle a SIGINT:
Use the default handler. Highly recommended, this requires the least amount of code and is unlikely to result in any abnormal program behavior. Your program will simply exit.
Use longjmp to exit immediately. This is for folk who like to ride fast motorcycles without helmets. It's like playing Russian roulette with library calls. Not recommended.
Set a flag, and interrupt the main loop's pselect/ppoll. This is a pain to get right, since you have to twiddle with signal masks. You want to interrupt pselect/ppoll only, and not non-reentrant functions like malloc or free, so you have to be very careful with things like signal masks. Not recommended. You have to use pselect/ppoll instead of select/poll, because the "p" versions can set the signal mask atomically. If you use select or poll, a signal can arrive after you check the flag but before you call select/poll, this is bad.
Create a pipe to communicate between the main thread and the signal handler. Always include this pipe in the call to select/poll. The signal handler simply writes one byte to the pipe, and if the main loop successfully reads one byte from the other end, then it exits cleanly. Highly recommended. You can also have the signal handler uninstall itself, so an impatient user can hit CTRL+C twice to get an immediate exit.
The two simplest and most fool-proof methods are #1 and #4.
A program that exits does not have any leaks. Only a running program can have leaks. Once the program exits, all memory is freed (so there is no leak any more).
Here's my simple and slightly dirty solution.
#include <signal.h>
volatile bool gContinue;
void handleCtrlC(int ) {
gContinue = false;
}
int main () {
gContinue = true;
signal(SIGINT, handleCtrlC);
... allocate memory ...
sigset_t sigmask;
sigemptyset (&sigmask);
while (gContinue) {
/*...*/
ready = pselect(nfds, &readfds, &writefds, &exceptfds,
timeout, &sigmask);
/*...*/
}
... free memory ...
return 0;
}
Edit: Added pselect to the loop.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With