Q: jctl-stop && utrace_wakeup()

Roland McGrath roland at redhat.com
Tue Jul 28 00:17:20 UTC 2009


> utrace_wakeup:
> 
> 	if (likely(task_is_stopped_or_traced(target))) {
> 		if (target->signal->flags & SIGNAL_STOP_STOPPED)
> 			target->state = TASK_STOPPED;
> 		else
> 			wake_up_state(target, __TASK_STOPPED | __TASK_TRACED);
> 	}

Looks like it should look at group_stop_count too.

> Let's forget about ptrace for the moment.

Gladly! ;-)

> The code above means that utrace can't wake up the tracee if it was
> group-stopped. This looks reasonable, but in that case I don't understand
> what should we do if ->report_signal() returns UTRACE_SIGNAL_STOP. I mean,
> the attached engine can stop the tracee but can't wake it up?

I'm not sure I follow the question.  UTRACE_SIGNAL_STOP means to act like a
normal SIGSTOP signal, i.e. initiate a group-stop (with group_exit_code set
to info->si_signo).  You do that when you are passing on a real stop signal
you decided not to intercept, or if you want to simulate a signal.  That
results in a normal job stop, unrelated to UTRACE_STOP.  If you want it to
wake up from that, you send it a SIGCONT.

If report_signal returns UTRACE_SIGNAL_STOP | UTRACE_STOP, that (as always)
means "do this signal action, then go into utrace-stop".  The signal action
is the group stop, so with today's code you go into TASK_STOPPED as normal,
but engine_wants_stop() is set so it will go into utrace_stop() when it
resumes.

With the new plan of always using TASK_TRACED for UTRACE_STOP, then
UTRACE_SIGNAL_STOP|UTRACE_STOP should do the group-stop bookkeeping/notify
and then go into TASK_TRACED.  i.e., as if it had finished processing the
stop signal and then you called utrace_control(,,UTRACE_STOP).

> However, utrace_wakeup() is not right. It only checks SIGNAL_STOP_STOPPED,
> but doesn't check ->group_stop_count. But, otoh, we need no checks here,
> utrace_wakeup() can just do wake_up_state(__TASK_TRACED) and nothing more
> (remember, I am ignoring ptrace issues).

For new the plan it needs to change back to TASK_STOPPED when appropriate.

> but ptrace_resume() is different, it should wake up the tracee, that is
> why it does:

But I've already forgotten about ptrace! :-)

> 		if (task_is_stopped(child)) {
> 			spin_lock_irq(&child->sighand->siglock);
> 			child->signal->flags &= ~SIGNAL_STOP_STOPPED;
> 			spin_unlock_irq(&child->sighand->siglock);
> 		}

All this is bug-compatibility with traditional ptrace where it uses
wake_up_process() unconditionally without regard to all the bookkeeping.
But utrace never ignores the proper bookkeeping, so we further confuse
things trying to get the traditional userland-visible results.

Probably the right thing to will be to fix the upstream ptrace semantics
and figure out any userland issues with that, and then we won't have any
kludge like this for utrace-based ptrace.

> and this code is wrong again: what if check ->group_stop_count != 0?
> In that case SIGNAL_STOP_STOPPED can be set later, when utrace_wakeup()
> is called.

Its kinds of "wrong" only have to be no worse than wake_up_process(),
which is many kinds of wrong, so this has been a hazy area.

> What can we do? I don't see any solution.

Let's iron out what we think are intelligent and proper semantics at the
utrace level, and then we can revisit the ptrace oddities later.  It has
never played very well with job control, so some changes are probably in
order to achieve anything sane enough to be specified precisely.


Thanks,
Roland




More information about the utrace-devel mailing list