This appeared to be a manifestation of the bug fixed by this commit. Version with the bug can (three threads required for minimum reproduction) unsubscribe all threads waiting for static initialization to complete from the “wakeup call”, so the thread which triggers the initialization does not wake others up when done.
FSM of cxa_guard_acquire has four possible states:
- uninitialized
- initializing
- initializing + waiting
- initialized
The first thread that hits the local static variable switches the machine to "initializing", subsequent threads hitting it before the initialization is completed are switching it to "initializing + waiting" and blocking on a futex. Upon the initialization is completed the initializing thread wakes up everyone blocked on the futex if the state was "initializing + waiting" at the end of the initialization. A bug can cause "initializing + waiting to be reset back to "initializing".