diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/3rdparty/forkfd/forkfd.c | 97 | ||||
-rw-r--r-- | src/3rdparty/forkfd/forkfd.h | 10 | ||||
-rw-r--r-- | src/corelib/io/qprocess_unix.cpp | 15 |
3 files changed, 87 insertions, 35 deletions
diff --git a/src/3rdparty/forkfd/forkfd.c b/src/3rdparty/forkfd/forkfd.c index 8d08f403ec..86e109358c 100644 --- a/src/3rdparty/forkfd/forkfd.c +++ b/src/3rdparty/forkfd/forkfd.c @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014 Intel Corporation +** Copyright (C) 2015 Intel Corporation ** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com ** ** Permission is hereby granted, free of charge, to any person obtaining a copy @@ -31,6 +31,8 @@ #include "forkfd.h" #include <sys/types.h> +#include <sys/time.h> +#include <sys/resource.h> #include <sys/wait.h> #include <assert.h> #include <errno.h> @@ -38,6 +40,7 @@ #include <signal.h> #include <stdlib.h> #include <string.h> +#include <time.h> #include <unistd.h> #ifdef __linux__ @@ -79,6 +82,12 @@ ret = call; \ } while (ret == -1 && errno == EINTR) +struct pipe_payload +{ + struct forkfd_info info; + struct rusage rusage; +}; + typedef struct process_info { ffd_atomic_int pid; @@ -179,33 +188,43 @@ static int isChildReady(pid_t pid, siginfo_t *info) } #endif -static int tryReaping(pid_t pid, siginfo_t *info) +static int tryReaping(pid_t pid, struct pipe_payload *payload) { /* reap the child */ #ifdef HAVE_WAITID if (waitid_works) { // we have waitid(2), which fills in siginfo_t for us - info->si_pid = 0; - return waitid(P_PID, pid, info, WEXITED | WNOHANG) == 0 && info->si_pid == pid; + siginfo_t info; + info.si_pid = 0; + int ret = waitid(P_PID, pid, &info, WEXITED | WNOHANG) == 0 && info.si_pid == pid; + if (!ret) + return ret; + + payload->info.code = info.si_code; + payload->info.status = info.si_status; +# ifdef __linux__ + payload->rusage.ru_utime.tv_sec = info.si_utime / CLOCKS_PER_SEC; + payload->rusage.ru_utime.tv_usec = info.si_utime % CLOCKS_PER_SEC; + payload->rusage.ru_stime.tv_sec = info.si_stime / CLOCKS_PER_SEC; + payload->rusage.ru_stime.tv_usec = info.si_stime % CLOCKS_PER_SEC; +# endif + return 1; } #endif - int status; if (waitpid(pid, &status, WNOHANG) <= 0) return 0; // child did not change state - info->si_signo = SIGCHLD; - info->si_pid = pid; if (WIFEXITED(status)) { - info->si_code = CLD_EXITED; - info->si_status = WEXITSTATUS(status); + payload->info.code = CLD_EXITED; + payload->info.status = WEXITSTATUS(status); } else if (WIFSIGNALED(status)) { - info->si_code = CLD_KILLED; + payload->info.code = CLD_KILLED; # ifdef WCOREDUMP if (WCOREDUMP(status)) - info->si_code = CLD_DUMPED; + payload->info.code = CLD_DUMPED; # endif - info->si_status = WTERMSIG(status); + payload->info.status = WTERMSIG(status); } return 1; @@ -220,10 +239,11 @@ static void freeInfo(Header *header, ProcessInfo *entry) assert(header->busyCount >= 0); } -static void notifyAndFreeInfo(Header *header, ProcessInfo *entry, siginfo_t *info) +static void notifyAndFreeInfo(Header *header, ProcessInfo *entry, + const struct pipe_payload *payload) { ssize_t ret; - EINTR_LOOP(ret, write(entry->deathPipe, info, sizeof(*info))); + EINTR_LOOP(ret, write(entry->deathPipe, payload, sizeof(*payload))); EINTR_LOOP(ret, close(entry->deathPipe)); freeInfo(header, entry); @@ -243,9 +263,11 @@ static void sigchld_handler(int signum) /* is this one of our children? */ BigArray *array; siginfo_t info; + struct pipe_payload payload; int i; memset(&info, 0, sizeof info); + memset(&payload, 0, sizeof payload); #ifdef HAVE_WAITID if (!waitid_works) @@ -275,8 +297,8 @@ search_next_child: FFD_ATOMIC_ACQUIRE, FFD_ATOMIC_RELAXED)) { /* this is our child, send notification and free up this entry */ /* ### FIXME: what if tryReaping returns false? */ - if (tryReaping(pid, &info)) - notifyAndFreeInfo(&children.header, &children.entries[i], &info); + if (tryReaping(pid, &payload)) + notifyAndFreeInfo(&children.header, &children.entries[i], &payload); goto search_next_child; } } @@ -290,8 +312,8 @@ search_next_child: FFD_ATOMIC_ACQUIRE, FFD_ATOMIC_RELAXED)) { /* this is our child, send notification and free up this entry */ /* ### FIXME: what if tryReaping returns false? */ - if (tryReaping(pid, &info)) - notifyAndFreeInfo(&array->header, &array->entries[i], &info); + if (tryReaping(pid, &payload)) + notifyAndFreeInfo(&array->header, &array->entries[i], &payload); goto search_next_child; } } @@ -321,9 +343,9 @@ search_arrays: continue; } #endif - if (tryReaping(pid, &info)) { + if (tryReaping(pid, &payload)) { /* this is our child, send notification and free up this entry */ - notifyAndFreeInfo(&children.header, &children.entries[i], &info); + notifyAndFreeInfo(&children.header, &children.entries[i], &payload); } } @@ -344,9 +366,9 @@ search_arrays: continue; } #endif - if (tryReaping(pid, &info)) { + if (tryReaping(pid, &payload)) { /* this is our child, send notification and free up this entry */ - notifyAndFreeInfo(&array->header, &array->entries[i], &info); + notifyAndFreeInfo(&array->header, &array->entries[i], &payload); } } @@ -626,7 +648,7 @@ int spawnfd(int flags, pid_t *ppid, const char *path, const posix_spawn_file_act { Header *header; ProcessInfo *info; - siginfo_t si; + struct pipe_payload payload; pid_t pid; int death_pipe[2]; int ret = -1; @@ -664,8 +686,8 @@ int spawnfd(int flags, pid_t *ppid, const char *path, const posix_spawn_file_act ffd_atomic_store(&info->pid, pid, FFD_ATOMIC_RELEASE); /* check if the child has already exited */ - if (tryReaping(pid, &si)) - notifyAndFreeInfo(header, info, &si); + if (tryReaping(pid, &payload)) + notifyAndFreeInfo(header, info, &payload); ret = death_pipe[0]; return ret; @@ -682,3 +704,28 @@ out: return -1; } #endif // _POSIX_SPAWN && !FORKFD_NO_SPAWNFD + + +int forkfd_wait(int ffd, forkfd_info *info, struct rusage *rusage) +{ + struct pipe_payload payload; + int ret; + + ret = read(ffd, &payload, sizeof(payload)); + if (ret == -1) + return ret; /* pass errno, probably EINTR, EBADF or EWOULDBLOCK */ + + assert(ret == sizeof(payload)); + if (info) + *info = payload.info; + if (rusage) + *rusage = payload.rusage; + + return 0; /* success */ +} + + +int forkfd_close(int ffd) +{ + return close(ffd); +} diff --git a/src/3rdparty/forkfd/forkfd.h b/src/3rdparty/forkfd/forkfd.h index b3ffe2bff3..dcb36f9f33 100644 --- a/src/3rdparty/forkfd/forkfd.h +++ b/src/3rdparty/forkfd/forkfd.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014 Intel Corporation +** Copyright (C) 2015 Intel Corporation ** ** Permission is hereby granted, free of charge, to any person obtaining a copy ** of this software and associated documentation files (the "Software"), to deal @@ -26,6 +26,7 @@ #define FORKFD_H #include <fcntl.h> +#include <stdint.h> #include <unistd.h> // to get the POSIX flags #ifdef _POSIX_SPAWN @@ -41,7 +42,14 @@ extern "C" { #define FFD_CHILD_PROCESS (-2) +struct forkfd_info { + int32_t code; + int32_t status; +}; + int forkfd(int flags, pid_t *ppid); +int forkfd_wait(int ffd, forkfd_info *info, struct rusage *rusage); +int forkfd_close(int ffd); #ifdef _POSIX_SPAWN /* only for spawnfd: */ diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index 0fc9464f52..7b6da90b04 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -1091,20 +1091,17 @@ bool QProcessPrivate::waitForDeadChild() return true; // child has already exited // read the process information from our fd - siginfo_t info; - qint64 ret = qt_safe_read(forkfd, &info, sizeof info); - Q_ASSERT(ret == sizeof info); - Q_UNUSED(ret); + forkfd_info info; + int ret; + EINTR_LOOP(ret, forkfd_wait(forkfd, &info, Q_NULLPTR)); - Q_ASSERT(info.si_pid == pid_t(pid)); - - exitCode = info.si_status; - crashed = info.si_code != CLD_EXITED; + exitCode = info.status; + crashed = info.code != CLD_EXITED; delete deathNotifier; deathNotifier = 0; - qt_safe_close(forkfd); + EINTR_LOOP(ret, forkfd_close(forkfd)); forkfd = -1; // Child is dead, don't try to kill it anymore #if defined QPROCESS_DEBUG |