[commit: ghc] master: rts: Close livelock window due to rapid ticker enable/disable (16a51a6)

git at git.haskell.org git at git.haskell.org
Sun May 1 21:56:20 UTC 2016


Repository : ssh://git@git.haskell.org/ghc

On branch  : master
Link       : http://ghc.haskell.org/trac/ghc/changeset/16a51a6c2f265f8670355be03d42b773d93e0684/ghc

>---------------------------------------------------------------

commit 16a51a6c2f265f8670355be03d42b773d93e0684
Author: Ben Gamari <bgamari.foss at gmail.com>
Date:   Sun May 1 13:38:38 2016 +0200

    rts: Close livelock window due to rapid ticker enable/disable
    
    This fixes #11830, where the RTS would livelock if run with `-I0` due
    to a regression introduced by bbdc52f3a6e6a28e209fb8f65699121d4ef3a4e3.
    The reason for this is that the new codepath introduced a subtle race
    condition:
    
     1. one thread could request that the ticker stop and would block until
        the ticker in fact stopped
     2. meanwhile, another thread could sneak in and restart the ticker
    
    this was implemented in such a way where thread (1) would end up
    blocked forever. The solution here is to simply not block. The worst
    that will happen is that timer fires again, but is ignored since the
    ticker is stopped.
    
    Test Plan:
    Validate, try reproduction case in #11830. Need to find a nice
    testcase.
    
    Reviewers: simonmar, erikd, hsyl20, austin
    
    Reviewed By: erikd, hsyl20
    
    Subscribers: erikd, thomie
    
    Differential Revision: https://phabricator.haskell.org/D2129
    
    GHC Trac Issues: #11830


>---------------------------------------------------------------

16a51a6c2f265f8670355be03d42b773d93e0684
 rts/posix/Itimer.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/rts/posix/Itimer.c b/rts/posix/Itimer.c
index 8915446..770ff20 100644
--- a/rts/posix/Itimer.c
+++ b/rts/posix/Itimer.c
@@ -177,6 +177,7 @@ static void install_vtalrm_handler(TickProc handle_tick)
 #if defined(USE_PTHREAD_FOR_ITIMER)
 enum ItimerState {STOPPED, RUNNING, STOPPING, EXITED};
 static volatile enum ItimerState itimer_state = STOPPED;
+
 static void *itimer_thread_func(void *_handle_tick)
 {
     TickProc handle_tick = _handle_tick;
@@ -189,7 +190,7 @@ static void *itimer_thread_func(void *_handle_tick)
     it.it_value.tv_nsec = TimeToNS(itimer_interval) % 1000000000;
     it.it_interval = it.it_value;
 
-    timerfd = timerfd_create(CLOCK_MONOTONIC,TFD_CLOEXEC);
+    timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
     if (timerfd == -1) {
         sysErrorBelch("timerfd_create");
         stg_exit(EXIT_FAILURE);
@@ -197,7 +198,7 @@ static void *itimer_thread_func(void *_handle_tick)
     if (!TFD_CLOEXEC) {
       fcntl(timerfd, F_SETFD, FD_CLOEXEC);
     }
-    timerfd_settime(timerfd,0,&it,NULL);
+    int ret = timerfd_settime(timerfd, 0, &it, NULL);
 #endif
 
     while (1) {
@@ -270,6 +271,11 @@ void
 startTicker(void)
 {
 #if defined(USE_PTHREAD_FOR_ITIMER)
+    // sanity check
+    if (itimer_state == EXITED) {
+        sysErrorBelch("ITimer: Tried to start a dead timer!\n");
+        stg_exit(EXIT_FAILURE);
+    }
     itimer_state = RUNNING;
 #elif defined(USE_TIMER_CREATE)
     {
@@ -306,10 +312,8 @@ stopTicker(void)
 #if defined(USE_PTHREAD_FOR_ITIMER)
     if (itimer_state == RUNNING) {
         itimer_state = STOPPING;
-        /* Wait for the thread to confirm it won't generate another tick. */
-        write_barrier();
-        while (itimer_state != STOPPED)
-            sched_yield();
+        // Note that the timer may fire once more, but that's okay;
+        // handle_tick is only called when itimer_state == RUNNING
     }
 #elif defined(USE_TIMER_CREATE)
     struct itimerspec it;



More information about the ghc-commits mailing list