... | ... | @@ -291,7 +291,7 @@ Par itself is implemented in terms of the `par#` primop, which the code generato |
|
|
Par doesn't actually create a new thread immediately; instead it places a pointer to its first argument in the *spark pool*. The spark pool is a circular buffer, when it is full we have the choice of either overwriting the oldest entry or dropping the new entry - currently we drop the new entry (see code for `newSpark`). Each capability has its own spark pool, so this operation can be performed without taking a lock.
|
|
|
|
|
|
|
|
|
So how does the spark turn into a thread? When the scheduler spots that the current capability has no runnable threads, it checks the spark pool, and if there is a valid spark (a spark that points to a THUNK), then the spark is turned into a real thread and placed on the run queue: see `createSparkThread` in [rts/Sparks.c](/trac/ghc/browser/ghc/rts/Sparks.c). Also, the scheduler attempts to share its available sparks with any other idle capabilities: see `schedulePushWork` in [rts/Scheduler.c](/trac/ghc/browser/ghc/rts/Scheduler.c).
|
|
|
So how does the spark turn into a thread? When the scheduler spots that the current capability has no runnable threads, it checks the spark pool, and if there is a valid spark (a spark that points to a THUNK), then the spark is turned into a real thread and placed on the run queue: see `createSparkThread` in [rts/Sparks.c](/trac/ghc/browser/ghc/rts/Sparks.c). Also, the scheduler attempts to share its available sparks with any other idle capabilities: see `schedulePushWork` in [rts/Schedule.c](/trac/ghc/browser/ghc/rts/Schedule.c).
|
|
|
|
|
|
## Affinity and migration
|
|
|
|
... | ... | |