kernel/debug: Report team/thread exit status
Add a field to `debug_[team/thread]_deleted` to report the exit status on the corresponding events. This is useful for debuggers like GDB expecting a return value when one of their inferiors quit. Also add a `usage` field to `debug_team_deleted` since this is another potentially useful piece of information exposed by the `waitpid` family of syscalls. Change-Id: Ieff7c31f56b1b9f8f709725d19050273b21f2504 Reviewed-on: https://review.haiku-os.org/c/haiku/+/7736 Tested-by: Commit checker robot <[email protected]> Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
7a5148b345
commit
9631ca7349
@@ -560,6 +560,8 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
debug_origin origin; // thread is < 0, team is the deleted team
|
debug_origin origin; // thread is < 0, team is the deleted team
|
||||||
// (asynchronous message)
|
// (asynchronous message)
|
||||||
|
status_t status; // the exit code of the team
|
||||||
|
team_usage_info usage; // the usage info of the team
|
||||||
} debug_team_deleted;
|
} debug_team_deleted;
|
||||||
|
|
||||||
// B_DEBUGGER_MESSAGE_TEAM_EXEC
|
// B_DEBUGGER_MESSAGE_TEAM_EXEC
|
||||||
@@ -580,6 +582,7 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
debug_origin origin; // the deleted thread (asynchronous message)
|
debug_origin origin; // the deleted thread (asynchronous message)
|
||||||
|
status_t status; // the exit code of the thread
|
||||||
} debug_thread_deleted;
|
} debug_thread_deleted;
|
||||||
|
|
||||||
// B_DEBUGGER_MESSAGE_IMAGE_CREATED
|
// B_DEBUGGER_MESSAGE_IMAGE_CREATED
|
||||||
|
|||||||
@@ -258,11 +258,12 @@ bool user_debug_handle_signal(int signal, struct sigaction *handler,
|
|||||||
siginfo_t *info, bool deadly);
|
siginfo_t *info, bool deadly);
|
||||||
void user_debug_stop_thread();
|
void user_debug_stop_thread();
|
||||||
void user_debug_team_created(team_id teamID);
|
void user_debug_team_created(team_id teamID);
|
||||||
void user_debug_team_deleted(team_id teamID, port_id debuggerPort);
|
void user_debug_team_deleted(team_id teamID, port_id debuggerPort, status_t status,
|
||||||
|
team_usage_info* usageInfo);
|
||||||
void user_debug_team_exec();
|
void user_debug_team_exec();
|
||||||
void user_debug_update_new_thread_flags(Thread* thread);
|
void user_debug_update_new_thread_flags(Thread* thread);
|
||||||
void user_debug_thread_created(thread_id threadID);
|
void user_debug_thread_created(thread_id threadID);
|
||||||
void user_debug_thread_deleted(team_id teamID, thread_id threadID);
|
void user_debug_thread_deleted(team_id teamID, thread_id threadID, status_t status);
|
||||||
void user_debug_thread_exiting(Thread* thread);
|
void user_debug_thread_exiting(Thread* thread);
|
||||||
void user_debug_image_created(const image_info *imageInfo);
|
void user_debug_image_created(const image_info *imageInfo);
|
||||||
void user_debug_image_deleted(const image_info *imageInfo);
|
void user_debug_image_deleted(const image_info *imageInfo);
|
||||||
|
|||||||
@@ -1000,7 +1000,8 @@ user_debug_team_created(team_id teamID)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
user_debug_team_deleted(team_id teamID, port_id debuggerPort)
|
user_debug_team_deleted(team_id teamID, port_id debuggerPort, status_t status,
|
||||||
|
team_usage_info* usageInfo)
|
||||||
{
|
{
|
||||||
if (debuggerPort >= 0) {
|
if (debuggerPort >= 0) {
|
||||||
TRACE(("user_debug_team_deleted(team: %" B_PRId32 ", debugger port: "
|
TRACE(("user_debug_team_deleted(team: %" B_PRId32 ", debugger port: "
|
||||||
@@ -1010,6 +1011,8 @@ user_debug_team_deleted(team_id teamID, port_id debuggerPort)
|
|||||||
message.origin.thread = -1;
|
message.origin.thread = -1;
|
||||||
message.origin.team = teamID;
|
message.origin.team = teamID;
|
||||||
message.origin.nub_port = -1;
|
message.origin.nub_port = -1;
|
||||||
|
message.status = status;
|
||||||
|
message.usage = *usageInfo;
|
||||||
write_port_etc(debuggerPort, B_DEBUGGER_MESSAGE_TEAM_DELETED, &message,
|
write_port_etc(debuggerPort, B_DEBUGGER_MESSAGE_TEAM_DELETED, &message,
|
||||||
sizeof(message), B_RELATIVE_TIMEOUT, 0);
|
sizeof(message), B_RELATIVE_TIMEOUT, 0);
|
||||||
}
|
}
|
||||||
@@ -1075,7 +1078,7 @@ user_debug_thread_created(thread_id threadID)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
user_debug_thread_deleted(team_id teamID, thread_id threadID)
|
user_debug_thread_deleted(team_id teamID, thread_id threadID, status_t status)
|
||||||
{
|
{
|
||||||
// Things are a bit complicated here, since this thread no longer belongs to
|
// Things are a bit complicated here, since this thread no longer belongs to
|
||||||
// the debugged team (but to the kernel). So we can't use debugger_write().
|
// the debugged team (but to the kernel). So we can't use debugger_write().
|
||||||
@@ -1121,6 +1124,7 @@ user_debug_thread_deleted(team_id teamID, thread_id threadID)
|
|||||||
message.origin.thread = threadID;
|
message.origin.thread = threadID;
|
||||||
message.origin.team = teamID;
|
message.origin.team = teamID;
|
||||||
message.origin.nub_port = -1;
|
message.origin.nub_port = -1;
|
||||||
|
message.status = status;
|
||||||
|
|
||||||
write_port_etc(debuggerPort, B_DEBUGGER_MESSAGE_THREAD_DELETED,
|
write_port_etc(debuggerPort, B_DEBUGGER_MESSAGE_THREAD_DELETED,
|
||||||
&message, sizeof(message), B_KILL_CAN_INTERRUPT, 0);
|
&message, sizeof(message), B_KILL_CAN_INTERRUPT, 0);
|
||||||
|
|||||||
@@ -3341,10 +3341,22 @@ team_delete_team(Team* team, port_id debuggerPort)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get team exit information
|
||||||
|
status_t exitStatus = team->exit.status;
|
||||||
|
|
||||||
teamLocker.Unlock();
|
teamLocker.Unlock();
|
||||||
|
|
||||||
sNotificationService.Notify(TEAM_REMOVED, team);
|
sNotificationService.Notify(TEAM_REMOVED, team);
|
||||||
|
|
||||||
|
// get team usage information
|
||||||
|
InterruptsSpinLocker timeLocker(team->time_lock);
|
||||||
|
|
||||||
|
team_usage_info usageInfo;
|
||||||
|
usageInfo.kernel_time = team->dead_threads_kernel_time;
|
||||||
|
usageInfo.user_time = team->dead_threads_user_time;
|
||||||
|
|
||||||
|
timeLocker.Unlock();
|
||||||
|
|
||||||
// free team resources
|
// free team resources
|
||||||
|
|
||||||
delete_user_mutex_context(team->user_mutex_context);
|
delete_user_mutex_context(team->user_mutex_context);
|
||||||
@@ -3356,7 +3368,7 @@ team_delete_team(Team* team, port_id debuggerPort)
|
|||||||
team->ReleaseReference();
|
team->ReleaseReference();
|
||||||
|
|
||||||
// notify the debugger, that the team is gone
|
// notify the debugger, that the team is gone
|
||||||
user_debug_team_deleted(teamID, debuggerPort);
|
user_debug_team_deleted(teamID, debuggerPort, exitStatus, &usageInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2306,7 +2306,7 @@ thread_exit(void)
|
|||||||
|
|
||||||
// notify the debugger
|
// notify the debugger
|
||||||
if (teamID != kernelTeam->id)
|
if (teamID != kernelTeam->id)
|
||||||
user_debug_thread_deleted(teamID, thread->id);
|
user_debug_thread_deleted(teamID, thread->id, thread->exit.status);
|
||||||
|
|
||||||
// enqueue in the undertaker list and reschedule for the last time
|
// enqueue in the undertaker list and reschedule for the last time
|
||||||
UndertakerEntry undertakerEntry(thread, teamID);
|
UndertakerEntry undertakerEntry(thread, teamID);
|
||||||
|
|||||||
Reference in New Issue
Block a user