Fix corruption and hanging resulting from using _exit in forked processes by calling QuitGS directly instead.

GNO's _exit (contrary to its man page) does clean-up for stuff like the memory allocator, which is inappropriate in a forked child process and leads to hangs and crashes.
This commit is contained in:
Stephen Heumann 2014-11-09 18:49:58 -06:00
parent b3a419646b
commit 6d5e65b9df
2 changed files with 44 additions and 0 deletions

View File

@ -1641,6 +1641,13 @@ int signal_parent_to_resume(void);
/* Get path of current executable */
char *get_exec_path(void);
/* On GNO, we need to use this wrapper because _exit is broken when
* called from forked child processes. */
#ifdef __GNO__
void _exit_wrapper(int status) NORETURN;
# define _exit(s) _exit_wrapper(s)
#endif
/* Simple unit-testing framework */
typedef void (*bbunit_testfunc)(void);

View File

@ -1356,6 +1356,43 @@ int signal_parent_to_resume(void) {
return 0;
}
#ifdef __GNO__
#undef _exit
#include <gsos.h>
static QuitRecGS quitRec = {0, NULL, 0};
/* _exit (contrary to its documentation) performs clean-up that's
* inappropriate for a forked child process (this usually results
* in corruption of the memory allocator state, and maybe other
* problems), so we define our own version without this problem.
*/
void _exit_wrapper(int status) {
if (getpid() == G.last_execed_pid) {
// We're the root shell or one that's been exec'd...
// Call regular _exit()
_exit(status);
} else {
// We're a forked child. Just call QuitGS. We do it in
// assembly so we can push the return value on the stack.
while (1) {
asm {
lda status
pha
jsl 0xE100A8
dcw 0x2029 /* QuitGS */
dcl quitRec;
pla
}
}
}
}
#define _exit(s) _exit_wrapper(s)
#endif
/* Basic theory of signal handling in shell
* ========================================
* This does not describe what hush does, rather, it is current understanding