Skip to content
Snippets Groups Projects
  • Nadav Har'El's avatar
    8ef7f248
    Fix concurrent static initialization · 8ef7f248
    Nadav Har'El authored
    
    When multiple threads concurrently use a function which has a static
    variable with a constructor, gcc guarantees that only one thread will run
    the constructor, and the other ones waits.  It uses __cxa_guard_acquire()/
    release()/abort() for implementing this guarantee. Unfortunately these
    functions, implemented in the C++ standard library, use the Linux futex
    syscall which we don't implement. The futex system call is only used in
    the rare case of contention - in the normal case, the __cxa_guard_*
    functions uses just atomic memory operations.
    
    This patch implements the bare minimum we need from futex to make the
    __cxa_guard_* functions work: All we need is FUTEX_WAIT and FUTEX_WAKE,
    with 0 timeout in FUTEX_WAIT and wake all in FUTEX_WAKE.
    
    It's nice how the new waitqueues fit this implementation like glove to
    a hand: We could use condvars too, but we anyway need to do the wake()
    with the mutex locked (to get the futex's atomic test-and-wait), and in
    that case we can use waitqueues without their additional internal mutex.
    
    This patch also adds a test for this bug. Catching this bug in a real
    application is very rare, but the test exposes it by defining an function-
    static object with a very slow constructor (it sleeps for a second), and
    calls the function from several threads concurrently.
    Before this patch the test fails with:
       constructing
       syscall(): unimplemented system call 202. Aborting.
    
    Fixes #199.
    
    Signed-off-by: default avatarNadav Har'El <nyh@cloudius-systems.com>
    Signed-off-by: default avatarPekka Enberg <penberg@cloudius-systems.com>
    8ef7f248
    History
    Fix concurrent static initialization
    Nadav Har'El authored
    
    When multiple threads concurrently use a function which has a static
    variable with a constructor, gcc guarantees that only one thread will run
    the constructor, and the other ones waits.  It uses __cxa_guard_acquire()/
    release()/abort() for implementing this guarantee. Unfortunately these
    functions, implemented in the C++ standard library, use the Linux futex
    syscall which we don't implement. The futex system call is only used in
    the rare case of contention - in the normal case, the __cxa_guard_*
    functions uses just atomic memory operations.
    
    This patch implements the bare minimum we need from futex to make the
    __cxa_guard_* functions work: All we need is FUTEX_WAIT and FUTEX_WAKE,
    with 0 timeout in FUTEX_WAIT and wake all in FUTEX_WAKE.
    
    It's nice how the new waitqueues fit this implementation like glove to
    a hand: We could use condvars too, but we anyway need to do the wake()
    with the mutex locked (to get the futex's atomic test-and-wait), and in
    that case we can use waitqueues without their additional internal mutex.
    
    This patch also adds a test for this bug. Catching this bug in a real
    application is very rare, but the test exposes it by defining an function-
    static object with a very slow constructor (it sleeps for a second), and
    calls the function from several threads concurrently.
    Before this patch the test fails with:
       constructing
       syscall(): unimplemented system call 202. Aborting.
    
    Fixes #199.
    
    Signed-off-by: default avatarNadav Har'El <nyh@cloudius-systems.com>
    Signed-off-by: default avatarPekka Enberg <penberg@cloudius-systems.com>