::  %khan, thread runner
::
::  this vane presents a command/response interface for running
::  threads. two modes are supported: %fard for intra-arvo
::  requests (i.e. within the same kernel space) and %fyrd for
::  external requests (e.g. from the unix control plane.)
::
::  both modes take a thread start request consisting of a
::  namespace, thread name, and input data; they respond over the
::  same duct with either success or failure. %fard takes its
::  input arguments as a cage and produces %arow, which contains
::  a cage on success (or tang on failure). %fyrd takes an output
::  mark and input page; it produces %avow, which contains a page
::  on success.
::
::  threads currently expect input and produce output as vase,
::  not cage. %fard/%arow use cage instead since this is the
::  eventual desired thread API; however, the input mark is
::  currently ignored, and the output mark is always %noun. (for
::  forward compatibility, it is safe to specify %noun as the
::  input mark.)
::
::  %fyrd does mark conversion on both ends, and additionally
::  lifts its input into a $unit. this second step is done
::  because threads conventionally take their input as a unit,
::  with ~ for the case of "no arguments".
::
::  n.b. the current convention for threads is to use !< to
::  unpack their input vase. !< imposes the requirement that the
::  input type nests within the specified type. this limits %fyrd
::  to threads with inputs for which a named mark exists; it is
::  impossible to use %noun in general since it does not nest.
::  threads written against the current vase-based API could use
::  ;; instead of !< to unpack their input, thus allowing the
::  use of %fyrd with %noun. however the eventual solution is
::  probably to make threads consume and produce cages, and do
::  mark conversion where appropriate.
!:
!?  164
::
=,  khan
|=  our=ship
=>  |%                                                  ::  %khan types
    +$  move  [p=duct q=(wite note gift)]               ::
    +$  note                                            ::    out request $->
      $~  [%g %deal *sock *term *deal:gall]             ::
      $%  $:  %g                                        ::    to %gall
              $>(%deal task:gall)                       ::  full transmission
          ==                                            ::
          $:  %k                                        ::    to self
              $>(%fard task)                            ::  internal thread
      ==  ==                                            ::
    +$  sign                                            ::    in response $<-
      $%  $:  %gall                                     ::    from %gall
              $>(%unto gift:gall)                       ::  update
          ==                                            ::
          $:  %khan                                     ::    from self
              $>(?(%arow %avow) gift)                   ::  thread result
      ==  ==                                            ::
    +$  khan-state                                      ::
      $:  %0                                            ::    state v0
          hey=duct                                      ::  unix duct
          tic=@ud                                       ::  tid counter
      ==                                                ::
    --                                                  ::
=>
|%
++  get-beak
  |=  [=bear now=@da]
  ?@(bear [our bear %da now] bear)
::
++  get-dais
  |=  [=beak =mark rof=roof]
  ^-  dais:clay
  ?~  ret=(rof ~ %cb beak /[mark])
    ~|(mark-unknown+mark !!)
  ?~  u.ret
    ~|(mark-invalid+mark !!)
  ?>  =(%dais p.u.u.ret)
  !<(dais:clay q.u.u.ret)
::
++  get-tube
  |=  [=beak =mark =out=mark rof=roof]
  ^-  tube:clay
  ?~  ret=(rof ~ %cc beak /[mark]/[out-mark])
    ~|(tube-unknown+[mark out-mark] !!)
  ?~  u.ret
    ~|(tube-invalid+[mark out-mark] !!)
  ?>  =(%tube p.u.u.ret)
  !<(tube:clay q.u.u.ret)
::
++  make-wire
  |=  [=beak =mark]
  ^-  wire
  [%fyrd (en-beam beak mark ~)]
::
++  read-wire
  |=  =wire
  ^-  (pair beak mark)
  ~|  khan-read-wire+wire
  ?>  ?=([%fyrd ^] wire)
  =/  =beam  (need (de-beam t.wire))
  ?>(?=([@ ~] s.beam) beam(s i.s.beam))
