mib created this revision.
mib added a reviewer: JDevlieghere.
mib added a project: LLDB.
mib requested review of this revision.
Herald added a subscriber: lldb-commits.
This patch adds support of multiple Scripted Threads in a ScriptedProcess.
This is done by fetch the Scripted Threads info dictionary at every
`ScriptedProcess::DoUpdateThreadList` and iterate over each element to
create a new ScriptedThread using the object instance, if it was not
already available.
This patch also update the test to make it multi-threaded.
rdar://84507704
Signed-off-by: Med Ismail Bennani <[email protected]>
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D117071
Files:
lldb/examples/python/scripted_process/scripted_process.py
lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
lldb/source/Plugins/Process/scripted/ScriptedThread.h
lldb/test/API/functionalities/scripted_process/Makefile
lldb/test/API/functionalities/scripted_process/main.c
lldb/test/API/functionalities/scripted_process/main.cpp
lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py
Index: lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py
===================================================================
--- lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py
+++ lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py
@@ -1,4 +1,4 @@
-import os,struct,signal
+import os,json,struct,signal
from typing import Any, Dict
@@ -21,6 +21,14 @@
idx = int(self.backing_target_idx.GetStringValue(100))
self.corefile_target = target.GetDebugger().GetTargetAtIndex(idx)
self.corefile_process = self.corefile_target.GetProcess()
+ for corefile_thread in self.corefile_process:
+ structured_data = lldb.SBStructuredData()
+ structured_data.SetFromJSON(json.dumps({
+ "backing_target_idx" : idx,
+ "thread_idx" : corefile_thread.GetIndexID()
+ }))
+
+ self.threads[corefile_thread.GetThreadID()] = StackCoreScriptedThread(self, structured_data)
def get_memory_region_containing_address(self, addr: int) -> lldb.SBMemoryRegionInfo:
mem_region = lldb.SBMemoryRegionInfo()
@@ -70,23 +78,43 @@
class StackCoreScriptedThread(ScriptedThread):
def __init__(self, process, args):
super().__init__(process, args)
- self.backing_target_idx = args.GetValueForKey("backing_target_idx")
+ backing_target_idx = args.GetValueForKey("backing_target_idx")
+ thread_idx = args.GetValueForKey("thread_idx")
+
+ def extract_value_from_structured_data(data, default_val):
+ if data and data.IsValid():
+ if data.GetType() == lldb.eStructuredDataTypeInteger:
+ return data.GetIntegerValue(default_val)
+ if data.GetType() == lldb.eStructuredDataTypeString:
+ return int(data.GetStringValue(100))
+ return None
+
+ #TODO: Change to Walrus operator (:=) with oneline if assignment
+ # Requires python 3.8
+ val = extract_value_from_structured_data(thread_idx, 0)
+ if val is not None:
+ self.idx = val
self.corefile_target = None
self.corefile_process = None
- if (self.backing_target_idx and self.backing_target_idx.IsValid()):
- if self.backing_target_idx.GetType() == lldb.eStructuredDataTypeInteger:
- idx = self.backing_target_idx.GetIntegerValue(42)
- if self.backing_target_idx.GetType() == lldb.eStructuredDataTypeString:
- idx = int(self.backing_target_idx.GetStringValue(100))
- self.corefile_target = self.target.GetDebugger().GetTargetAtIndex(idx)
+ self.corefile_thread = None
+
+ #TODO: Change to Walrus operator (:=) with oneline if assignment
+ # Requires python 3.8
+ val = extract_value_from_structured_data(backing_target_idx, 42)
+ if val is not None:
+ self.corefile_target = self.target.GetDebugger().GetTargetAtIndex(val)
self.corefile_process = self.corefile_target.GetProcess()
+ self.corefile_thread = self.corefile_process.GetThreadByIndexID(self.idx)
+
+ if self.corefile_thread:
+ self.id = self.corefile_thread.GetThreadID()
def get_thread_id(self) -> int:
- return 0x19
+ return self.id
def get_name(self) -> str:
- return StackCoreScriptedThread.__name__ + ".thread-1"
+ return StackCoreScriptedThread.__name__ + ".thread-" + str(self.id)
def get_stop_reason(self) -> Dict[str, Any]:
return { "type": lldb.eStopReasonSignal, "data": {
@@ -109,10 +137,9 @@
return self.frame_zero[0:0]
def get_register_context(self) -> str:
- thread = self.corefile_process.GetSelectedThread()
- if not thread or thread.GetNumFrames() == 0:
+ if not self.corefile_thread or self.corefile_thread.GetNumFrames() == 0:
return None
- frame = thread.GetFrameAtIndex(0)
+ frame = self.corefile_thread.GetFrameAtIndex(0)
GPRs = None
registerSet = frame.registers # Returns an SBValueList.
Index: lldb/test/API/functionalities/scripted_process/main.cpp
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/scripted_process/main.cpp
@@ -0,0 +1,34 @@
+#include <iostream>
+#include <mutex>
+#include <thread>
+
+int bar(int i) {
+ int j = i * i;
+ return j; // break here
+}
+
+int foo(int i) { return bar(i); }
+
+void call_and_wait(int &n) {
+ std::cout << "waiting for computation!" << std::endl;
+ while (n != 42 * 42)
+ ;
+ std::cout << "finished computation!" << std::endl;
+}
+
+void compute_pow(int &n) { n = foo(n); }
+
+int main() {
+ int n = 42;
+ std::mutex mutex;
+ std::unique_lock<std::mutex> lock(mutex);
+
+ std::thread thread_1(call_and_wait, std::ref(n));
+ std::thread thread_2(compute_pow, std::ref(n));
+ lock.unlock();
+
+ thread_1.join();
+ thread_2.join();
+
+ return 0;
+}
Index: lldb/test/API/functionalities/scripted_process/main.c
===================================================================
--- lldb/test/API/functionalities/scripted_process/main.c
+++ /dev/null
@@ -1,8 +0,0 @@
-int bar(int i) {
- int j = i * i;
- return j; // break here
-}
-
-int foo(int i) { return bar(i); }
-
-int main() { return foo(42); }
Index: lldb/test/API/functionalities/scripted_process/Makefile
===================================================================
--- lldb/test/API/functionalities/scripted_process/Makefile
+++ lldb/test/API/functionalities/scripted_process/Makefile
@@ -1,4 +1,4 @@
-C_SOURCES := main.c
-
+CXX_SOURCES := main.cpp
+ENABLE_THREADS := YES
include Makefile.rules
Index: lldb/source/Plugins/Process/scripted/ScriptedThread.h
===================================================================
--- lldb/source/Plugins/Process/scripted/ScriptedThread.h
+++ lldb/source/Plugins/Process/scripted/ScriptedThread.h
@@ -26,7 +26,9 @@
class ScriptedThread : public lldb_private::Thread {
public:
- ScriptedThread(ScriptedProcess &process, Status &error);
+ ScriptedThread(
+ ScriptedProcess &process, Status &error,
+ llvm::Optional<StructuredData::Generic> script_object = llvm::None);
~ScriptedThread() override;
@@ -61,7 +63,7 @@
const ScriptedProcess &m_scripted_process;
lldb::ScriptedThreadInterfaceSP m_scripted_thread_interface_sp = nullptr;
std::shared_ptr<DynamicRegisterInfo> m_register_info_sp = nullptr;
- lldb_private::StructuredData::Generic *m_script_object = nullptr;
+ llvm::Optional<StructuredData::Generic> m_script_object = llvm::None;
};
} // namespace lldb_private
Index: lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
===================================================================
--- lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
+++ lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
@@ -28,10 +28,13 @@
lldbassert(GetInterface() && "Invalid Scripted Thread Interface.");
}
-ScriptedThread::ScriptedThread(ScriptedProcess &process, Status &error)
+ScriptedThread::ScriptedThread(
+ ScriptedProcess &process, Status &error,
+ llvm::Optional<StructuredData::Generic> script_object)
: Thread(process, LLDB_INVALID_THREAD_ID), m_scripted_process(process),
m_scripted_thread_interface_sp(
- m_scripted_process.GetInterface().CreateScriptedThreadInterface()) {
+ m_scripted_process.GetInterface().CreateScriptedThreadInterface()),
+ m_script_object(script_object) {
if (!process.IsValid()) {
error.SetErrorString("Invalid scripted process");
return;
@@ -45,27 +48,33 @@
return;
}
- llvm::Optional<std::string> class_name =
- process.GetInterface().GetScriptedThreadPluginName();
- if (!class_name || class_name->empty()) {
- error.SetErrorString("Failed to get scripted thread class name.");
- return;
- }
-
- ExecutionContext exe_ctx(process);
-
- StructuredData::Generic *script_object =
- scripted_thread_interface->CreatePluginObject(
- class_name->c_str(), exe_ctx,
- process.m_scripted_process_info.GetArgsSP());
- if (!script_object || !script_object->IsValid()) {
- error.SetErrorString("Failed to create valid script object");
- return;
+ if (!script_object) {
+ llvm::Optional<std::string> class_name =
+ process.GetInterface().GetScriptedThreadPluginName();
+ if (!class_name || class_name->empty()) {
+ error.SetErrorString("Failed to get scripted thread class name.");
+ return;
+ }
+
+ ExecutionContext exe_ctx(process);
+
+ StructuredData::Generic *script_obj =
+ scripted_thread_interface->CreatePluginObject(
+ class_name->c_str(), exe_ctx,
+ process.m_scripted_process_info.GetArgsSP());
+ if (!script_obj || !script_obj->IsValid()) {
+ error.SetErrorString("Failed to create valid script object");
+ return;
+ }
+
+ m_script_object = *script_obj;
+
+ } else {
+ scripted_thread_interface->SetPluginObject(&*m_script_object);
}
- m_script_object = script_object;
-
- SetID(scripted_thread_interface->GetThreadID());
+ lldb::tid_t tid = scripted_thread_interface->GetThreadID();
+ SetID(tid);
}
ScriptedThread::~ScriptedThread() { DestroyThread(); }
Index: lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
===================================================================
--- lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
+++ lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
@@ -164,9 +164,6 @@
SetPrivateState(eStateStopped);
- UpdateThreadListIfNeeded();
- GetThreadList();
-
return {};
}
@@ -304,19 +301,55 @@
.str(),
error);
- lldb::ThreadSP thread_sp;
- thread_sp = std::make_shared<ScriptedThread>(*this, error);
-
- if (!thread_sp || error.Fail())
- return GetInterface().ErrorWithMessage<bool>(LLVM_PRETTY_FUNCTION,
- error.AsCString(), error);
+ StructuredData::DictionarySP thread_info_sp = GetInterface().GetThreadsInfo();
- RegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext();
- if (!reg_ctx_sp)
+ if (!thread_info_sp)
return GetInterface().ErrorWithMessage<bool>(
- LLVM_PRETTY_FUNCTION, "Invalid Register Context", error);
-
- new_thread_list.AddThread(thread_sp);
+ LLVM_PRETTY_FUNCTION,
+ "Couldn't fetch thread list from Scripted Process.", error);
+
+ auto create_scripted_thread =
+ [this, &old_thread_list, &error,
+ &new_thread_list](ConstString key, StructuredData::Object *val) -> bool {
+ if (!val)
+ return GetInterface().ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION, "Invalid thread info object", error);
+
+ lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
+ if (!llvm::to_integer(key.AsCString(), tid))
+ return GetInterface().ErrorWithMessage<bool>(LLVM_PRETTY_FUNCTION,
+ "Invalid thread id", error);
+
+ if (ThreadSP thread_sp =
+ old_thread_list.FindThreadByID(tid, false /*=can_update*/)) {
+ // If the thread was already in the old_thread_list,
+ // just add it back to the new_thread_list.
+ new_thread_list.AddThread(thread_sp);
+ return true;
+ }
+
+ lldb::ThreadSP thread_sp =
+ std::make_shared<ScriptedThread>(*this, error, *val->GetAsGeneric());
+
+ if (!thread_sp || error.Fail())
+ return GetInterface().ErrorWithMessage<bool>(LLVM_PRETTY_FUNCTION,
+ error.AsCString(), error);
+
+ RegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext();
+ if (!reg_ctx_sp)
+ return GetInterface().ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION,
+ llvm::Twine("Invalid Register Context for thread " +
+ llvm::Twine(key.AsCString()))
+ .str(),
+ error);
+
+ new_thread_list.AddThread(thread_sp);
+
+ return true;
+ };
+
+ thread_info_sp->ForEach(create_scripted_thread);
return new_thread_list.GetSize(false) > 0;
}
Index: lldb/examples/python/scripted_process/scripted_process.py
===================================================================
--- lldb/examples/python/scripted_process/scripted_process.py
+++ lldb/examples/python/scripted_process/scripted_process.py
@@ -70,7 +70,7 @@
tid (int): Thread ID to look for in the scripted process.
Returns:
- Dict: The thread represented as a dictionary, withr the
+ Dict: The thread represented as a dictionary, with the
tid thread ID. None if tid doesn't match any of the scripted
process threads.
"""
@@ -212,11 +212,12 @@
self.target = None
self.process = None
self.args = None
- if isinstance(process, lldb.SBProcess) and process.IsValid():
- self.process = process
- self.target = process.GetTarget()
+ if isinstance(process, ScriptedProcess):
+ self.target = process.target
+ self.process = self.target.GetProcess()
self.id = None
+ self.idx = None
self.name = None
self.queue = None
self.state = None
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits