[GHC] #13497: GHC does not use select()/poll() correctly on non-Linux platforms

GHC ghc-devs at haskell.org
Wed Mar 29 20:13:59 UTC 2017


#13497: GHC does not use select()/poll() correctly on non-Linux platforms
-------------------------------------+-------------------------------------
           Reporter:  nh2            |             Owner:  (none)
               Type:  bug            |            Status:  new
           Priority:  normal         |         Milestone:
          Component:  Runtime        |           Version:  8.0.1
  System                             |
           Keywords:                 |  Operating System:  Unknown/Multiple
       Architecture:                 |   Type of failure:  None/Unknown
  Unknown/Multiple                   |
          Test Case:                 |        Blocked By:
           Blocking:                 |   Related Tickets:  #8684, #12912
Differential Rev(s):                 |         Wiki Page:
-------------------------------------+-------------------------------------
 From my discovery at https://phabricator.haskell.org/D42#30542:

 {{{
 Why does the existing code work on platforms that are not Linux? In my
 select man page it says:

 On Linux, select() modifies timeout to reflect the amount of  time  not
 slept;  most  other implementations do not do this.  (POSIX.1-2001 per‐
 mits either behavior.)  This causes problems both when Linux code which
 reads  timeout  is  ported to other operating systems, and when code is
 ported to Linux that reuses a struct timeval for multiple select()s  in
 a  loop  without  reinitializing  it.  Consider timeout to be undefined
 after select() returns.

 The existing select loop seems to rely on the fact that &tv is updated as
 described here.
 }}}

 Same for `man 2 poll`.

 E.g. `man 2 select` on FreeBSD 11 says explicitly:

 {{{
 BUGS
      Version 2 of the Single UNIX Specification (``SUSv2'') allows systems
 to
      modify the original timeout in place.  Thus, it is unwise to assume
 that
      the timeout value will be unmodified by the select() system call.
      FreeBSD does not modify the return value, which can cause problems
 for
      applications ported from other systems.
 }}}

 I have tested this now on FreeBSD, and indeed it doesn't work as expected.

 With GHC 7.10.2:

 {{{
 import System.IO
 main = hWaitForInput stdin (1 * 1000)
 }}}

 `ghc --make test.hs -rtsopts`

 {{{
 [root@ ~]# time ./test

 real    0m1.386s
 user    0m0.004s
 sys     0m0.000s
 [root@ ~]# time ./test +RTS -V0.01

 real    0m1.386s
 user    0m0.001s
 sys     0m0.000s
 [root@ ~]# time ./test +RTS -V0.001

 real    0m1.678s
 user    0m0.003s
 sys     0m0.002s
 [root@ ~]# time ./test +RTS -V0.0001

 real    0m11.311s
 user    0m0.032s
 sys     0m0.139s
 }}}

 See how when we increase the timer signal, the sleep suddenly takes 10x
 longer than it should.

 That's because it triggers the case where EINTR is received in
 https://github.com/ghc/ghc/blob/f46369b8a1bf90a3bdc30f2b566c3a7e03672518%5E/libraries/base/cbits/inputReady.c#L48,
 letting us use the same unmodified 1-second `struct timeval *timeout`
 again and again.

 This demo of the bug works for GHC 7.10 and 8.0.1; in 8.0.2
 `hWaitForInput` is broken
 (https://ghc.haskell.org/trac/ghc/ticket/12912#comment:4) so the demo
 doesn't work there.

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


More information about the ghc-tickets mailing list