::
++  poke-spider
  |=  [hen=duct =cage]
  ^-  move
  [hen %pass //g %g %deal [our our] %spider %poke cage]
::
++  watch-spider
  |=  [hen=duct =path]
  ^-  move
  [hen %pass //g %g %deal [our our] %spider %watch path]
--
=|  khan-state
=*  state  -
|=  [now=@da eny=@uvJ rof=roof]
=*  khan-gate  .
^?
|%
::  +call: handle a +task request
::
++  call
  |=  $:  hen=duct
          dud=(unit goof)
          wrapped-task=(hobo task)
      ==
  ^-  [(list move) _khan-gate]
  ::
  =/  =task  ((harden task) wrapped-task)
  ?^  dud
    ~|(%khan-call-dud (mean tang.u.dud))
  ?+    -.task  [~ khan-gate]
      %born
    [~ khan-gate(hey hen, tic 0)]
  ::
      %fard  (bard hen 'khan-fyrd--' bear.p.task %| [name args]:p.task)
      %lard  (bard hen 'khan-lard--' bear.task %& shed.task)
      %fyrd
    =*  fyd         p.task
    =/  =beak       (get-beak bear.fyd now)
    =/  =wire       (make-wire beak p.args.fyd)
    =/  =dais:clay  (get-dais beak p.q.args.fyd rof)
    =/  =vase
      (slap (vale.dais q.q.args.fyd) !,(*hoon [~ u=.]))
    =-  [[hen %pass wire -]~ khan-gate]
    [%k %fard bear.fyd name.fyd p.q.args.fyd vase]
  ==
::
++  bard
  |=  [hen=duct prefix=@ta =bear payload=(each shed [name=term args=cage])]
  ^-  [(list move) _khan-gate]
  =/  =tid:rand  (cat 3 prefix (scot %uv (sham (mix tic eny))))
  =/  =beak      (get-beak bear now)
  =/  =cage
    ?-  -.payload
      %&  [%spider-inline !>([~ `tid beak p.payload])]
      %|  [%spider-start !>([~ `tid beak [name q.args]:p.payload])]
    ==
  =.  tic  +(tic)
  :_  khan-gate
  :~  (watch-spider hen /thread-result/[tid])
      (poke-spider hen cage)
  ==
::
::  +load: migrate an old state to a new khan version
::
++  load
  |=  old=khan-state
  ^+  khan-gate
  khan-gate(state old)
::  +scry: nothing to see as yet
::
++  scry
  ^-  roon
  |=  [lyc=gang car=term bem=beam]
  ^-  (unit (unit cage))
  ~
++  stay  state
::  +take: handle responses.
::
++  take
  |=  [tea=wire hen=duct dud=(unit goof) hin=sign]
  ^-  [(list move) _khan-gate]
  ?^  dud
    ~|(%khan-take-dud (mean tang.u.dud))
  :_  khan-gate
  ?-    -.hin
      %gall
    ?+    -.p.hin  ~
        ?(%poke-ack %watch-ack)
      ?~  p.p.hin  ~
      %-  (slog 'khan-ack' u.p.p.hin)
      [hen %give %arow %| -.p.hin u.p.p.hin]~
    ::
        %fact
      =*  cag  cage.p.hin
      ?+    p.cag  ~&(bad-fact+p.cag !!)
          %thread-fail
        =/  =tang  !<(tang q.cag)
        ::  %-  (slog 'khan-fact' tang)
        [hen %give %arow %| p.cag tang]~
      ::
          %thread-done
        [hen %give %arow %& %noun q.cag]~
      ==
    ==
  ::
      %khan
    ?.  ?=(%arow +<.hin)    ~
    ?.  ?=([%fyrd *] tea)   ~
    =*  row  p.hin
    ?.  ?=(%& -.row)
      [hen %give %avow row]~
    =/  [=beak =mark]   (read-wire tea)
    =/  =tube:clay      (get-tube beak p.p.row mark rof)
    =/  =vase           (tube q.p.row)
    [hen %give %avow %& mark q.vase]~
  ==
--
