Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/inspector/domain_target.pdl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ experimental domain Target
SessionID sessionId
TargetInfo targetInfo
boolean waitingForDebugger
command getTargets
returns
array of TargetInfo targetInfos
command setAutoAttach
parameters
boolean autoAttach
Expand Down
2 changes: 2 additions & 0 deletions src/inspector/node_inspector.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
'src/inspector/network_inspector.h',
'src/inspector/network_agent.cc',
'src/inspector/network_agent.h',
'src/inspector/target_manager.cc',
'src/inspector/target_manager.h',
'src/inspector/target_agent.cc',
'src/inspector/target_agent.h',
'src/inspector/worker_inspector.cc',
Expand Down
38 changes: 24 additions & 14 deletions src/inspector/target_agent.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ namespace node {
namespace inspector {
namespace protocol {

std::unordered_map<int, std::shared_ptr<MainThreadHandle>>
TargetAgent::target_session_id_worker_map_ =
std::unordered_map<int, std::shared_ptr<MainThreadHandle>>();
int TargetAgent::next_session_id_ = 1;
class WorkerTargetDelegate : public WorkerDelegate {
public:
explicit WorkerTargetDelegate(std::shared_ptr<TargetAgent> target_agent)
Expand All @@ -32,13 +28,14 @@ std::unique_ptr<Target::TargetInfo> createTargetInfo(
const std::string_view target_id,
const std::string_view type,
const std::string_view title,
const std::string_view url) {
const std::string_view url,
bool attached = false) {
return Target::TargetInfo::create()
.setTargetId(std::string(target_id))
.setType(std::string(type))
.setTitle(std::string(title))
.setUrl(std::string(url))
.setAttached(false)
.setAttached(attached)
.setCanAccessOpener(true)
.build();
}
Expand All @@ -57,11 +54,11 @@ void TargetAgent::createAndAttachIfNecessary(

targetCreated(target_id, type, title, url);
bool attached = false;
if (auto_attach_) {
if (target_manager_->auto_attach()) {
attached = true;
attachedToTarget(worker, target_id, type, title, url);
}
targets_.push_back({target_id, type, title, url, worker, attached});
target_manager_->AddTarget(worker, target_id, type, title, url, attached);
}

void TargetAgent::listenWorker(std::weak_ptr<WorkerManager> worker_manager) {
Expand All @@ -87,12 +84,26 @@ void TargetAgent::targetCreated(const std::string_view target_id,
frontend_->targetCreated(createTargetInfo(target_id, type, title, url));
}

crdtp::DispatchResponse TargetAgent::getTargets(
std::unique_ptr<protocol::Array<Target::TargetInfo>>* out_targetInfos) {
auto target_infos = std::make_unique<protocol::Array<Target::TargetInfo>>();
for (const auto& target : target_manager_->GetTargetsSnapshot()) {
target_infos->push_back(createTargetInfo(target.target_id,
target.type,
target.title,
target.url,
target.attached));
}
*out_targetInfos = std::move(target_infos);
return DispatchResponse::Success();
}

int TargetAgent::getNextSessionId() {
return next_session_id_++;
return target_manager_->NextSessionId();
}

int TargetAgent::getNextTargetId() {
return next_target_id_++;
return target_manager_->NextTargetId();
}

void TargetAgent::attachedToTarget(std::shared_ptr<MainThreadHandle> worker,
Expand All @@ -101,7 +112,7 @@ void TargetAgent::attachedToTarget(std::shared_ptr<MainThreadHandle> worker,
const std::string& title,
const std::string& url) {
int session_id = getNextSessionId();
target_session_id_worker_map_[session_id] = worker;
TargetManager::RegisterSessionWorker(session_id, worker);
worker->SetTargetSessionId(session_id);
frontend_->attachedToTarget(std::to_string(session_id),
createTargetInfo(target_id, type, title, url),
Expand All @@ -112,11 +123,10 @@ void TargetAgent::attachedToTarget(std::shared_ptr<MainThreadHandle> worker,
// all threads. Modify it to be managed per worker thread.
crdtp::DispatchResponse TargetAgent::setAutoAttach(
bool auto_attach, bool wait_for_debugger_on_start) {
auto_attach_ = auto_attach;
wait_for_debugger_on_start_ = wait_for_debugger_on_start;
target_manager_->SetAutoAttach(auto_attach, wait_for_debugger_on_start);

if (auto_attach) {
for (auto& target : targets_) {
for (auto& target : target_manager_->targets()) {
if (!target.attached) {
target.attached = true;
attachedToTarget(target.worker,
Expand Down
30 changes: 7 additions & 23 deletions src/inspector/target_agent.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#ifndef SRC_INSPECTOR_TARGET_AGENT_H_
#define SRC_INSPECTOR_TARGET_AGENT_H_

#include <memory>
#include <string_view>
#include <unordered_map>
#include <vector>
#include "inspector/target_manager.h"
#include "inspector/worker_inspector.h"
#include "node/inspector/protocol/Target.h"

Expand All @@ -14,15 +14,6 @@ class TargetInspector;

namespace protocol {

struct TargetInfo {
std::string target_id;
std::string type;
std::string title;
std::string url;
std::shared_ptr<MainThreadHandle> worker;
bool attached;
};

class TargetAgent : public Target::Backend,
public std::enable_shared_from_this<TargetAgent> {
public:
Expand All @@ -32,15 +23,14 @@ class TargetAgent : public Target::Backend,
const std::string& title,
const std::string& url);

DispatchResponse getTargets(
std::unique_ptr<protocol::Array<Target::TargetInfo>>* out_targetInfos)
override;
DispatchResponse setAutoAttach(bool auto_attach,
bool wait_for_debugger_on_start) override;

void listenWorker(std::weak_ptr<WorkerManager> worker_manager);
void reset();
static std::unordered_map<int, std::shared_ptr<MainThreadHandle>>
target_session_id_worker_map_;

bool isThisThread(MainThreadHandle* worker) { return worker == main_thread_; }

private:
int getNextTargetId();
Expand All @@ -57,15 +47,9 @@ class TargetAgent : public Target::Backend,

std::shared_ptr<Target::Frontend> frontend_;
std::weak_ptr<WorkerManager> worker_manager_;
static int next_session_id_;
int next_target_id_ = 1;
std::unique_ptr<WorkerManagerEventHandle> worker_event_handle_ = nullptr;
bool auto_attach_ = false;
// TODO(islandryu): If false, implement it so that each thread does not wait
// for the worker to execute.
bool wait_for_debugger_on_start_ = true;
std::vector<TargetInfo> targets_;
MainThreadHandle* main_thread_;
std::unique_ptr<TargetManager> target_manager_ =
std::make_unique<TargetManager>();
};

} // namespace protocol
Expand Down
66 changes: 66 additions & 0 deletions src/inspector/target_manager.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#include "inspector/target_manager.h"

#include "inspector/main_thread_interface.h"

namespace node {
namespace inspector {

Mutex TargetManager::session_state_lock_;
std::unordered_map<int, std::shared_ptr<MainThreadHandle>>
TargetManager::session_worker_map_;
int TargetManager::next_session_id_ = 1;

int TargetManager::NextTargetId() {
return next_target_id_++;
}

int TargetManager::NextSessionId() {
Mutex::ScopedLock scoped_lock(session_state_lock_);
return next_session_id_++;
}

void TargetManager::SetAutoAttach(bool auto_attach,
bool wait_for_debugger_on_start) {
auto_attach_ = auto_attach;
wait_for_debugger_on_start_ = wait_for_debugger_on_start;
}

void TargetManager::AddTarget(std::shared_ptr<MainThreadHandle> worker,
const std::string& target_id,
const std::string& type,
const std::string& title,
const std::string& url,
bool attached) {
targets_.push_back({target_id, type, title, url, worker, attached});
}

std::vector<TargetManager::TargetInfo> TargetManager::GetTargetsSnapshot()
const {
std::vector<TargetInfo> result;
result.reserve(targets_.size());
for (const auto& target : targets_) {
if (target.worker && !target.worker->Expired()) {
result.push_back(target);
}
}
return result;
}

void TargetManager::RegisterSessionWorker(
int session_id, std::shared_ptr<MainThreadHandle> worker) {
Mutex::ScopedLock scoped_lock(session_state_lock_);
session_worker_map_[session_id] = std::move(worker);
}

std::shared_ptr<MainThreadHandle> TargetManager::WorkerForSession(
int session_id) {
Mutex::ScopedLock scoped_lock(session_state_lock_);
auto it = session_worker_map_.find(session_id);
if (it == session_worker_map_.end()) {
return nullptr;
}
return it->second;
}

} // namespace inspector
} // namespace node
70 changes: 70 additions & 0 deletions src/inspector/target_manager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#ifndef SRC_INSPECTOR_TARGET_MANAGER_H_
#define SRC_INSPECTOR_TARGET_MANAGER_H_

#include <memory>
#include <string>
#include <unordered_map>
#include <vector>

#include "node_mutex.h"

namespace node {
namespace inspector {

class MainThreadHandle;

class TargetManager {
public:
struct TargetInfo {
std::string target_id;
std::string type;
std::string title;
std::string url;
std::shared_ptr<MainThreadHandle> worker;
bool attached;
};

TargetManager() = default;

int NextTargetId();
int NextSessionId();

void SetAutoAttach(bool auto_attach, bool wait_for_debugger_on_start);
bool auto_attach() const { return auto_attach_; }
bool wait_for_debugger_on_start() const {
return wait_for_debugger_on_start_;
}

void AddTarget(std::shared_ptr<MainThreadHandle> worker,
const std::string& target_id,
const std::string& type,
const std::string& title,
const std::string& url,
bool attached);
std::vector<TargetInfo> GetTargetsSnapshot() const;
std::vector<TargetInfo>& targets() { return targets_; }
const std::vector<TargetInfo>& targets() const { return targets_; }

static void RegisterSessionWorker(int session_id,
std::shared_ptr<MainThreadHandle> worker);
static std::shared_ptr<MainThreadHandle> WorkerForSession(int session_id);

private:
static Mutex session_state_lock_;
static std::unordered_map<int, std::shared_ptr<MainThreadHandle>>
session_worker_map_;
static int next_session_id_;

int next_target_id_ = 1;
bool auto_attach_ = false;
// TODO(islandryu): Honor this flag for worker targets. It is stored here
// so Target.setAutoAttach() state can be tracked, but worker startup pause
// behavior does not change based on it yet.
bool wait_for_debugger_on_start_ = true;
std::vector<TargetInfo> targets_;
};

} // namespace inspector
} // namespace node

#endif // SRC_INSPECTOR_TARGET_MANAGER_H_
4 changes: 2 additions & 2 deletions src/inspector_io.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "inspector/node_json.h"
#include "inspector/node_string.h"
#include "inspector/target_agent.h"
#include "inspector/target_manager.h"
#include "inspector_socket_server.h"
#include "ncrypto.h"
#include "node.h"
Expand Down Expand Up @@ -380,8 +381,7 @@ void InspectorIoDelegate::MessageReceived(int session_id,
::isdigit);
if (is_number) {
int target_session_id = std::stoi(*target_session_id_str);
worker = protocol::TargetAgent::target_session_id_worker_map_
[target_session_id];
worker = TargetManager::WorkerForSession(target_session_id);
if (worker) {
merged_session_id += target_session_id << 16;
}
Expand Down
17 changes: 16 additions & 1 deletion test/parallel/test-inspector-worker-target.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
const common = require('../common');
const fixtures = require('../common/fixtures');

const assert = require('assert');

common.skipIfInspectorDisabled();

const { NodeInstance } = require('../common/inspector-helper.js');
Expand All @@ -21,6 +23,15 @@ async function setupInspector(session, sessionId = undefined) {
});
}

async function assertTargetAttachedState(session, targetId, attached) {
const { targetInfos } = await session.send({ method: 'Target.getTargets' });
const targetInfo = targetInfos.find((target) => {
return target.targetId === targetId;
});
assert.notStrictEqual(targetInfo, undefined);
assert.strictEqual(targetInfo.attached, attached);
}

async function test(isSetAutoAttachBeforeExecution) {
const child = new NodeInstance(['--inspect-brk=0', '--experimental-worker-inspection'],
'',
Expand All @@ -38,7 +49,10 @@ async function test(isSetAutoAttachBeforeExecution) {
await session.send({ method: 'Debugger.resume' });

const sessionId = '1';
await session.waitForNotification('Target.targetCreated');
const targetCreated = await session.waitForNotification('Target.targetCreated');
const targetId = targetCreated.params.targetInfo.targetId;

await assertTargetAttachedState(session, targetId, isSetAutoAttachBeforeExecution);

if (!isSetAutoAttachBeforeExecution) {
await session.send({ method: 'Target.setAutoAttach', params: { autoAttach: true, waitForDebuggerOnStart: true } });
Expand All @@ -47,6 +61,7 @@ async function test(isSetAutoAttachBeforeExecution) {
return notification.method === 'Target.attachedToTarget' &&
notification.params.sessionId === sessionId;
});
await assertTargetAttachedState(session, targetId, true);
await setupInspector(session, sessionId);
await session.waitForNotification('Debugger.paused');
await session.send({ method: 'Debugger.resume', sessionId });
Expand Down
Loading