Skip to content

Commit 3b81d2a

Browse files
hoxyqfacebook-github-bot
authored andcommitted
Define main entities (facebook#54334)
Summary: # Changelog: [Internal] This defines the main entities for the console.createTask(): - ConsoleTaskOrchestrator: global stack that can be used as a source of pending tasks. - ConsoleTaskContext: RAII object, captures the context for a specific task. Lifetime is bound to the lifetime of the task object in JavaScript. - ConsoleTask: RAII-like object. Initialized only during the callback run of `task.run(...)`. I couldn't find a better way to solve this without having a static singleton. Native modules don't have access to ReactInstance object, so we won't be able to access this global stack from `performance.measure` implementation, for example. Not using the word `async` anywhere in the naming, because the current implementation doesn't support async stack traces. Differential Revision: D85481864
1 parent 1787e93 commit 3b81d2a

File tree

6 files changed

+332
-0
lines changed

6 files changed

+332
-0
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#include "ConsoleTask.h"
9+
#include "ConsoleTaskOrchestrator.h"
10+
11+
namespace facebook::react::jsinspector_modern {
12+
13+
ConsoleTask::ConsoleTask(std::shared_ptr<ConsoleTaskContext> taskContext)
14+
: taskContext_(std::move(taskContext)),
15+
orchestrator_(ConsoleTaskOrchestrator::getInstance()) {
16+
if (taskContext_) {
17+
orchestrator_.startTask(taskContext_->id());
18+
}
19+
}
20+
21+
ConsoleTask::~ConsoleTask() {
22+
if (taskContext_) {
23+
orchestrator_.finishTask(taskContext_->id());
24+
}
25+
}
26+
27+
} // namespace facebook::react::jsinspector_modern
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#pragma once
9+
10+
#include <memory>
11+
12+
namespace facebook::react::jsinspector_modern {
13+
14+
class ConsoleTaskContext;
15+
class RuntimeTargetDelegate;
16+
class ConsoleTaskOrchestrator;
17+
18+
class ConsoleTask {
19+
public:
20+
/**
21+
* \param runtimeTargetDelegate The delegate to the corresponding runtime.
22+
* \param taskContext The context that tracks the task.
23+
*/
24+
explicit ConsoleTask(std::shared_ptr<ConsoleTaskContext> taskContext);
25+
~ConsoleTask();
26+
27+
ConsoleTask(const ConsoleTask &) = default;
28+
ConsoleTask &operator=(const ConsoleTask &) = delete;
29+
30+
ConsoleTask(ConsoleTask &&) = default;
31+
ConsoleTask &operator=(ConsoleTask &&) = delete;
32+
33+
private:
34+
std::shared_ptr<ConsoleTaskContext> taskContext_;
35+
ConsoleTaskOrchestrator &orchestrator_;
36+
};
37+
38+
} // namespace facebook::react::jsinspector_modern
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#include "ConsoleTaskContext.h"
9+
#include "ConsoleTaskOrchestrator.h"
10+
#include "RuntimeTarget.h"
11+
12+
namespace facebook::react::jsinspector_modern {
13+
14+
ConsoleTaskContext::ConsoleTaskContext(
15+
jsi::Runtime& runtime,
16+
RuntimeTargetDelegate& runtimeTargetDelegate,
17+
std::string name)
18+
: runtimeTargetDelegate_(runtimeTargetDelegate),
19+
name_(std::move(name)),
20+
orchestrator_(ConsoleTaskOrchestrator::getInstance()) {
21+
stackTrace_ = runtimeTargetDelegate_.captureStackTrace(runtime);
22+
}
23+
24+
ConsoleTaskContext::~ConsoleTaskContext() {
25+
orchestrator_.cancelTask(id());
26+
}
27+
28+
ConsoleTaskId ConsoleTaskContext::id() const {
29+
return ConsoleTaskId{(void*)this};
30+
}
31+
32+
std::optional<folly::dynamic> ConsoleTaskContext::getSerializedStackTrace()
33+
const {
34+
auto maybeValue = runtimeTargetDelegate_.serializeStackTrace(*stackTrace_);
35+
if (maybeValue) {
36+
maybeValue.value()["description"] = name_;
37+
}
38+
39+
return maybeValue;
40+
}
41+
42+
std::function<std::optional<folly::dynamic>()>
43+
ConsoleTaskContext::getSerializedStackTraceProvider() const {
44+
return [selfWeak = weak_from_this()]() -> std::optional<folly::dynamic> {
45+
if (auto self = selfWeak.lock()) {
46+
return self->getSerializedStackTrace();
47+
}
48+
49+
return std::nullopt;
50+
};
51+
}
52+
53+
void ConsoleTaskContext::schedule() {
54+
orchestrator_.scheduleTask(id(), weak_from_this());
55+
}
56+
57+
} // namespace facebook::react::jsinspector_modern
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#pragma once
9+
10+
#include "StackTrace.h"
11+
12+
#include <folly/dynamic.h>
13+
#include <jsi/jsi.h>
14+
15+
#include <cassert>
16+
#include <functional>
17+
#include <memory>
18+
#include <string>
19+
20+
namespace facebook::react::jsinspector_modern {
21+
22+
class ConsoleTaskOrchestrator;
23+
class RuntimeTargetDelegate;
24+
25+
class ConsoleTaskId {
26+
public:
27+
ConsoleTaskId() = default;
28+
~ConsoleTaskId() = default;
29+
30+
ConsoleTaskId(const ConsoleTaskId &) = default;
31+
ConsoleTaskId &operator=(const ConsoleTaskId &) = default;
32+
33+
ConsoleTaskId(ConsoleTaskId &&) = default;
34+
ConsoleTaskId &operator=(ConsoleTaskId &&) = default;
35+
36+
bool operator==(const ConsoleTaskId &) const = default;
37+
inline operator bool() const
38+
{
39+
return (bool)id_;
40+
}
41+
42+
explicit inline operator void *() const
43+
{
44+
return id_;
45+
}
46+
47+
private:
48+
explicit inline ConsoleTaskId(void *id) : id_(id)
49+
{
50+
assert(id_ != nullptr);
51+
}
52+
53+
void *id_{nullptr};
54+
55+
friend class ConsoleTaskContext;
56+
};
57+
58+
class ConsoleTaskContext : public std::enable_shared_from_this<ConsoleTaskContext> {
59+
public:
60+
ConsoleTaskContext(jsi::Runtime &runtime, RuntimeTargetDelegate &runtimeTargetDelegate, std::string name);
61+
~ConsoleTaskContext();
62+
63+
// Can't be moved or copied: the address of `ConsoleTaskContext` is used to
64+
// identify this task and all corresponding invocations.
65+
ConsoleTaskContext(const ConsoleTaskContext &) = delete;
66+
ConsoleTaskContext &operator=(const ConsoleTaskContext &) = delete;
67+
68+
ConsoleTaskContext(ConsoleTaskContext &&) = delete;
69+
ConsoleTaskContext &operator=(ConsoleTaskContext &&) = delete;
70+
71+
/**
72+
* Unique identifier that is calculated based on the address of
73+
* ConsoleTaskContext.
74+
*/
75+
ConsoleTaskId id() const;
76+
77+
/**
78+
* Returns the serialized stack trace that was captured during the allocation
79+
* of ConsoleTaskContext.
80+
*/
81+
std::optional<folly::dynamic> getSerializedStackTrace() const;
82+
83+
/**
84+
* Returns a function that returns the serialized stack trace, if available.
85+
*/
86+
std::function<std::optional<folly::dynamic>()> getSerializedStackTraceProvider() const;
87+
88+
void schedule();
89+
90+
private:
91+
RuntimeTargetDelegate &runtimeTargetDelegate_;
92+
std::string name_;
93+
ConsoleTaskOrchestrator &orchestrator_;
94+
std::unique_ptr<StackTrace> stackTrace_;
95+
};
96+
97+
} // namespace facebook::react::jsinspector_modern
98+
99+
namespace std {
100+
template <>
101+
struct hash<facebook::react::jsinspector_modern::ConsoleTaskId> {
102+
size_t operator()(const facebook::react::jsinspector_modern::ConsoleTaskId &id) const
103+
{
104+
return std::hash<void *>{}(static_cast<void *>(id));
105+
}
106+
};
107+
} // namespace std
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#include "ConsoleTaskOrchestrator.h"
9+
10+
namespace facebook::react::jsinspector_modern {
11+
12+
/* static */ ConsoleTaskOrchestrator& ConsoleTaskOrchestrator::getInstance() {
13+
static ConsoleTaskOrchestrator instance;
14+
return instance;
15+
}
16+
17+
void ConsoleTaskOrchestrator::scheduleTask(
18+
ConsoleTaskId taskId,
19+
std::weak_ptr<ConsoleTaskContext> taskContext) {
20+
std::lock_guard<std::mutex> lock(mutex_);
21+
tasks_.emplace(taskId, taskContext);
22+
}
23+
24+
void ConsoleTaskOrchestrator::cancelTask(ConsoleTaskId id) {
25+
std::lock_guard<std::mutex> lock(mutex_);
26+
tasks_.erase(id);
27+
}
28+
29+
void ConsoleTaskOrchestrator::startTask(ConsoleTaskId id) {
30+
std::lock_guard<std::mutex> lock(mutex_);
31+
stack_.push(id);
32+
}
33+
34+
void ConsoleTaskOrchestrator::finishTask(ConsoleTaskId id) {
35+
std::lock_guard<std::mutex> lock(mutex_);
36+
assert(stack_.top() == id);
37+
38+
stack_.pop();
39+
}
40+
41+
std::shared_ptr<ConsoleTaskContext> ConsoleTaskOrchestrator::top() const {
42+
std::lock_guard<std::mutex> lock(mutex_);
43+
if (stack_.empty()) {
44+
return nullptr;
45+
}
46+
47+
auto it = tasks_.find(stack_.top());
48+
if (it == tasks_.end()) {
49+
return nullptr;
50+
}
51+
52+
return it->second.lock();
53+
}
54+
55+
} // namespace facebook::react::jsinspector_modern
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#pragma once
9+
10+
#include <memory>
11+
#include <mutex>
12+
#include <stack>
13+
14+
#include "ConsoleTaskContext.h"
15+
16+
namespace facebook::react::jsinspector_modern {
17+
18+
class ConsoleTaskOrchestrator {
19+
public:
20+
static ConsoleTaskOrchestrator &getInstance();
21+
22+
~ConsoleTaskOrchestrator() = default;
23+
24+
ConsoleTaskOrchestrator(const ConsoleTaskOrchestrator &) = delete;
25+
ConsoleTaskOrchestrator &operator=(const ConsoleTaskOrchestrator &) = delete;
26+
27+
ConsoleTaskOrchestrator(ConsoleTaskOrchestrator &&) = delete;
28+
ConsoleTaskOrchestrator &operator=(ConsoleTaskOrchestrator &&) = delete;
29+
30+
void scheduleTask(ConsoleTaskId taskId, std::weak_ptr<ConsoleTaskContext> taskContext);
31+
void cancelTask(ConsoleTaskId taskId);
32+
33+
void startTask(ConsoleTaskId taskId);
34+
void finishTask(ConsoleTaskId taskId);
35+
std::shared_ptr<ConsoleTaskContext> top() const;
36+
37+
private:
38+
ConsoleTaskOrchestrator() = default;
39+
40+
std::stack<ConsoleTaskId> stack_;
41+
std::unordered_map<ConsoleTaskId, std::weak_ptr<ConsoleTaskContext>> tasks_;
42+
/**
43+
* Protects the stack_ and tasks_ members.
44+
*/
45+
mutable std::mutex mutex_;
46+
};
47+
48+
} // namespace facebook::react::jsinspector_modern

0 commit comments

Comments
 (0)