aboutsummaryrefslogtreecommitdiff
path: root/libbutl/process.cxx
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2019-11-16 14:43:56 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2019-11-16 15:47:18 +0300
commitaf077f06d30703088d784e73e6088ce69a419561 (patch)
tree681be753b0a2b4afd6eeae6d6775c5a62ff12484 /libbutl/process.cxx
parente8381d5e5e19166001561244f7a9db5742f1090a (diff)
Try to re-exec POSIX process after "text file busy" failure for 450ms
Diffstat (limited to 'libbutl/process.cxx')
-rw-r--r--libbutl/process.cxx27
1 files changed, 21 insertions, 6 deletions
diff --git a/libbutl/process.cxx b/libbutl/process.cxx
index e2a8af1..8d067f4 100644
--- a/libbutl/process.cxx
+++ b/libbutl/process.cxx
@@ -624,12 +624,14 @@ namespace butl
// "text file busy" issue: if some other thread creates a shell script
// and the write-open file descriptor leaks into some child process,
// then exec() for this script fails with ETXTBSY (see exec() man page
- // for details).
+ // for details). If that's the case, it feels like such a descriptor
+ // should not stay open for too long. Thus, we will retry the exec()
+ // calls for about half a second.
//
handle = fork ();
if (handle == -1)
- fail (false);
+ fail (false /* child */);
if (handle == 0)
{
@@ -647,7 +649,7 @@ namespace butl
assert (fd > -1);
if (dup2 (fd, sd) == -1)
- fail (true);
+ fail (true /* child */);
pd.in.reset (); // Silently close.
pd.out.reset (); // Silently close.
@@ -680,7 +682,7 @@ namespace butl
// Change current working directory if requested.
//
if (cwd != nullptr && *cwd != '\0' && chdir (cwd) != 0)
- fail (true);
+ fail (true /* child */);
// Set/unset environment variables if requested.
//
@@ -704,8 +706,21 @@ namespace butl
}
}
- if (execv (pp.effect_string (), const_cast<char**> (&args[0])) == -1)
- fail (true);
+ // Try to re-exec after the "text file busy" failure for 450ms.
+ //
+ // Note that execv() does not return on success.
+ //
+ for (size_t i (1); i != 10; ++i)
+ {
+ execv (pp.effect_string (), const_cast<char**> (&args[0]));
+
+ if (errno != ETXTBSY)
+ break;
+
+ this_thread::sleep_for (i * 10ms);
+ }
+
+ fail (true /* child */);
}
} // Release the lock in parent.
#endif // LIBBUTL_POSIX_SPAWN_CHDIR