resume from another engine results in loss of singlestep req.
Oleg Nesterov
oleg at redhat.com
Wed Aug 12 10:36:44 UTC 2009
On 08/11, Roland McGrath wrote:
>
> I think this might be the right fix. First, we change the order so that
> UTRACE_INTERRUPT prevails over UTRACE_REPORT. (I'm really not sure why I
> ever had it the other way around.)
and this is consistent with the behaviour utrace_resume() which does nothing
if utrace->interrupt == T, it just returns and relies on utrace_get_signal().
But I wonder if this always correct, please see below.
> Next, we keep track of not only whether
> one engine wanted a report when another wanted stop, but of the prevailing
> resume action (i.e. least value still > UTRACE_STOP). After stopping and
> resuming, we apply UTRACE_INTERRUPT or UTRACE_REPORT as needed to make sure
> we get the kind of resume report we need.
Agreed, this looks like a right change to me. In any case I think this makes
the code more understandable and logical, and ->resume_action is much better
than ->reports imho.
But, you seem to forget to fix other callers of utrace_stop(),
utrace_report_syscall_entry
utrace_finish_vfork
utrace_report_exit
they all do utrace_stop(false), and with this change this "false" means
UTRACE_STOP.
> @@ -1298,14 +1305,14 @@ static void finish_report(struct utrace_
> {
> bool clean = (report->takers && !report->detaches);
>
> - if (report->action <= UTRACE_REPORT && !utrace->report) {
> - spin_lock(&utrace->lock);
> - utrace->report = 1;
> - set_tsk_thread_flag(task, TIF_NOTIFY_RESUME);
> - } else if (report->action == UTRACE_INTERRUPT && !utrace->interrupt) {
> + if (report->action == UTRACE_INTERRUPT && !utrace->interrupt) {
> spin_lock(&utrace->lock);
> utrace->interrupt = 1;
> set_tsk_thread_flag(task, TIF_SIGPENDING);
> + } else if (report->action <= UTRACE_REPORT && !utrace->report) {
> + spin_lock(&utrace->lock);
> + utrace->report = 1;
> + set_tsk_thread_flag(task, TIF_NOTIFY_RESUME);
Can't we (well, partly) miss UTRACE_STOP request?
Two engines A and B. Say, utrace_report_exec() calls ->report_exec().
A returns UTRACE_STOP, B returns UTRACE_INTERRUPT.
->resume_action = UTRACE_INTERRUPT, finish_report() sets ->interrupt = 1,
utrace_report_exec() returns.
Now. We can't rely on utrace_resume()->finish_resume_report() which can
notice the stop request and do utrace_stop() to actually stop. This is
delayed until utrace_get_signal()->finish_resume_report(), and I am not
sure this is what we really want:
- minor, but it is possible that tracehook_notify_jctl() will
be called before tracehook_get_signal(). Not a real problem,
but shouldn't UTRACE_STOP mean "stop as soon as possible" ?
- utrace_get_signal() can return without finish_resume_report()
if B->report_signal() (say) returns UTRACE_SIGNAL_DELIVER.
Yes, in this case A->report_signal() can return UTRACE_STOP
again, this means utrace_get_signal() returns with ->report = T.
But another UTRACE_INTERRUPT can set ->interrupt, this can
"disable" ->report again, and so on.
In short: unless I missed something, it is hardly possible to predict when
the tracee will actually stop, perhaps UTRACE_STOP needs more respect?
Oleg.
More information about the utrace-devel
mailing list