According to "man atexit" on my system, the POSIX.1-2001 behaviour of calling exit within an atexit handler is undefined. Indeed it suggests an infinite loop is a possible outcome. I think the correct way of exiting from an atexit function is probably to call _exit.
let exit retcode =
Could be replaced by:
let exit_code = ref None
let exit retcode = match !exit_code with
| Some _ when retcode = 0 -> ()
| Some _ -> exit_code := Some retcode
| None ->
exit_code := Some retcode;
match !exit_code with
| None -> assert false
| Some retcode -> sys_exit retcode
to solve the problem. The semantics is that the last non-zero [exit] call gives the final exit code of the program.