Skip to content

[lldb] Add support for Task names #10684

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
May 19, 2025

Conversation

kastiglione
Copy link

@kastiglione kastiglione commented May 14, 2025

This updates both OperatingSystemSwiftTasks and Task_SummaryProvider to include a
Task's name, if available. See SE-0469 for the introduction of task names.

The result is that threads representing Swift Tasks will show the given name, and when
printing a task, its name will be shown in the summary string.

rdar://146940592

This updates both `OperatingSystemSwiftTasks` and `Task_SummaryProvider` to include a
Task's name, if available. See [SE-0469][] for the introduction of task names.

The result is that threads representing Swift Tasks will show the given name, and when
printing a task, its name will be shown in the summary string.

[SE-0469]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0469-task-names.md
@kastiglione kastiglione requested a review from a team as a code owner May 14, 2025 21:44
@kastiglione
Copy link
Author

@swift-ci test

return {};
}

TaskStatusRecord getParent(Status &status) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For future-proofing you could convert these functions to Expected like so:

llvm::Expected<TaskStatusRecord> getParent() {
     addr_t parent = LLDB_INVALID_ADDRESS;
     Status status;
     if (*this)
       parent = process->ReadPointerFromMemory(addr + ParentOffset, status);
     if (Status.Fail())
       return Status.takeError();
     return {process, parent};
   }

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because these functions perform a number of Read* calls to process, I kept Status as the means of communicating errors. It makes the code more concise while still having the error handling/control. After the set of Reads (a logical transaction of sorts) have been completed (or failure occurred), the Status is then converted to Expected. This pattern I used elsewhere in support of inspection of other concurrency types.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll leave a comment describing this.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I must admit that this pattern also gave me a hard time convincing me everything was correct. Especially reading something like if (getKind(status) != Kind::TaskName), it reads like we're extracting the kind from the status


}; // namespace

llvm::Expected<std::optional<std::string>> GetTaskName(lldb::addr_t task_addr,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the optional add anything over just using an empty string for "success, but no name"?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My testing shows that I can provide the empty string as a task name, which should be distinguished from no task name.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To elaborate, using std::optional<std::string> allows both a task name of the empty string (which lldb should show), and a task not having a name.

OperatingSystemSwiftTasks::FindTaskName(addr_t task_addr, Process *process) {
auto task_name_or_err = GetTaskName(task_addr, process);
if (auto err = task_name_or_err.takeError()) {
LLDB_LOG_ERROR(GetLog(LLDBLog::OS), std::move(err),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of returning optional and logging the error, you can return Expected and return llvm::createStringError(...). And let the call site do logging or error reporting.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or actually, here just return task_name_or_err

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah I guess the entire function becomes pointless then :-)


/// Find the (optional) name of the Task at the given address, if any.
std::optional<std::string> FindTaskName(lldb::addr_t task_addr,
Process *process);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method doesn't need to me a member, it can be declared and defined inside the cpp file

/// Find the Task ID of the task being executed by `thread`, if any.
std::optional<uint64_t> FindTaskId(Thread &thread);
/// Find the address of the Task being executed by `thread`, if any.
std::optional<lldb::addr_t> FindTaskAddress(Thread &thread);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method doesn't need to be a member

if (task_name)
name = llvm::formatv("{0} (Task {1})", *task_name, task_id);
else
name = llvm::formatv("Task {0}", task_id);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar comment here: let's strive to always initialize at the declaration. A ternary operator should work fine here, and if this ever becomes more complicated we move it to a helper function

Copy link
Author

@kastiglione kastiglione May 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case I see a ternary as worse readability. As written above, I consider the initialization to be clearly one of two ways. I'm not aware of any standard conventions or strong arguments that code should be bent to ensure variables are always initialized.

Copy link

@felipepiovezan felipepiovezan May 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I strongly disagree, but won't insist in the interest of timeliness. But please ponder how would you implement this in a language that does not allow for uninitialized variables? (swift, rust, zig, all the modern ones, and why do they make that choice)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Swift does not allow uninitialized variables, but does permit separate declaration and initialization:

var name: String
if whatever {
    name = oneName()
} else {
    name = anotherName()
}

@kastiglione
Copy link
Author

@swift-ci test

…hange UpdateThreadList to handle task failures more granularly
@kastiglione
Copy link
Author

@swift-ci test

@kastiglione
Copy link
Author

@swift-ci test

@kastiglione
Copy link
Author

@swift-ci test

@kastiglione
Copy link
Author

@swift-ci test

Copy link

@felipepiovezan felipepiovezan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! I think there is still one function that was forgotten in this version, but we can address it afterwards

@kastiglione
Copy link
Author

@swift-ci test

@kastiglione
Copy link
Author

Thanks, I updated that function.

@kastiglione
Copy link
Author

@swift-ci test

@adrian-prantl
Copy link

@swift-ci test

@kastiglione
Copy link
Author

@swift-ci test macOS

@kastiglione
Copy link
Author

@swift-ci test windows

@kastiglione
Copy link
Author

@swift-ci test macOS

@adrian-prantl adrian-prantl merged commit 262cfab into swift/release/6.2 May 19, 2025
3 checks passed
@adrian-prantl adrian-prantl deleted the dl/lldb-Add-support-for-Task-names branch May 19, 2025 15:43
kastiglione added a commit that referenced this pull request May 20, 2025
* [lldb] Add support for Task names

This updates both `OperatingSystemSwiftTasks` and `Task_SummaryProvider` to include a
Task's name, if available. See [SE-0469][] for the introduction of task names.

The result is that threads representing Swift Tasks will show the given name, and when
printing a task, its name will be shown in the summary string.

[SE-0469]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0469-task-names.md

* Add tests

* Add docstrings; Switch to process reference; Make functions static; Change UpdateThreadList to handle task failures more granularly

* Another switch from pointer to reference; Use GetAddressByteSize

* Support 32 bit in TaskStatusRecord

* Fix bug in handling of non-Task threads

* Change int type of TaskStatusRecord offsets

* Make FindTaskId static

* Refactor test to (hopefully) work on Linux

* Disable test_thread_contains_name on Linux
(cherry-picked from commit 262cfab)
kastiglione added a commit that referenced this pull request May 20, 2025
* [lldb] Add support for Task names

This updates both `OperatingSystemSwiftTasks` and `Task_SummaryProvider` to include a
Task's name, if available. See [SE-0469][] for the introduction of task names.

The result is that threads representing Swift Tasks will show the given name, and when
printing a task, its name will be shown in the summary string.

[SE-0469]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0469-task-names.md

* Add tests

* Add docstrings; Switch to process reference; Make functions static; Change UpdateThreadList to handle task failures more granularly

* Another switch from pointer to reference; Use GetAddressByteSize

* Support 32 bit in TaskStatusRecord

* Fix bug in handling of non-Task threads

* Change int type of TaskStatusRecord offsets

* Make FindTaskId static

* Refactor test to (hopefully) work on Linux

* Disable test_thread_contains_name on Linux
(cherry-picked from commit 262cfab)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants