Take notice of SA_RESTART flags on signals, so as to deal (at least
partially properly) with blocking system calls interrupted by signals.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@62 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/vg_scheduler.c b/vg_scheduler.c
index ecf4466..cb7d5a9 100644
--- a/vg_scheduler.c
+++ b/vg_scheduler.c
@@ -35,15 +35,24 @@
#include "valgrind.h" /* for VG_USERREQ__MAKE_NOACCESS and
VG_USERREQ__DO_LEAK_CHECK */
-/* BORKAGE as of 11 Apr 02
+/* BORKAGE/ISSUES as of 14 Apr 02
-Note! This implementation is so poor as to not be suitable for use by
-anyone at all!
+Note! This pthreads implementation is so poor as to not be
+suitable for use by anyone at all!
-- properly save scheduler private state in signal delivery frames.
+- Currently, when a signal is run, just the ThreadStatus.status fields
+ are saved in the signal frame, along with the CPU state. Question:
+ should I also save and restore:
+ ThreadStatus.joiner
+ ThreadStatus.waited_on_mid
+ ThreadStatus.awaken_at
+ ThreadStatus.retval
+ Currently unsure, and so am not doing so.
-- signals interrupting read/write and nanosleep, and take notice
- of SA_RESTART or not
+- Signals interrupting read/write and nanosleep: SA_RESTART settings.
+ Read/write correctly return with EINTR when SA_RESTART isn't
+ specified and they are interrupted by a signal. nanosleep just
+ pretends signals don't exist -- should be fixed.
- when a thread is done mark its stack as noaccess
@@ -1657,6 +1666,44 @@
}
+/* vthread tid is returning from a signal handler; modify its
+ stack/regs accordingly. */
+static
+void handle_signal_return ( ThreadId tid )
+{
+ Char msg_buf[100];
+ Bool restart_blocked_syscalls = VG_(signal_returns)(tid);
+
+ if (restart_blocked_syscalls)
+ /* Easy; we don't have to do anything. */
+ return;
+
+ if (vg_threads[tid].status == VgTs_WaitFD) {
+ vg_assert(vg_threads[tid].m_eax == __NR_read
+ || vg_threads[tid].m_eax == __NR_write);
+ /* read() or write() interrupted. Force a return with EINTR. */
+ vg_threads[tid].m_eax = -VKI_EINTR;
+ vg_threads[tid].status = VgTs_Runnable;
+ if (VG_(clo_trace_sched)) {
+ VG_(sprintf)(msg_buf,
+ "read() / write() interrupted by signal; return EINTR" );
+ print_sched_event(tid, msg_buf);
+ }
+ return;
+ }
+
+ if (vg_threads[tid].status == VgTs_WaitFD) {
+ vg_assert(vg_threads[tid].m_eax == __NR_nanosleep);
+ /* We interrupted a nanosleep(). The right thing to do is to
+ write the unused time to nanosleep's second param and return
+ EINTR, but I'm too lazy for that. */
+ return;
+ }
+
+ /* All other cases? Just return. */
+}
+
+
/* ---------------------------------------------------------------------
Handle non-trivial client requests.
------------------------------------------------------------------ */
@@ -1725,11 +1772,9 @@
vg_threads[tid].m_edx = VG_(handle_client_request) ( arg );
break;
- case VG_USERREQ__SIGNAL_RETURNS:
- /* vthread tid is returning from a signal handler;
- modify its stack/regs accordingly. */
- VG_(signal_returns)(tid);
- break;
+ case VG_USERREQ__SIGNAL_RETURNS:
+ handle_signal_return(tid);
+ break;
default:
VG_(printf)("panic'd on private request = 0x%x\n", arg[0] );