Skip to content
Snippets Groups Projects
  • Florian Fischer's avatar
    82cf159a
    handle UnboundedBlockingMpscQueue spurious wake-ups · 82cf159a
    Florian Fischer authored
    A spurious wake-up can be produced by the new UnblockOnMainActorTest which
    triggers the assert(!mpscQueue.empty()) in UnboundedBlockingMpscQueue::get.
    
    Those spurious wake-ups are possible because the push and wake-up pair in
    UnboundedBlockingMpscQueue::put are not atomic.
    The following sequence diagram demonstrates a spurious wake-up:
    
       T1          T2            Q
       .           .            { }
      put(e)       .            { }
     push 54-57    .            {e}
       .         get()          {e}
       .        consume e       { }
       .           .            { }
       .         get()          { }
       .         block          { }
     unblock       .            { }
       .           .            { }
       .         wakeup         { }
       .           .            { }
                   X
           assert(!queue.Empty())
    
    To deal with spurious wake-ups we recheck the wake-up condition (a non empty queue)
    and block again if we find it empty.
    We assume spurious wake-ups are rare because it was difficult to reproduce them
    even with a dedicated Test (the new UnblockOnMainActorTest) therefore we declare
    the empty queue branch as unlikely.
    
    Fixes #4.
    82cf159a
    History
    handle UnboundedBlockingMpscQueue spurious wake-ups
    Florian Fischer authored
    A spurious wake-up can be produced by the new UnblockOnMainActorTest which
    triggers the assert(!mpscQueue.empty()) in UnboundedBlockingMpscQueue::get.
    
    Those spurious wake-ups are possible because the push and wake-up pair in
    UnboundedBlockingMpscQueue::put are not atomic.
    The following sequence diagram demonstrates a spurious wake-up:
    
       T1          T2            Q
       .           .            { }
      put(e)       .            { }
     push 54-57    .            {e}
       .         get()          {e}
       .        consume e       { }
       .           .            { }
       .         get()          { }
       .         block          { }
     unblock       .            { }
       .           .            { }
       .         wakeup         { }
       .           .            { }
                   X
           assert(!queue.Empty())
    
    To deal with spurious wake-ups we recheck the wake-up condition (a non empty queue)
    and block again if we find it empty.
    We assume spurious wake-ups are rare because it was difficult to reproduce them
    even with a dedicated Test (the new UnblockOnMainActorTest) therefore we declare
    the empty queue branch as unlikely.
    
    Fixes #4.