Skip to content

Commit e01f2b1

Browse files
committed
[lldb/Plugin] Sort the ScriptedProcess' thread list before creating threads
With Scripted Processes, in order to create scripted threads, the blueprint provides a dictionary that have each thread index as the key with the respective thread instance as the pair value. In Python, this is fine because a dictionary key can be of any type including integer types: ``` >>> {1: "one", 2: "two", 10: "ten"} {1: 'one', 2: 'two', 10: 'ten'} ``` However, when the python dictionary gets bridged to C++ we convert it to a `StructuredData::Dictionary` that uses a `std::map<ConstString, ObjectSP>` for storage. Because `std::map` is an ordered container and ours uses the `ConstString` type for keys, the thread indices gets converted to strings which makes the dictionary sorted alphabetically, instead of numerically. If the ScriptedProcess has 10 threads or more, it causes thread “10” (and higher) to be after thread “1”, but before thread “2”. In order to solve this, this sorts the thread info dictionary keys numerically, before iterating over them to create ScriptedThreads. rdar://90327854 Differential Revision: https://reviews.llvm.org/D122429 Signed-off-by: Med Ismail Bennani <[email protected]>
1 parent 0353a86 commit e01f2b1

File tree

1 file changed

+42
-23
lines changed

1 file changed

+42
-23
lines changed

lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -309,35 +309,55 @@ bool ScriptedProcess::DoUpdateThreadList(ThreadList &old_thread_list,
309309

310310
StructuredData::DictionarySP thread_info_sp = GetInterface().GetThreadsInfo();
311311

312-
// FIXME: Need to sort the dictionary otherwise the thread ids won't match the
313-
// thread indices.
314-
315312
if (!thread_info_sp)
316313
return ScriptedInterface::ErrorWithMessage<bool>(
317314
LLVM_PRETTY_FUNCTION,
318315
"Couldn't fetch thread list from Scripted Process.", error);
319316

317+
// Because `StructuredData::Dictionary` uses a `std::map<ConstString,
318+
// ObjectSP>` for storage, each item is sorted based on the key alphabetical
319+
// order. Since `GetThreadsInfo` provides thread indices as the key element,
320+
// thread info comes ordered alphabetically, instead of numerically, so we
321+
// need to sort the thread indices before creating thread.
322+
323+
StructuredData::ArraySP keys = thread_info_sp->GetKeys();
324+
325+
std::map<size_t, StructuredData::ObjectSP> sorted_threads;
326+
auto sort_keys = [&sorted_threads,
327+
&thread_info_sp](StructuredData::Object *item) -> bool {
328+
if (!item)
329+
return false;
330+
331+
llvm::StringRef key = item->GetStringValue();
332+
size_t idx = 0;
333+
334+
// Make sure the provided index is actually an integer
335+
if (!llvm::to_integer(key, idx))
336+
return false;
337+
338+
sorted_threads[idx] = thread_info_sp->GetValueForKey(key);
339+
return true;
340+
};
341+
342+
size_t thread_count = thread_info_sp->GetSize();
343+
344+
if (!keys->ForEach(sort_keys) || sorted_threads.size() != thread_count)
345+
// Might be worth showing the unsorted thread list instead of return early.
346+
return ScriptedInterface::ErrorWithMessage<bool>(
347+
LLVM_PRETTY_FUNCTION, "Couldn't sort thread list.", error);
348+
320349
auto create_scripted_thread =
321-
[this, &old_thread_list, &error,
322-
&new_thread_list](ConstString key, StructuredData::Object *val) -> bool {
323-
if (!val)
324-
return ScriptedInterface::ErrorWithMessage<bool>(
325-
LLVM_PRETTY_FUNCTION, "Invalid thread info object", error);
350+
[this, &error, &new_thread_list](
351+
const std::pair<size_t, StructuredData::ObjectSP> pair) -> bool {
352+
size_t idx = pair.first;
353+
StructuredData::ObjectSP object_sp = pair.second;
326354

327-
lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
328-
if (!llvm::to_integer(key.AsCString(), tid))
355+
if (!object_sp)
329356
return ScriptedInterface::ErrorWithMessage<bool>(
330-
LLVM_PRETTY_FUNCTION, "Invalid thread id", error);
331-
332-
if (ThreadSP thread_sp =
333-
old_thread_list.FindThreadByID(tid, false /*=can_update*/)) {
334-
// If the thread was already in the old_thread_list,
335-
// just add it back to the new_thread_list.
336-
new_thread_list.AddThread(thread_sp);
337-
return true;
338-
}
357+
LLVM_PRETTY_FUNCTION, "Invalid thread info object", error);
339358

340-
auto thread_or_error = ScriptedThread::Create(*this, val->GetAsGeneric());
359+
auto thread_or_error =
360+
ScriptedThread::Create(*this, object_sp->GetAsGeneric());
341361

342362
if (!thread_or_error)
343363
return ScriptedInterface::ErrorWithMessage<bool>(
@@ -350,8 +370,7 @@ bool ScriptedProcess::DoUpdateThreadList(ThreadList &old_thread_list,
350370
if (!reg_ctx_sp)
351371
return ScriptedInterface::ErrorWithMessage<bool>(
352372
LLVM_PRETTY_FUNCTION,
353-
llvm::Twine("Invalid Register Context for thread " +
354-
llvm::Twine(key.AsCString()))
373+
llvm::Twine("Invalid Register Context for thread " + llvm::Twine(idx))
355374
.str(),
356375
error);
357376

@@ -360,7 +379,7 @@ bool ScriptedProcess::DoUpdateThreadList(ThreadList &old_thread_list,
360379
return true;
361380
};
362381

363-
thread_info_sp->ForEach(create_scripted_thread);
382+
llvm::for_each(sorted_threads, create_scripted_thread);
364383

365384
return new_thread_list.GetSize(false) > 0;
366385
}

0 commit comments

Comments
 (0)