summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <dvlasenk@redhat.com>2012-01-12 11:26:34 +0100
committerDenys Vlasenko <dvlasenk@redhat.com>2012-01-12 11:26:34 +0100
commitfe585656f8d0c6ac7298df22fce0d9ee0935e264 (patch)
tree85c3fa93ea2beed9d98e0286b491c8895e421deb
parent3cc943825e3aa0d3f2681be33164412113cab5ab (diff)
downloadstrace-fe585656f8d0c6ac7298df22fce0d9ee0935e264.tar.gz
Make ERESTARTxyz messages more descriptive
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>
-rw-r--r--syscall.c46
1 files changed, 43 insertions, 3 deletions
diff --git a/syscall.c b/syscall.c
index b103d3482..706ded40a 100644
--- 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: