Skip to content
  • Simon Marlow's avatar
    Fix deadlock (#10545) · 111ba4be
    Simon Marlow authored
    yieldCapability() was not prepared to be called by a Task that is not
    either a worker or a bound Task.  This could happen if we ended up in
    yieldCapability via this call stack:
    
    performGC()
    scheduleDoGC()
    requestSync()
    yieldCapability()
    
    and there were a few other ways this could happen via requestSync.
    The fix is to handle this case in yieldCapability(): when the Task is
    not a worker or a bound Task, we put it on the returning_workers
    queue, where it will be woken up again.
    
    Summary of changes:
    
    * `yieldCapability`: factored out subroutine waitForWorkerCapability`
    * `waitForReturnCapability` renamed to `waitForCapability`, and
      factored out subroutine `waitForReturnCapability`
    * `releaseCapabilityAndQueue` worker renamed to `enqueueWorker`, does
      not take a lock and no longer tests if `!isBoundTask()`
    * `yieldCapability` adjusted for refactorings, only change in behavior
      is when it is not a worker or bound task.
    
    Test Plan:
    * new test concurrent/should_run/performGC
    * validate
    
    Reviewers: niteria, austin, ezyang, bgamari
    
    Subscribers: thomie, bgamari
    
    Differential Revision: https://phabricator.haskell.org/D997
    
    GHC Trac Issues: #10545
    111ba4be