wait4(): retrieve dead team entries usage information.
* This adds a parameter to the wait_for_child syscall. I extended the test case to show the actual retrieved information. * fix #13546
This commit is contained in:
parent
c80ec6a9fe
commit
a295d3f46e
@ -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);
|
||||
|
@ -116,6 +116,8 @@ struct job_control_entry : DoublyLinkedListLinkImpl<job_control_entry> {
|
||||
status_t status;
|
||||
uint16 reason; // reason for the team's demise, one of the
|
||||
// CLD_* values defined in <signal.h>
|
||||
bigtime_t user_time;
|
||||
bigtime_t kernel_time;
|
||||
|
||||
job_control_entry();
|
||||
~job_control_entry();
|
||||
|
@ -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);
|
||||
|
@ -12,6 +12,10 @@
|
||||
#include <sys/wait.h>
|
||||
|
||||
|
||||
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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/resource.h>
|
||||
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user