
--{{{  COMMENT documentation
--|
--| This program shows a use of a shared data structure (the "blackboard"),
--| protected by CREW synchronisation.  The "blackboard" is shared between
--| 10 philosophers.  To read/write the "blackboard", philosophers must obtain
--| the corresponding CREW lock.  That lock allows concurrent readers but
--| only one reader/writer at a time.  Readers and writers are strictly
--| queued - no reader is delayed by later arriving writers and vice-versa.
--|
--| The CREW-shared "blackboard", for this example, consists only of a single
--| character (a BYTE).  This could, of course, be any data structure.
--|
--| A further example is the CREW-shared "control.info".  This contains
--| run-time parameters used by the philosophers (their view of how long
--| a second is and the percentage of time they read, as opposed to write,
--| the "blackboard").  This is updated by the controller, in response to
--| keyboard input, and observed by the philosophers and display process.
--|
--| The use of "control.info" shows CREW synchronisation in real use - to share
--| information and provide useful control over the running animation.
--| On the other hand, the use of "blackboard" is simply to demonstrate
--| how it is done and provide the subject for the animation.
--|
--| The philosophers also report to a display process via a shared channel.
--| So, also, does a timekeeper.  Here is their college (crew.test), which
--| has the standard KRoC channel interface to the outside world:
--|
--|  _______________________________________________________________________
--| |                                                                       |
--| |                                               _____________________   |
--| |                                              |                     |  |
--| |  --------------------------------------------|  (CREW) blackboard  |  |
--| |      |           |               |           |_____________________|  |
--| |     r|w         r|w             r|w                                   |
--| |   ___|___     ___|___         ___|___                                 |
--| |  |       |   |       |       |       |                                |
--| |  | :-) 0 |   | :-) 1 |  ...  | :-) 9 |                                |
--| |  |_______|   |_______|       |_______|                                |
--| |    |   |       |   |           |   |                                  |
--| |    v  r|       v  r|           v  r|          _____________________   |
--| |    |   |       |   |           |   |         |                     |  |
--| |  --|-----------|---------------|-------------| (CREW) control.info |  |
--| |    |           |         |     |        |    |_____________________|  |
--| |    |           |         |     |       r|                             |
--| |    |           |         |     |    ____|____                         |
--| |    |           |         |     |   |         |                        |
--| |  ------------------------|---------| display |                        |
--| |         |            |   |         |_________|                        |
--| |         ^            ^  r|w             |                             |
--| |   ______|_____    ___|___|____          |                             |
--| |  |            |  |            |         |                             |
--| |  | timekeeper |  | controller |         |                             |
--| |  |____________|  |____________|         |                             |
--| |                         |               |                             |
--| |                         |               |                 crew.test   |
--| |_________|_______________|_______________|_____________________________|
--|           |               |               |
--|    error  v     keyboard  ^               v screen
--|           |               |               |
--|
--}}}

#INCLUDE "semaphore.inc"
#INCLUDE "crew.inc"

#INCLUDE "display.inc"
#INCLUDE "blackboard.inc"
#INCLUDE "control_info.inc"

#USE "controller"
#USE "philosopher"
#USE "display"
#USE "timekeeper"

PROC crew.test (CHAN OF BYTE keyboard, screen, error)

  --{{{  CREW.BLACKBOARD blackboard:
  CREW.BLACKBOARD blackboard:
  #PRAGMA SHARED blackboard
  --}}}

  --{{{  CREW.CONTROL.INFO control.info:
  CREW.CONTROL.INFO control.info:
  #PRAGMA SHARED control.info
  --}}}

  --{{{  SHARED CHAN OF DISPLAY to.display:
  CHAN OF DISPLAY to.display:
  #PRAGMA SHARED to.display
  
  SEMAPHORE to.display.s:
  #PRAGMA SHARED to.display.s
  --}}}

  VAL INT n.philosophers IS 10:

  VAL INT initial.seconds IS 10000:
  VAL INT initial.read.percentage IS 80:

  INT seed:

  SEQ

    initialise.crew (blackboard[crew])
    blackboard[value] := '?'

    initialise.crew (control.info[crew])
    control.info[seconds] := initial.seconds
    control.info[read.percentage] := initial.read.percentage

    initialise.semaphore (to.display.s, 1)

    --{{{  initialise random number seed
    TIMER tim:
    SEQ
      tim ? seed
      IF
        (seed = (MOSTNEG INT)) OR (seed = 0)
          seed := 42
        seed < 0
          seed := -seed
        TRUE
          SKIP
      IF
        (seed PLUS n.philosophers) < 0
          seed := seed MINUS n.philosophers
        TRUE
          SKIP
    --}}}

    PAR
      controller (keyboard, control.info, to.display, to.display.s)
      PAR i = 0 FOR n.philosophers
        philosopher (BYTE i, i + seed, control.info,
                     blackboard, to.display, to.display.s)
      display (to.display, control.info, screen)
      timekeeper (to.display, to.display.s)

:
