Adam Hunt's suggestion will work, provided that you add a check for the flag just before your call to select
. It must be immediately before because your normal EINTR
handling would likely skip over the check otherwise, so the exiting would be delayed until your next select
returned a real event.
while (gContinue) {
/*set up some stuff for next select call*/
do {
if (gContinue == 0) break;
nfds = select(...);
} while (nfds == -1 && errno == EINTR);
/*handle select return*/
}
Edit: Dietrich Epp points out there is a race condition between the flag check and the select
call that can only be closed by a call to pselect
. pselect
is very similar to select
, with the primary difference being the last parameter is used as a mask to determine which signals to block. So the code sample below closes the race between the flag check and the pselect
call:
sigset_t emptyset, blockset, origset;
sigemptyset(&emptyset);
sigemptyset(&blockset);
sigaddset(&blockset, SIGINT);
while (gContinue) {
/*...*/
sigprocmask(SIG_BLOCK, &blockset, &origset);
do {
if (gContinue == 0) break;
nfds = pselect(..., &emptyset);
} while (nfds == -1 && errno == EINTR);
sigprocmask(SIG_SETMASK, &origset, NULL);
/*...*/
};
Another approach is to register all your allocated elements to a global data structure, so that they can be freed by an atexit
handler that you install. If you end up in code that will deallocate it, unregister it from the global data structure first;
m = malloc(sz);
register_allocation(m);
/*...*/
unregister_allocation(m);
free(m);
And using atexit
:
void cleanup_allocations () {
/*...*/
}
atexit(cleanup_allocations);