[GHC] #8684: hWaitForInput cannot be interrupted by async exceptions on unix

GHC ghc-devs at haskell.org
Sun Jan 7 00:16:35 UTC 2018


#8684: hWaitForInput cannot be interrupted by async exceptions on unix
-------------------------------------+-------------------------------------
        Reporter:  nh2               |                Owner:  (none)
            Type:  bug               |               Status:  new
        Priority:  normal            |            Milestone:
       Component:  Core Libraries    |              Version:  7.6.3
      Resolution:                    |             Keywords:
Operating System:  Unknown/Multiple  |         Architecture:
                                     |  Unknown/Multiple
 Type of failure:  None/Unknown      |            Test Case:
      Blocked By:  13497, 13525      |             Blocking:
 Related Tickets:  #12912, #13525    |  Differential Rev(s):  Phab:D42
       Wiki Page:                    |
-------------------------------------+-------------------------------------

Comment (by nh2):

 As part of the review of my patch in https://phabricator.haskell.org/D42,
 I have gathered some information of how the timer signal is implemented.
 Since that may be a useful by itself, I post it here. It is as of commit
 `a1950e6`, and, since not much of this has changed since the last release,
 also of GHC 8.2.

 # How the timer signal is implemented

 In general, the tick callbacks go like this to do context switching:

 {{{
 handle_tick()
   contextSwitchAllCapabilities()
     for all capabilities:
       contextSwitchCapability()
         stopCapability()
           cap->r.rHpLim = NULL; // makes the heap check fail
         also sets `cap->interrupt = 1;`
 }}}

 Methods used on the various platforms:

 {{{
 - POSIX (method selected in `posix/Itimer.c`)
   - Linux, threaded RTS            -> timer_create() if it exists,
 otherwise setitimer()
   - Linux, non-threaded, >= 2.6.25 -> pthread with timerfd
   - Linux, non-threaded, <  2.6.25 -> pthread without timerfd
   - Darwin                         -> pthread without timerfd
   - iOS                            -> pthread without timerfd
 - Windows (`win32/Ticker.c`)
   - Windows                        -> CreateTimerQueueTimer()
 }}}

 Notably the Darwin and iOS implementations use a pthread even for the non-
 threaded RTS!

 Relevant trac issues about the above methods:

 * #1933 - [https://ghc.haskell.org/trac/ghc/ticket/1933 Zero times in
 profiling with GHC-6.8.1] --
   This added autoconf-based detection of `timer_create()` on Linux.
 * #10840 - [https://ghc.haskell.org/trac/ghc/ticket/10840 Periodic alarm
 signals can cause a retry loop to get stuck] --
   This added the pthread-based implementations.

 Method implementation locations:

 {{{
 - pthread with timerfd                 -> `itimer/Pthread.c`
 - pthread without timerfd (sleep loop) -> `itimer/Pthread.c`
 - timer_create()                       -> `itimer/TimerCreate.c`
 - setitimer()                          -> `itimer/Setitimer.c`
 }}}

 How the implementations work:

 - pthread with timerfd
   - A pthread is started that runs a loop reading from the timerfd.
     No SIGVTALRM is used.
     When the timerfd ticks, that thread wakes up and calls handle_tick().
 - pthread without timerfd
   - A pthread is started that runs a loop running
 `sleep(itimer_interval)`.
     No SIGVTALRM is used.
     When that thread finishes the sleep, it calls handle_tick().
 - timer_create()
   - A SIGVTALRM signal handler is set up that `handle_tick()`.
     Then timer_create() is called to set up a SIGVTALRM signal occurring
 regularly,
     using the `ITIMER_REAL` real-time clock.
     The SIGVTALRM signal occurring will EINTR all system calls of all
 threads of the process.
 - `setitimer()`
   - A SIGVTALRM signal handler is set up that `handle_tick()`.
     Then `setitimer()` is called to set up a SIGVTALRM signal occurring
 regularly, using the `CLOCK_ID` clock, which is `CLOCK_MONOTONIC` if
 available and `CLOCK_REALTIME` otherwise.
     The SIGVTALRM signal occurring will EINTR all system calls of all
 threads of the process.
 - `CreateTimerQueueTimer()`
   - `CreateTimerQueueTimer()` is set up to call `tick_callback()` which
 calls `tick_proc = handle_tick()` regularly.
     The option `WT_EXECUTEINTIMERTHREAD` is passed which results in
 "callback function is invoked by the timer thread itself".
     There are a couple issues with it:
     1. The period is set to `TimeToUS(tick_interval) / 1000` milliseconds,
 which becomes 0 if less than a millisecond is chosen.
 `CreateTimerQueueTimer()` does not document what happens if a 0-period is
 given. It might busy-poll, but it's not documented, so who knows?
     2. A comment in the code remarks that this timer has a maximum
 accuracy of 15ms on Windows 7, and even worse on older platforms.

-- 
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/8684#comment:29>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list