/*
* Copyright 2016, Rene Gollent, rene@gollent.com.
* Copyright 2016, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "LocalTargetHostInterface.h"
#include <set>
#include <stdio.h>
#include <unistd.h>
#include <image.h>
#include <AutoDeleter.h>
#include <AutoLocker.h>
#include <system_info.h>
#include <util/KMessage.h>
#include "debug_utils.h"
#include "CoreFile.h"
#include "CoreFileDebuggerInterface.h"
#include "LocalDebuggerInterface.h"
#include "TargetHost.h"
using std::set;
LocalTargetHostInterface::LocalTargetHostInterface()
:
TargetHostInterface(),
fTargetHost(NULL),
fDataPort(-1)
{
SetName("Local");
}
LocalTargetHostInterface::~LocalTargetHostInterface()
{
Close();
if (fTargetHost != NULL)
fTargetHost->ReleaseReference();
}
status_t
LocalTargetHostInterface::Init(Settings* settings)
{
char hostname[HOST_NAME_MAX + 1];
status_t error = gethostname(hostname, sizeof(hostname));
if (error != B_OK) {
fprintf(stderr, "gethostname() failed, defaults to localhost\n");
strlcpy(hostname, "localhost", sizeof(hostname));
}
fTargetHost = new(std::nothrow) TargetHost(hostname);
if (fTargetHost == NULL)
return B_NO_MEMORY;
team_info info;
error = get_team_info(B_CURRENT_TEAM, &info);
if (error != B_OK)
return error;
char buffer[128];
snprintf(buffer, sizeof(buffer), "LocalTargetHostInterface %" B_PRId32,
info.team);
fDataPort = create_port(100, buffer);
if (fDataPort < 0)
return fDataPort;
fPortWorker = spawn_thread(_PortLoop, "Local Target Host Loop",
B_NORMAL_PRIORITY, this);
if (fPortWorker < 0)
return fPortWorker;
resume_thread(fPortWorker);
AutoLocker<TargetHost> hostLocker(fTargetHost);
error = __start_watching_system(-1,
B_WATCH_SYSTEM_TEAM_CREATION | B_WATCH_SYSTEM_TEAM_DELETION,
fDataPort, 0);
if (error != B_OK)
return error;
int32 cookie = 0;
while (get_next_team_info(&cookie, &info) == B_OK) {
error = fTargetHost->AddTeam(info);
if (error != B_OK)
return error;
}
snprintf(buffer, sizeof(buffer), "Local (%s)", hostname);
SetName(buffer);
return B_OK;
}
void
LocalTargetHostInterface::Close()
{
if (fDataPort > 0) {
__stop_watching_system(-1,
B_WATCH_SYSTEM_TEAM_CREATION | B_WATCH_SYSTEM_TEAM_DELETION,
fDataPort, 0);
delete_port(fDataPort);
fDataPort = -1;
}
if (fPortWorker > 0) {
wait_for_thread(fPortWorker, NULL);
fPortWorker = -1;
}
}
bool
LocalTargetHostInterface::IsLocal() const
{
return true;
}
bool
LocalTargetHostInterface::Connected() const
{
return true;
}
TargetHost*
LocalTargetHostInterface::GetTargetHost()
{
return fTargetHost;
}
status_t
LocalTargetHostInterface::Attach(team_id teamID, thread_id threadID,
DebuggerInterface*& _interface) const
{
if (teamID < 0 && threadID < 0)
return B_BAD_VALUE;
status_t error;
if (teamID < 0) {
thread_info threadInfo;
error = get_thread_info(threadID, &threadInfo);
if (error != B_OK)
return error;
teamID = threadInfo.team;
}
LocalDebuggerInterface* interface
= new(std::nothrow) LocalDebuggerInterface(teamID);
if (interface == NULL)
return B_NO_MEMORY;
BReference<DebuggerInterface> interfaceReference(interface, true);
error = interface->Init();
if (error != B_OK)
return error;
_interface = interface;
interfaceReference.Detach();
return B_OK;
}
status_t
LocalTargetHostInterface::CreateTeam(int commandLineArgc,
const char* const* arguments, team_id& _teamID) const
{
thread_id thread = load_program(arguments, commandLineArgc, false);
if (thread < 0)
return thread;
// main thread ID == team ID.
_teamID = thread;
return B_OK;
}
status_t
LocalTargetHostInterface::LoadCore(const char* coreFilePath,
DebuggerInterface*& _interface, thread_id& _thread) const
{
// load the core file
CoreFile* coreFile = new(std::nothrow) CoreFile;
if (coreFile == NULL)
return B_NO_MEMORY;
ObjectDeleter<CoreFile> coreFileDeleter(coreFile);
status_t error = coreFile->Init(coreFilePath);
if (error != B_OK)
return error;
// create the debugger interface
CoreFileDebuggerInterface* interface
= new(std::nothrow) CoreFileDebuggerInterface(coreFile);
if (interface == NULL)
return B_NO_MEMORY;
coreFileDeleter.Detach();
BReference<DebuggerInterface> interfaceReference(interface, true);
error = interface->Init();
if (error != B_OK)
return error;
const CoreFileTeamInfo& teamInfo = coreFile->GetTeamInfo();
_thread = teamInfo.Id();
_interface = interface;
interfaceReference.Detach();
return B_OK;
}
status_t
LocalTargetHostInterface::FindTeamByThread(thread_id thread,
team_id& _teamID) const
{
thread_info info;
status_t error = get_thread_info(thread, &info);
if (error != B_OK)
return error;
_teamID = info.team;
return B_OK;
}
status_t
LocalTargetHostInterface::_PortLoop(void* arg)
{
LocalTargetHostInterface* interface = (LocalTargetHostInterface*)arg;
set<team_id> waitingTeams;
for (;;) {
status_t error;
bool addToWaiters;
char buffer[2048];
int32 messageCode;
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 == B_TIMED_OUT && !waitingTeams.empty()) {
for (set<team_id>::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)
continue;
if (message.What() != B_SYSTEM_OBJECT_UPDATE)
continue;
int32 opcode = 0;
if (message.FindInt32("opcode", &opcode) != B_OK)
continue;
team = -1;
if (message.FindInt32("team", &team) != B_OK)
continue;
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<TargetHost> 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;
}
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: fPortWorker.