From 475ea59b5fe44946c2ab5bea9737b26b5267d425 Mon Sep 17 00:00:00 2001 From: Rene Gollent Date: Mon, 4 Apr 2016 21:58:12 -0400 Subject: [PATCH] Debugger: Fix handling of team creation events. LocalTargetHostInterface: - When receiving team creation events, check if the team in question actually contains a valid app image. The kernel's create notification is sent before the team is completely initialized, and consequently if our get_team_info() call gets in quickly enough, the images may not be loaded yet. If this situation is detected, add the team ID to a wait list. - If we have waiting teams, listen for new messages with a short timeout. If no message is received within the timeout, walk our list of waiting teams and see if they are fully initialized yet, and if so, dispatch the appropriate event. --- .../interfaces/LocalTargetHostInterface.cpp | 129 +++++++++++++----- .../interfaces/LocalTargetHostInterface.h | 4 +- 2 files changed, 99 insertions(+), 34 deletions(-) diff --git a/src/apps/debugger/target_host_interface/interfaces/LocalTargetHostInterface.cpp b/src/apps/debugger/target_host_interface/interfaces/LocalTargetHostInterface.cpp index 532106ced3..ef3957e46e 100644 --- a/src/apps/debugger/target_host_interface/interfaces/LocalTargetHostInterface.cpp +++ b/src/apps/debugger/target_host_interface/interfaces/LocalTargetHostInterface.cpp @@ -5,6 +5,8 @@ #include "LocalTargetHostInterface.h" +#include + #include #include @@ -14,6 +16,7 @@ #include "TargetHost.h" +using std::set; LocalTargetHostInterface::LocalTargetHostInterface() : @@ -59,7 +62,7 @@ LocalTargetHostInterface::Init() if (fDataPort < 0) return fDataPort; - fPortWorker = spawn_thread(PortLoop, "Local Target Host Loop", + fPortWorker = spawn_thread(_PortLoop, "Local Target Host Loop", B_NORMAL_PRIORITY, this); if (fPortWorker < 0) return fPortWorker; @@ -135,24 +138,46 @@ LocalTargetHostInterface::CreateTeam(int commandLineArgc, status_t -LocalTargetHostInterface::PortLoop(void* arg) +LocalTargetHostInterface::_PortLoop(void* arg) { LocalTargetHostInterface* interface = (LocalTargetHostInterface*)arg; + set waitingTeams; for (;;) { + status_t error; + bool addToWaiters; char buffer[2048]; int32 messageCode; - ssize_t size = read_port(interface->fDataPort, &messageCode, buffer, - sizeof(buffer)); + team_id team; + + ssize_t size = read_port_etc(interface->fDataPort, &messageCode, + buffer, sizeof(buffer), B_TIMEOUT, waitingTeams.empty() + ? B_INFINITE_TIMEOUT : 20000); if (size == B_INTERRUPTED) continue; - else if (size < 0) + else if (size == B_TIMED_OUT && !waitingTeams.empty()) { + for (set::iterator it = waitingTeams.begin(); + it != waitingTeams.end(); ++it) { + team = *it; + error = interface->_HandleTeamEvent(team, + B_TEAM_CREATED, addToWaiters); + if (error != B_OK) + continue; + else if (!addToWaiters) { + waitingTeams.erase(it); + if (waitingTeams.empty()) + break; + it = waitingTeams.begin(); + } + } + continue; + } else if (size < 0) return size; KMessage message; size = message.SetTo(buffer); if (size != B_OK) - return size; + continue; if (message.What() != B_SYSTEM_OBJECT_UPDATE) continue; @@ -161,39 +186,77 @@ LocalTargetHostInterface::PortLoop(void* arg) if (message.FindInt32("opcode", &opcode) != B_OK) continue; - team_id team = -1; + team = -1; if (message.FindInt32("team", &team) != B_OK) continue; - AutoLocker locker(interface->fTargetHost); - switch (opcode) { - case B_TEAM_CREATED: - case B_TEAM_EXEC: - { - team_info info; - status_t error = get_team_info(team, &info); - if (error != B_OK) - continue; - - if (opcode == B_TEAM_CREATED) - interface->fTargetHost->AddTeam(info); - else - interface->fTargetHost->UpdateTeam(info); - break; - } - - case B_TEAM_DELETED: - { - interface->fTargetHost->RemoveTeam(team); - break; - } - - default: - { - break; + error = interface->_HandleTeamEvent(team, opcode, + addToWaiters); + if (error != B_OK) + continue; + if (opcode == B_TEAM_CREATED && addToWaiters) { + try { + waitingTeams.insert(team); + } catch (...) { + continue; } } } return B_OK; } + + +status_t +LocalTargetHostInterface::_HandleTeamEvent(team_id team, int32 opcode, + bool& addToWaiters) +{ + addToWaiters = false; + AutoLocker locker(fTargetHost); + switch (opcode) { + case B_TEAM_CREATED: + case B_TEAM_EXEC: + { + team_info info; + status_t error = get_team_info(team, &info); + // this team is already gone, no point in sending a notification + if (error == B_BAD_TEAM_ID) + return B_OK; + else if (error != B_OK) + return error; + else { + int32 cookie = 0; + image_info imageInfo; + addToWaiters = true; + while (get_next_image_info(team, &cookie, &imageInfo) + == B_OK) { + if (imageInfo.type == B_APP_IMAGE) { + addToWaiters = false; + break; + } + } + if (addToWaiters) + return B_OK; + } + + if (opcode == B_TEAM_CREATED) + fTargetHost->AddTeam(info); + else + fTargetHost->UpdateTeam(info); + break; + } + + case B_TEAM_DELETED: + { + fTargetHost->RemoveTeam(team); + break; + } + + default: + { + break; + } + } + + return B_OK; +} diff --git a/src/apps/debugger/target_host_interface/interfaces/LocalTargetHostInterface.h b/src/apps/debugger/target_host_interface/interfaces/LocalTargetHostInterface.h index d5f10f3d6d..972355ee28 100644 --- a/src/apps/debugger/target_host_interface/interfaces/LocalTargetHostInterface.h +++ b/src/apps/debugger/target_host_interface/interfaces/LocalTargetHostInterface.h @@ -30,7 +30,9 @@ public: DebuggerInterface*& _interface); private: - static status_t PortLoop(void* arg); + static status_t _PortLoop(void* arg); + status_t _HandleTeamEvent(team_id team, int32 opcode, + bool& addToWaiters); private: TargetHost* fTargetHost;