diff --git a/headers/private/kernel/team.h b/headers/private/kernel/team.h index 2fb555e493..e376409f75 100644 --- a/headers/private/kernel/team.h +++ b/headers/private/kernel/team.h @@ -69,7 +69,8 @@ thread_id _user_load_image(const char* const* flatArgs, size_t flatArgsSize, status_t _user_wait_for_team(team_id id, status_t *_returnCode); void _user_exit_team(status_t returnValue); status_t _user_kill_team(thread_id thread); -pid_t _user_wait_for_child(thread_id child, uint32 flags, siginfo_t* info); +pid_t _user_wait_for_child(thread_id child, uint32 flags, siginfo_t* info, + team_usage_info* usageInfo); status_t _user_exec(const char *path, const char* const* flatArgs, size_t flatArgsSize, int32 argCount, int32 envCount, mode_t umask); thread_id _user_fork(void); diff --git a/headers/private/kernel/thread_types.h b/headers/private/kernel/thread_types.h index e90e25829a..720a221c17 100644 --- a/headers/private/kernel/thread_types.h +++ b/headers/private/kernel/thread_types.h @@ -116,6 +116,8 @@ struct job_control_entry : DoublyLinkedListLinkImpl { status_t status; uint16 reason; // reason for the team's demise, one of the // CLD_* values defined in + bigtime_t user_time; + bigtime_t kernel_time; job_control_entry(); ~job_control_entry(); diff --git a/headers/private/system/syscalls.h b/headers/private/system/syscalls.h index 35fe2a1632..9d5e8f2eab 100644 --- a/headers/private/system/syscalls.h +++ b/headers/private/system/syscalls.h @@ -141,7 +141,7 @@ extern status_t _kern_kill_team(team_id team); extern team_id _kern_get_current_team(); extern status_t _kern_wait_for_team(team_id team, status_t *_returnCode); extern pid_t _kern_wait_for_child(thread_id child, uint32 flags, - siginfo_t* info); + siginfo_t* info, team_usage_info* usageInfo); extern status_t _kern_exec(const char *path, const char* const* flatArgs, size_t flatArgsSize, int32 argCount, int32 envCount, mode_t umask); diff --git a/src/libs/bsd/wait.c b/src/libs/bsd/wait.c index 368d8dddad..57fc328992 100644 --- a/src/libs/bsd/wait.c +++ b/src/libs/bsd/wait.c @@ -12,6 +12,10 @@ #include +extern pid_t _waitpid(pid_t pid, int* _status, int options, + team_usage_info *usage_info); + + pid_t wait3(int *status, int options, struct rusage *rusage) { @@ -22,14 +26,10 @@ wait3(int *status, int options, struct rusage *rusage) pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage) { - pid_t waitPid = waitpid(pid, status, options); - if (waitPid != -1) { - team_usage_info info; - - // Obtain info for the process that changed state. - if (get_team_usage_info(waitPid, RUSAGE_SELF, &info) != B_OK) - return -1; - + team_usage_info info; + pid_t waitPid = _waitpid(pid, status, options, + rusage != NULL ? &info : NULL); + if (waitPid != -1 && rusage != NULL) { rusage->ru_utime.tv_sec = info.user_time / 1000000; rusage->ru_utime.tv_usec = info.user_time % 1000000; diff --git a/src/system/kernel/team.cpp b/src/system/kernel/team.cpp index 1b364fea88..5a78c08b48 100644 --- a/src/system/kernel/team.cpp +++ b/src/system/kernel/team.cpp @@ -2369,6 +2369,10 @@ job_control_entry::InitDeadState() reason = team->exit.reason; signal = team->exit.signal; signaling_user = team->exit.signaling_user; + user_time = team->dead_threads_user_time + + team->dead_children.user_time; + kernel_time = team->dead_threads_kernel_time + + team->dead_children.kernel_time; team = NULL; } @@ -2387,6 +2391,8 @@ job_control_entry::operator=(const job_control_entry& other) group_id = other.group_id; status = other.status; reason = other.reason; + user_time = other.user_time; + kernel_time = other.kernel_time; return *this; } @@ -2395,7 +2401,8 @@ job_control_entry::operator=(const job_control_entry& other) /*! This is the kernel backend for waitid(). */ static thread_id -wait_for_child(pid_t child, uint32 flags, siginfo_t& _info) +wait_for_child(pid_t child, uint32 flags, siginfo_t& _info, + team_usage_info& _usage_info) { Thread* thread = thread_get_current_thread(); Team* team = thread->team; @@ -2533,6 +2540,8 @@ wait_for_child(pid_t child, uint32 flags, siginfo_t& _info) _info.si_code = foundEntry.reason; _info.si_status = foundEntry.reason == CLD_EXITED ? foundEntry.status : foundEntry.signal; + _usage_info.user_time = foundEntry.user_time; + _usage_info.kernel_time = foundEntry.kernel_time; break; case JOB_CONTROL_STATE_STOPPED: _info.si_code = CLD_STOPPED; @@ -3915,19 +3924,28 @@ _user_fork(void) pid_t -_user_wait_for_child(thread_id child, uint32 flags, siginfo_t* userInfo) +_user_wait_for_child(thread_id child, uint32 flags, siginfo_t* userInfo, + team_usage_info* usageInfo) { if (userInfo != NULL && !IS_USER_ADDRESS(userInfo)) return B_BAD_ADDRESS; + if (usageInfo != NULL && !IS_USER_ADDRESS(usageInfo)) + return B_BAD_ADDRESS; siginfo_t info; - pid_t foundChild = wait_for_child(child, flags, info); + team_usage_info usage_info; + pid_t foundChild = wait_for_child(child, flags, info, usage_info); if (foundChild < 0) return syscall_restart_handle_post(foundChild); // copy info back to userland if (userInfo != NULL && user_memcpy(userInfo, &info, sizeof(info)) != B_OK) return B_BAD_ADDRESS; + // copy usage_info back to userland + if (usageInfo != NULL && user_memcpy(usageInfo, &usage_info, + sizeof(usage_info)) != B_OK) { + return B_BAD_ADDRESS; + } return foundChild; } diff --git a/src/system/libroot/posix/sys/wait.cpp b/src/system/libroot/posix/sys/wait.cpp index 1c785c9fdb..d410a48737 100644 --- a/src/system/libroot/posix/sys/wait.cpp +++ b/src/system/libroot/posix/sys/wait.cpp @@ -23,13 +23,12 @@ wait(int* _status) return waitpid(-1, _status, 0); } - -pid_t -waitpid(pid_t pid, int* _status, int options) +extern "C" pid_t +_waitpid(pid_t pid, int* _status, int options, team_usage_info *usage_info) { // wait siginfo_t info; - pid_t child = _kern_wait_for_child(pid, options, &info); + pid_t child = _kern_wait_for_child(pid, options, &info, usage_info); pthread_testcancel(); @@ -84,6 +83,13 @@ waitpid(pid_t pid, int* _status, int options) } +pid_t +waitpid(pid_t pid, int* _status, int options) +{ + return _waitpid(pid, _status, options, NULL); +} + + int waitid(idtype_t idType, id_t id, siginfo_t* info, int options) { @@ -111,7 +117,7 @@ waitid(idtype_t idType, id_t id, siginfo_t* info, int options) RETURN_AND_SET_ERRNO_TEST_CANCEL(EINVAL); } - pid_t child = _kern_wait_for_child(id, options, info); + pid_t child = _kern_wait_for_child(id, options, info, NULL); if (child >= 0 || child == B_WOULD_BLOCK) return 0; diff --git a/src/tests/libs/bsd/wait4_test.cpp b/src/tests/libs/bsd/wait4_test.cpp index e5d761d034..46f261551a 100644 --- a/src/tests/libs/bsd/wait4_test.cpp +++ b/src/tests/libs/bsd/wait4_test.cpp @@ -5,6 +5,7 @@ #include +#include #include #include #include @@ -55,10 +56,14 @@ main(int argc, char** argv) struct rusage usage; pid_t pid; do { + memset(&usage, 0, sizeof(usage)); int childStatus = -1; pid = wait4(-1, &childStatus, 0, &usage); - printf("wait4() returned %ld (%s), child status %d\n", - pid, strerror(errno), childStatus); + printf("wait4() returned %" PRId32 " (%s), child status %" PRId32 + ", kernel: %ld.%06" PRId32 " user: %ld.%06" PRId32 "\n", + pid, strerror(errno), childStatus, usage.ru_stime.tv_sec, + usage.ru_stime.tv_usec, usage.ru_utime.tv_sec, + usage.ru_utime.tv_usec); } while (pid >= 0); return 0;