use process descriptors where available for readiness notification
This commit is contained in:
parent
97b1a11be0
commit
2477e7266c
1 changed files with 67 additions and 12 deletions
|
@ -30,23 +30,78 @@
|
||||||
|
|
||||||
#define SHELL "/bin/sh"
|
#define SHELL "/bin/sh"
|
||||||
|
|
||||||
/* TODO: Add support for Linux process descriptors once it is okay to require
|
#if defined(__linux__)
|
||||||
* Linux 5.3 or newer.
|
# include <sys/syscall.h>
|
||||||
*/
|
#endif
|
||||||
|
|
||||||
|
/* POSIX compatible fallback using waitpid(2) and usleep(3) */
|
||||||
|
static inline bool
|
||||||
|
lif_process_monitor_busyloop(pid_t child, int timeout_sec, int *status)
|
||||||
|
{
|
||||||
|
int ticks = 0;
|
||||||
|
|
||||||
|
while (ticks < timeout_sec * 10)
|
||||||
|
{
|
||||||
|
/* Ugly hack: most executors finish very quickly,
|
||||||
|
* so give them a chance to finish before sleeping.
|
||||||
|
*/
|
||||||
|
usleep(50);
|
||||||
|
|
||||||
|
if (waitpid(child, status, WNOHANG) == child)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
usleep(99950);
|
||||||
|
ticks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__linux__) && defined(__NR_pidfd_open)
|
||||||
|
|
||||||
|
/* TODO: remove this wrapper once musl and glibc gain pidfd_open() directly. */
|
||||||
|
static inline int
|
||||||
|
lif_pidfd_open(pid_t pid, unsigned int flags)
|
||||||
|
{
|
||||||
|
return syscall(__NR_pidfd_open, pid, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
lif_process_monitor_procdesc(pid_t child, int timeout_sec, int *status)
|
||||||
|
{
|
||||||
|
int pidfd = lif_pidfd_open(child, 0);
|
||||||
|
|
||||||
|
/* pidfd_open() not available, fall back to busyloop */
|
||||||
|
if (pidfd == -1 && errno == ENOSYS)
|
||||||
|
return lif_process_monitor_busyloop(child, timeout_sec, status);
|
||||||
|
|
||||||
|
struct pollfd pfd = {
|
||||||
|
.fd = pidfd,
|
||||||
|
.events = POLLIN,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (poll(&pfd, 1, timeout_sec * 1000) < 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
waitpid(child, status, 0);
|
||||||
|
close(pidfd);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
lif_process_monitor(const char *cmdbuf, pid_t child, int timeout_sec)
|
lif_process_monitor(const char *cmdbuf, pid_t child, int timeout_sec)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
int ticks = 0;
|
|
||||||
|
|
||||||
while (ticks < timeout_sec)
|
#if defined(__linux__) && defined(__NR_pidfd_open)
|
||||||
{
|
if (lif_process_monitor_procdesc(child, timeout_sec, &status))
|
||||||
if (waitpid(child, &status, WNOHANG) == child)
|
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
|
||||||
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
|
#else
|
||||||
|
if (lif_process_monitor_busyloop(child, timeout_sec, &status))
|
||||||
sleep(1);
|
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
|
||||||
ticks++;
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, "execution of '%s': timeout after %d seconds\n", cmdbuf, timeout_sec);
|
fprintf(stderr, "execution of '%s': timeout after %d seconds\n", cmdbuf, timeout_sec);
|
||||||
kill(child, SIGKILL);
|
kill(child, SIGKILL);
|
||||||
|
|
Loading…
Reference in a new issue