[project @ 2002-02-13 08:48:06 by sof]
authorsof <unknown>
Wed, 13 Feb 2002 08:48:07 +0000 (08:48 +0000)
committersof <unknown>
Wed, 13 Feb 2002 08:48:07 +0000 (08:48 +0000)
commite289780ec23a1934f39d214d60705f8f26d1763d
tree2e8bc9206843ea60002c6cf628cbe02c759d739a
parent3470e75bd62fa08f86da2607a58c7f0b4aeba9db
[project @ 2002-02-13 08:48:06 by sof]
Revised implementation of multi-threaded callouts (and callins):

- unified synchronisation story for threaded and SMP builds,
  following up on SimonM's suggestion. The following synchro
  variables are now used inside the Scheduler:

    + thread_ready_cond - condition variable that is signalled
      when a H. thread has become runnable (via the THREAD_RUNNABLE()
      macro) and there are available capabilities. Waited on:
         + upon schedule() entry (iff no caps. available).
 + when a thread inside of the Scheduler spots that there
   are no runnable threads to service, but one or more
   external call is in progress.
 + in resumeThread(), waiting for a capability to become
   available.

      Prior to waiting on thread_ready_cond, a counter rts_n_waiting_tasks
      is incremented, so that we can keep track of the number of
      readily available worker threads (need this in order to make
      an informed decision on whether or not to create a new thread
      when an external call is made).

    + returning_worker_cond - condition variable that is waited
      on by an OS thread that has finished executing and external
      call & now want to feed its result back to the H thread
      that made the call. Before doing so, the counter
      rts_n_returning_workers is incremented.

      Upon entry to the Scheduler, this counter is checked for &
      if it is non-zero, the thread gives up its capability and
      signals returning_worker_cond before trying to re-grab a
      capability. (releaseCapability() takes care of this).

    + sched_mutex - protect Scheduler data structures.
    + gc_pending_cond - SMP-only condition variable for signalling
      completion of GCs.

- initial implementation of call-ins, i.e., multiple OS threads
  may concurrently call into the RTS without interfering with
  each other. Implementation uses cheesy locking protocol to
  ensure that only one OS thread at a time can construct a
  function application -- stop-gap measure until the RtsAPI
  is revised (as discussed last month) *and* a designated
  block is used for allocating these applications.

- In the implementation of call-ins, the OS thread blocks
  waiting for an RTS worker thread to complete the evaluation
  of the function application. Since main() also uses the
  RtsAPI, provide a separate entry point for it (rts_mainEvalIO()),
  which avoids creating a separate thread to evaluate Main.main,
  that can be done by the thread exec'ing main() directly.
  [Maybe there's a tidier way of doing this, a bit ugly the
  way it is now..]

There are a couple of dark corners that needs to be looked at,
such as conditions for shutting down (and how) + consider what
ought to happen when async I/O is thrown into the mix (I know
what will happen, but that's maybe not what we want).

Other than that, things are in a generally happy state & I hope
to declare myself done before the week is up.
ghc/rts/Capability.c
ghc/rts/Capability.h
ghc/rts/Main.c
ghc/rts/RtsAPI.c
ghc/rts/Schedule.c
ghc/rts/Schedule.h