It is easy to start a process from a specific directory with Lwt using the functions Sys.getpwd
, Lwt_unix.chdir
and Lwt_process.exec
:
Sys.getpwd
to save the current working directoryLwt_unix.chdir
to change to the specific directoryLwt_process.exec
to start the external processLwt_unix.chdir
to change to the saved current working directoryThis logic is flawed, for it allows the scheduler to run another thread after after the first call to Lwt_unix.chdir
and after the call to Lwt_process.exec
which would lead this thread to be run in special directory rather than in the saved current directory. Is it possible to easily start a process from a special directory with Lwt without introducing a race condition such as the one I describe?
You can protect your current working directory with with some synchronization primitive, like Lwt_mutex
. But there is some caveat here, suppose you have this chain:
lock dir_guard >> chdir dir >> exec proc >> chdir dir' >> unlock dir_guard
Which disallows changing the directory for the whole time the process proc
is performing its task. This maybe overcautious and unnecessary. The following code doesn't have this problems:
let exec_in_folder guard dir proc =
with_lock guard (fun () ->
chdir dir >>= fun () -> return (exec proc)) >>= fun proc_t ->
proc_t
But, this code, has an issue, it is correct only if process is started atomically, i.e., if there is no such possibility that during the process starting procedure there will be some rescheduling, that will allow other thread to interfere and to change current folder. To proof that it is atomic, you can either read sources, or implement your own process started, that will have such guarantees. If you will read the code, then you will figure out, that process is created with spawn
function, that momentary will do a fork
without any interspersed threads. So yes, this code is correct.