Changes between Version 17 and Version 18 of Commentary/Rts/Scheduler

May 20, 2010 9:58:15 AM (7 years ago)

update to new InCall story


  • Commentary/Rts/Scheduler

    v17 v18  
    6666Source files: [[GhcFile(rts/Task.h)]], [[GhcFile(rts/Task.c)]]
    68 A Task is a further layer of abstraction over an OS thread. 
    70 One Task is created for each ''call-in'' to the runtime.  When a
    71 call-in is made, a Task is allocated, a new Haskell thread is created,
    72 and the two are bound together for the duration of the call:
    73 {{{task->tso}}} points to the TSO, and {{{tso->bound}}} points to the
    74 Task.
    75 If a thread makes a call-in, followed by a call-out, and another call-in and so on, there could be a whole stack of tasks associated with a single OS thread.
    77 Additionally, there is one Task for each worker OS thread in the
    78 system.  A worker OS thread is used for executing the unbound Haskell
    79 threads.  {{{tso->bound}}} is {{{NULL}}} for a worker Task.
    81 The function
     68A Task is a further layer of abstraction over an OS thread.  One `Task` is created for each OS thread known to the runtime.  To get the `Task` associated with with the current OS thread, use the function `myTask`:
    8371  Task *myTask (void);
    85 returns the Task associated with the current OS thread.  However,
    86 there may be multiple Tasks associated with a particular OS thread,
    87 for example if a call-in executes some code that makes a foreign call,
    88 and that foreign call makes a further call-in, and so on.  If an OS
    89 thread has multiple Tasks associated with it, then {{{myTask}}}
    90 returns the topmost, or most recently created, one.  The {{{myTask}}}
    91 function is implemented using OS thread-local state.
     74The Task contains a mutex and a condition variable used when OS threads in the runtime need to synchronise with each other or sleep waiting for a condition to occur.  The `Task` also points to the `Capability` that the `Task` currently owns (`task->cap`), or `NULL` if the `Task` does not currently own a `Capability`.
    9376The important components of a Task are:
    9578 * The OS thread that owns this Task
    9679 * The ''Capability'' that this Task holds (see below)
    97  * The TSO that this Task is bound to, if any
     80 * The current `InCall` for this Task (see below)
    9881 * A condition variable on which this Task can put itself to sleep
    9982 * Some link fields for placing the Task on various queues
     84== InCalls ==
     86When an in-call is made, a Task is allocated (unless the current OS thread already has a Task), and an `InCall` structure is allocated for the call.  The `InCall` structure contains
     88 * a pointer to the `Task` that made the in-call
     89 * a pointer to the `TSO` that is executing the call
     90 * a slot to save the `TSO` in the event that this `TSO` needs to make a foreign call itself
     91 * a pointer to the previous `InCall`, if the current `Task` had already made an in-call followed by an out-call that lead to this in-call
     93Each task points to its current `InCall`.  A worker Task (i.e. one that was created by the RTS rather than externally) also has an `InCall` structure, but in that case `incall->tso` is NULL.
     95When a `TSO` makes a foreign call, the current `InCall` is placed on a queue attached to the `Capability`, `cap->suspended_ccalls`, from where the garbage collector can find the `TSO`s involved in foreign calls.  If one of these threads makes another in-call into Haskell, then another `InCall` is allocated, which points back to the original `InCall` via `incall->prev_stack`.  So we have a representation of the out-call/in-call stack for each `Task`, and we can restore the previous `InCall` when an in-call returns.
     97A task has a small cache of spare `InCall` structures so that it can allocate a fresh one quickly and without taking any locks; this is important for in-call performance.
    10199== Capabilities ==