Original bug ID: 7209 Reporter: lcorrenson Assigned to:@diml Status: closed (set by @xavierleroy on 2017-09-24T15:32:12Z) Resolution: fixed Priority: normal Severity: minor Version: 4.02.3 Fixed in version: 4.03.0+dev / +beta1 Category: standard library Monitored by: bobot @dbuenzli
Originally, we discover the « bug » when creating a process with a non-existing command :
Pervasive.at_exit some job
Unix.create_process with a wrong command
The job is executed twice
Diagnosis : Unix.create_process forks the original process, which is an ocaml runtime with Pervasive.at_exit registered job(s). Then, Unix.create_process fails without cleaning the duplicated runtime, hence the job is executed in both processes. When Unix.create_process succeed, the registered jobs are executed once as expected.
Less surprising, the « bug » is also visible when using Unix.fork -- is it a bug or a feature ?
A work around is to check within jobs registered via Pervasives.at_exit whether the pid has changed or not.
Though, we would suggest that any forking operation in the standard library starts by cleaning the daemons in the child processes.
For Unix.create_process, I agree that registered functions should not be run. But for generic fork I disagree since it is completely the inverse of the POSIX C atexit: When a child process is created via fork(2), it inherits copies of its parent's registrations. Upon a successful call to one of the exec(3) functions, all registrations are removed.
A simple solution is to call sys_exit (defined in pervasives.ml but not exported) instead of exit in Unix.create_process, to avoid running at_exit handlers. I did this a while ago in Lwt_process but forgot to upstream it. I'll do a patch
For 4.03 the proposed fix of Jeremy Dimino is great. For a later version I'm wondering if caml_sys_exit is the best since it prints gc statistics and gc instrumented time. It is just noise for these functions that does no allocation. A direct call to the C exit function would be better.