]> granicus.if.org Git - strace/commitdiff
Make ERESTARTxyz messages more descriptive
authorDenys Vlasenko <dvlasenk@redhat.com>
Thu, 12 Jan 2012 10:26:34 +0000 (11:26 +0100)
committerDenys Vlasenko <dvlasenk@redhat.com>
Thu, 12 Jan 2012 10:26:34 +0000 (11:26 +0100)
There is widespread confusion about exact meaning
of ERESTARTxyz codes. Before this change, we were showing
all four of them the same: as "(To be restarted)".

This change prints better explanations for these codes,
and contains verbose comments which explain *why* we display
codes that way - or else someone confused
is bound to come later and mangle them again.
New messages are:

ERESTARTSYS (To be restarted if SA_RESTART is set)
ERESTARTNOINTR (To be restarted)
ERESTARTNOHAND (Interrupted by signal)
ERESTART_RESTARTBLOCK (Interrupted by signal)

* syscall.c (trace_syscall_exiting): Make ERESTARTxyz messages
more descriptive.

Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
syscall.c

index b103d3482e87776021da3a5d93f8071e491c9590..706ded40a1cb1452bbcabd114d05d00364717db8 100644 (file)
--- a/syscall.c
+++ b/syscall.c
@@ -2412,17 +2412,57 @@ trace_syscall_exiting(struct tcb *tcp)
        else if (!(sys_res & RVAL_NONE) && u_error) {
                switch (u_error) {
 #ifdef LINUX
+               /* Blocked signals do not interrupt any syscalls.
+                * In this case syscalls don't return ERESTARTfoo codes.
+                *
+                * Deadly signals set to SIG_DFL interrupt syscalls
+                * and kill the process regardless of which of the codes below
+                * is returned by the interrupted syscall.
+                * In some cases, kernel forces a kernel-generated deadly
+                * signal to be unblocked and set to SIG_DFL (and thus cause
+                * death) if it is blocked or SIG_IGNed: for example, SIGSEGV
+                * or SIGILL. (The alternative is to leave process spinning
+                * forever on the faulty instruction - not useful).
+                *
+                * SIG_IGNed signals and non-deadly signals set to SIG_DFL
+                * (for example, SIGCHLD, SIGWINCH) interrupt syscalls,
+                * but kernel will always restart them.
+                */
                case ERESTARTSYS:
-                       tprints("= ? ERESTARTSYS (To be restarted)");
+                       /* Most common type of signal-interrupted syscall exit code.
+                        * The system call will be restarted with the same arguments
+                        * if SA_RESTART is set; otherwise, it will fail with EINTR.
+                        */
+                       tprints("= ? ERESTARTSYS (To be restarted if SA_RESTART is set)");
                        break;
                case ERESTARTNOINTR:
+                       /* Rare. For example, fork() returns this if interrupted.
+                        * SA_RESTART is ignored (assumed set): the restart is unconditional.
+                        */
                        tprints("= ? ERESTARTNOINTR (To be restarted)");
                        break;
                case ERESTARTNOHAND:
-                       tprints("= ? ERESTARTNOHAND (To be restarted)");
+                       /* pause(), rt_sigsuspend() etc use this code.
+                        * SA_RESTART is ignored (assumed not set):
+                        * syscall won't restart (will return EINTR instead)
+                        * even after signal with SA_RESTART set.
+                        * However, after SIG_IGN or SIG_DFL signal it will.
+                        */
+                       tprints("= ? ERESTARTNOHAND (Interrupted by signal)");
                        break;
                case ERESTART_RESTARTBLOCK:
-                       tprints("= ? ERESTART_RESTARTBLOCK (To be restarted)");
+                       /* Syscalls like nanosleep(), poll() which can't be
+                        * restarted with their original arguments use this
+                        * code. Kernel will execute restart_syscall() instead,
+                        * which changes arguments before restarting syscall.
+                        * SA_RESTART is ignored (assumed not set) similarly
+                        * to ERESTARTNOHAND. (Kernel can't honor SA_RESTART
+                        * since restart data is saved in "restart block"
+                        * in task struct, and if signal handler uses a syscall
+                        * which in turn saves another such restart block,
+                        * old data is lost and restart becomes impossible)
+                        */
+                       tprints("= ? ERESTART_RESTARTBLOCK (Interrupted by signal)");
                        break;
 #endif /* LINUX */
                default: