Q: signals: UTRACE_SIGNAL_HANDLER, multitracing

Roland McGrath roland at redhat.com
Mon Aug 24 07:53:25 UTC 2009


> Why does utrace_signal_handler() set ->signal_handler when !stepping?
> 
> If I understand correctly, the logic is
> 
> 	if (stepping)
> 		make sure that before return to user-space
> 		UTRACE_SIGNAL_HANDLER will be reported.
> 
> 		This is understandable. More or less.
> 	else
> 		make sure that UTRACE_SIGNAL_REPORT is not
> 		possible before we return to user-space,
> 		UTRACE_SIGNAL_HANDLER should be used instead.
> 
> 		Why? I mean, why this is useful?

If you want to let a signal happen and then see the new user state before
letting user-mode run, then you'd:
	return UTRACE_SIGNAL_DELIVER|UTRACE_REPORT;
or:
	return UTRACE_SIGNAL_DELIVER|UTRACE_INTERRUPT;

IMHO this is the more natural way to express what you want than
UTRACE_SINGLESTEP.  It's also possible and kosher to do this on
a machine where UTRACE_SINGLESTEP is not supported.

The main reason that single-step has this behavior implicitly is for the
benefit of ptrace.  That is, the traditional behavior is to pretend there
was a SIGTRAP at handler setup when stepping, i.e. as if "deliver signal"
were an instruction and you'd just stepped over it to get to the first
instruction of the handler.

The UTRACE_SIGNAL_DELIVER logic for handled signals should already mean
that utrace->interrupt is forced even for UTRACE_REPORT.  So it might be
fine for utrace_signal_handler() to set ->signal_handler only if
->interrupt is already set.

So maybe this?  (I haven't committed this.)

Thanks,
Roland

diff --git a/kernel/utrace.c b/kernel/utrace.c
index 2e63a11..70d032f 100644
--- a/kernel/utrace.c
+++ b/kernel/utrace.c
@@ -2174,11 +2174,12 @@ int utrace_get_signal(struct task_struct *task, struct pt_regs *regs,
 }
 
 /*
- * This gets called after a signal handler has been set up.
- * We set a flag so the next report knows it happened.
- * If we're already stepping, make sure we do a report_signal.
- * If not, make sure we get into utrace_resume() where we can
- * clear the signal_handler flag before resuming.
+ * This gets called after a signal handler has been set up.  If someone
+ * wanted a UTRACE_SIGNAL_HANDLER report_signal in particular, then
+ * utrace->interrupt is already set and we set the signal_handler flag
+ * so the next report knows it happened.  If not, keep the flag clear so
+ * that we do not have to come back and reset it before resume just for
+ * bookkeeping purposes.
  */
 void utrace_signal_handler(struct task_struct *task, int stepping)
 {
@@ -2186,13 +2187,7 @@ void utrace_signal_handler(struct task_struct *task, int stepping)
 
 	spin_lock(&utrace->lock);
 
-	utrace->signal_handler = 1;
-	if (stepping) {
-		utrace->interrupt = 1;
-		set_tsk_thread_flag(task, TIF_SIGPENDING);
-	} else {
-		set_tsk_thread_flag(task, TIF_NOTIFY_RESUME);
-	}
+	utrace->signal_handler = utrace->interrupt;
 
 	spin_unlock(&utrace->lock);
 }




More information about the utrace-devel mailing list