This is an archive of the discontinued LLVM Phabricator instance.

Make sure SelectMostRelevantFrame happens only when returning to the user
ClosedPublic

Authored by jingham on Apr 20 2023, 5:25 PM.

Details

Summary

This is a user facing action, it is meant to focus the user's attention on
something other than the 0th frame when you stop somewhere where that's
helpful. For instance, stopping in pthread_kill after an assert will select
the assert frame.

This is not something you want to have happen internally in lldb, both
because internally you really don't want the selected frame changing out
from under you, and because the recognizers can do arbitrary work, and that
can cause deadlocks or other unexpected behavior.

However, it's not something that the current code does
explicitly after a stop has been delivered, it's expected to happen implicitly
as part of stopping. I changing this to call SMRF explicitly after a user
stop, but that got pretty ugly quickly.

So I added a bool to control whether to run this and audited all the current
uses to determine whether we're returning to the user or not.

This is currently a little ad hoc because there isn't a formal way to
determine why we're fetching events. It would certainly be cleaner to
pass around a "process control baton" that would hold the history of
who is currently running the target, and on whose behalf, so we know:
"we're stopping because we completed a user request", or "we're continuing
because we're running an expression for the user" vrs. "we're continuing
because we're running an expression to allocate memory for another expression",
etc.

But that's a much bigger project...

Diff Detail

Event Timeline

jingham created this revision.Apr 20 2023, 5:25 PM
Herald added a project: Restricted Project. · View Herald TranscriptApr 20 2023, 5:25 PM
jingham requested review of this revision.Apr 20 2023, 5:25 PM
Herald added a project: Restricted Project. · View Herald TranscriptApr 20 2023, 5:25 PM

I looked at all the call sites and they all seemed reasonable in terms of doing work on behalf of the user or not and selecting the most relevant frame respectively. My only concern is that we now have a bunch of places where we're passing a blind true or false. While it's pretty obvious in this patch, it won't be so obvious when you're reading the same code in the future, let alone when someone inevitably copy-pastes it. I can think of two easy ways to improve readability:

  1. Add an inline comment:
StackFrameSP frame_sp = GetSelectedFrame(/*select_most_relevant=*/false);
  1. Add an enum to Frame:
enum SelectMostRelevant : bool {
  SelectMostRelevantFrame = true,
  DoNoSelectMostRelevantFrame = false,
};
StackFrameSP frame_sp = GetSelectedFrame(SelectMostRelevantFrame);

This is a trick that @dexonsmith thought me a long time ago. I personally like it the best because it makes things very explicit without the hassle of having to actually treat the value like an enum.

I looked at all the call sites and they all seemed reasonable in terms of doing work on behalf of the user or not and selecting the most relevant frame respectively. My only concern is that we now have a bunch of places where we're passing a blind true or false. While it's pretty obvious in this patch, it won't be so obvious when you're reading the same code in the future, let alone when someone inevitably copy-pastes it. I can think of two easy ways to improve readability:

  1. Add an inline comment:
StackFrameSP frame_sp = GetSelectedFrame(/*select_most_relevant=*/false);
  1. Add an enum to Frame:
enum SelectMostRelevant : bool {
  SelectMostRelevantFrame = true,
  DoNoSelectMostRelevantFrame = false,
};
StackFrameSP frame_sp = GetSelectedFrame(SelectMostRelevantFrame);

This is a trick that @dexonsmith thought me a long time ago. I personally like it the best because it makes things very explicit without the hassle of having to actually treat the value like an enum.

Oh, that's cute, I'll try that.

mib added a comment.Apr 21 2023, 11:38 AM

It's unfortunate that we're not able to determine easily if the stop is public or not, so I guess this is the best we could do for now.

We could however greatly reduce the amount of changes in the patch by having select_most_relevant default to false (or the true either way). Then, to improve readability, we would only need to add an inline comment before the argument (GetSelectedFrame(/*select_most_relevant=*/true)) like Jonas suggested.

Other than that, this looks good to me :)

lldb/include/lldb/Target/Process.h
2171

typo I guess

mib added inline comments.Apr 21 2023, 11:39 AM
lldb/include/lldb/Target/StackFrameList.h
56

I'd suggested making select_most_relevant_frame = false by default.

lldb/include/lldb/Target/Thread.h
433

ditto

437–438

ditto

It's unfortunate that we're not able to determine easily if the stop is public or not, so I guess this is the best we could do for now.

We could however greatly reduce the amount of changes in the patch by having select_most_relevant default to false (or the true either way). Then, to improve readability, we would only need to add an inline comment before the argument (GetSelectedFrame(/*select_most_relevant=*/true)) like Jonas suggested.

Other than that, this looks good to me :)

I thought about that (it would have made my job easier) but I don't want to have a default argument. I want people to have to think about who they are returning this too, and if it had a default argument it would be too easy to add it somewhere w/o thinking.

jingham updated this revision to Diff 515908.Apr 21 2023, 2:05 PM

Adopted the "enum SelectMostRelevant" as Jonas suggested.

This revision is now accepted and ready to land.Apr 21 2023, 2:09 PM