base: Fix race in PollQueue and remove SIGALRM workaround
authorAndreas Sandberg <andreas@sandberg.pp.se>
Fri, 29 Nov 2013 13:36:10 +0000 (14:36 +0100)
committerAndreas Sandberg <andreas@sandberg.pp.se>
Fri, 29 Nov 2013 13:36:10 +0000 (14:36 +0100)
There is a race between enabling asynchronous IO for a file descriptor
and IO events happening on that descriptor. A SIGIO won't normally be
delivered if an event is pending when asynchronous IO is
enabled. Instead, the signal will be raised the next time there is an
event on the FD. This changeset simulates a SIGIO by setting the
async_io flag when setting up asynchronous IO for an FD. This causes
the main event loop to poll all file descriptors to check for pending
IO. As a consequence of this, the old SIGALRM hack should no longer be
needed and is therefore removed.

src/base/pollevent.cc
src/sim/async.cc
src/sim/async.hh
src/sim/init.cc
src/sim/simulate.cc

index 67e97f98f041fdd2c7774f3ef2569d908257750c..9ed6df4fe5d365754ae959b6073f1bf1e07a3dad 100644 (file)
@@ -214,4 +214,14 @@ PollQueue::setupAsyncIO(int fd, bool set)
 
     if (fcntl(fd, F_SETFL, flags) == -1)
         panic("Could not set up async IO");
+
+    // The file descriptor might already have events pending. We won't
+    // see them if they occurred before we set the FASYNC
+    // flag. Simulate a SIGIO to ensure that the FD will be polled in
+    // next iteration of the simulation loop. We could just poll it,
+    // but this is much simpler.
+    if (set) {
+        async_event = true;
+        async_io = true;
+    }
 }
index 1a8e499f78ca887edcea285d468aabbb4e7bb60c..8ed00372c3bd378c19a7ec4abb6138abdb69c5dc 100644 (file)
@@ -33,6 +33,5 @@ volatile bool async_statdump = false;
 volatile bool async_statreset = false;
 volatile bool async_exit = false;
 volatile bool async_io = false;
-volatile bool async_alarm = false;
 volatile bool async_exception = false;
 
index 6dd5b8a0d48e687109d7b81d29411d6cff2c52f9..67f686a5947dade63eb32d60c25adf968bd5807a 100644 (file)
 /// @name Asynchronous event flags.
 /// To avoid races, signal handlers simply set these flags, which are
 /// then checked in the main event loop.  Defined in main.cc.
-/// @note See the PollQueue object (in pollevent.hh) for the use of async_io and async_alarm.
 //@{
 extern volatile bool async_event;       ///< Some asynchronous event has happened.
 extern volatile bool async_statdump;    ///< Async request to dump stats.
 extern volatile bool async_statreset;   ///< Async request to reset stats.
 extern volatile bool async_exit;        ///< Async request to exit simulator.
 extern volatile bool async_io;          ///< Async I/O request (SIGIO).
-extern volatile bool async_alarm;       ///< Async alarm event (SIGALRM).
 extern volatile bool async_exception;   ///< Python exception.
 //@}
 
index 660fab62b53a639801adb96006720e489cc4fb96..63af2dd889b89eb4a4ff31acba919cd77b2fd435 100644 (file)
@@ -104,15 +104,6 @@ ioHandler(int sigtype)
     async_io = true;
 }
 
-// Handle SIGALRM
-static void
-alrmHandler(int sigtype)
-{
-    async_event = true;
-    async_alarm = true;
-    alarm(1);
-}
-
 static void
 installSignalHandler(int signal, void (*handler)(int sigtype))
 {
@@ -156,15 +147,6 @@ initSignals()
     // Install a SIGIO handler to handle asynchronous file IO. See the
     // PollQueue class.
     installSignalHandler(SIGIO, ioHandler);
-
-    // Setup an alarm handler that triggers every second. This
-    // triggers a PollQueue service just like a SIGIO. It is
-    // /probably/ used to work around a bug in the poll queue (likely
-    // a race between setting up a asynchronous IO and data becoming
-    // available), but its use isn't documented anywhere.
-    // TODO: Find out why this is needed and fix the original bug.
-    installSignalHandler(SIGALRM, alrmHandler);
-    alarm(1);
 }
 
 // The python library is totally messed up with respect to constness,
index 78695688af6da947d34b24a15589895f6547388f..407e2274e426761e56d270b3d917e7fcfbae87f4 100644 (file)
@@ -210,9 +210,8 @@ doSimLoop(EventQueue *eventq)
                 exitSimLoop("user interrupt received");
             }
 
-            if (async_io || async_alarm) {
+            if (async_io) {
                 async_io = false;
-                async_alarm = false;
                 pollQueue.service();
             }