urbit/sys/vane/behn.hoon
Joe Bryan e603aef6b5 Merge branch 'hotfix' into next
* hotfix:
  ensures $~ defaults nest in the actual structure
  behn: ignore duplicate %wait requests (#1043)
  restores +able:dill comment margin
  renames kernel upgrade initialization event from %vega to %lyra
  refactors arvo's +spam:is, which sends a move to every vane
  refactors effect iteration in arvo +poke
  updates arvo/vanes to send/receive %vega kernel upgrade notification
  build tank outside of |.
2019-02-05 18:42:19 -05:00

241 lines
5.8 KiB
Plaintext

:: %behn, just a timer
::
!? 164
::
=, behn
|= pit=vase
=> |%
+$ move [p=duct q=(wind note:able gift:able)]
+$ sign ~
::
+$ behn-state
$: timers=(list timer)
unix-duct=duct
next-wake=(unit @da)
==
::
+$ timer [date=@da =duct]
--
::
=> |%
++ per-event
=| moves=(list move)
|= [[our=ship now=@da =duct] state=behn-state]
::
|%
:: %entry-points
::
:: +born: handle urbit restart
::
++ born
^+ [moves state]
:: store this duct for setting unix wakeup timers
::
=. unix-duct.state duct
:: process any elapsed timers and clear and reset :next-wake
::
=> notify-clients
set-wake(next-wake.state ~)
:: +crud: error report; hand off to %dill to be printed
::
++ crud
|= [p=@tas q=tang]
^+ [moves state]
[[duct %slip %d %flog %crud p q]~ state]
:: +rest: cancel the timer at :date, resetting :next-wake if needed
::
++ rest
|= date=@da
^+ [moves state]
::
=. timers.state (unset-timer [date duct])
set-wake
:: +vega: learn of a kernel upgrade
::
++ vega
[moves state]
:: +wait: set a new timer at :date, resetting :next-wake if needed
::
++ wait
|= date=@da
^+ [moves state]
:: process elapsed timers first to maintain sort order
::
=. event-core notify-clients
=. timers.state (set-timer [date duct])
set-wake
:: +wake: unix says we should wake up; notify clients and set :next-wake
::
++ wake
^+ [moves state]
=> notify-clients
set-wake(next-wake.state ~)
:: +wegh: produce memory usage report for |mass
::
++ wegh
^+ [moves state]
:_ state :_ ~
:^ duct %give %mass
:+ %behn %|
:~ timers+&+timers.state
dot+&+state
==
:: %utilities
::
::+|
::
++ event-core .
:: +notify-clients: wake up vanes whose timers have expired
::
:: When we return the list moves to clients, we flop them so they're in
:: the same order as they were in :timers.
::
++ notify-clients
=* timers timers.state
|- ^+ event-core
::
?~ timers
=. moves (flop moves)
event-core
::
?: (gth date.i.timers now)
=. moves (flop moves)
event-core
::
%_ $
timers t.timers
moves [[duct.i.timers %give %wake ~] moves]
==
:: +set-wake: set or unset a unix timer to wake us when next timer expires
::
:: We prepend the unix %doze event so that it is handled first. Arvo must
:: handle this first because the moves %behn emits will get handled in
:: depth-first order. If we're handling a %wake which causes a move to a
:: different vane and a %doze event to send to unix, Arvo needs to process
:: the %doze first because otherwise if the move to the other vane calls
:: back into %behn and emits a second %doze, the second %doze would be
:: handled by unix first which is incorrect.
::
++ set-wake
^+ [moves state]
::
=* next-wake next-wake.state
=* timers timers.state
=* unix-duct unix-duct.state
:: if no timers, cancel existing wakeup timer or no-op
::
?~ timers
?~ next-wake
[moves state]
:_ state(next-wake ~)
[[unix-duct %give %doze ~] moves]
:: if :next-wake is in the past or not soon enough, reset it
::
?^ next-wake
?: &((gte date.i.timers u.next-wake) (lte now u.next-wake))
[moves state]
:_ state(next-wake `date.i.timers)
[[unix-duct %give %doze `date.i.timers] moves]
:: there was no unix wakeup timer; set one
::
:_ state(next-wake `date.i.timers)
[[unix-duct %give %doze `date.i.timers] moves]
:: +set-timer: set a timer, maintaining the sort order of the :timers list
::
++ set-timer
=* timers timers.state
|= t=timer
^+ timers
::
?~ timers
~[t]
:: ignore duplicates
::
?: =(t i.timers)
timers
:: timers at the same date form a fifo queue
::
?: (lth date.t date.i.timers)
[t timers]
::
[i.timers $(timers t.timers)]
:: +unset-timer: cancel a timer; if it already expired, no-op
::
++ unset-timer
=* timers timers.state
|= [t=timer]
^+ timers
:: if we don't have this timer, no-op; for debugging, add a printf here
::
?~ timers
~
?: =(i.timers t)
t.timers
::
[i.timers $(timers t.timers)]
--
--
::
=| behn-state
=* state -
|= [our=ship now=@da eny=@uvJ ski=sley]
=* behn-gate .
^?
|%
:: +call: handle a +task:able:behn request
::
++ call
|= $: hen=duct
type=*
wrapped-task=(hobo task:able)
==
^- [(list move) _behn-gate]
::
=/ =task:able
?. ?=(%soft -.wrapped-task)
wrapped-task
((hard task:able) p.wrapped-task)
::
=/ event-core (per-event [our now hen] state)
::
=^ moves state
?- -.task
%born born:event-core
%crud (crud:event-core [p q]:task)
%rest (rest:event-core date=p.task)
%vega vega:event-core
%wait (wait:event-core date=p.task)
%wake wake:event-core
%wegh wegh:event-core
==
[moves behn-gate]
:: +load: migrate an old state to a new behn version
::
++ load
|= old=*
^+ behn-gate
::
~| %behn-load-fail
behn-gate(state (behn-state old))
:: +scry: view timer state
::
:: TODO: not referentially transparent w.r.t. elapsed timers,
:: which might or might not show up in the product
::
++ scry
|= [fur=(unit (set monk)) ren=@tas why=shop syd=desk lot=coin tyl=path]
^- (unit (unit cage))
::
?. ?=(%& -.why)
~
[~ ~ %tank !>(>timers<)]
::
++ stay state
++ take
|= [tea=wire hen=duct hin=(hypo sign)]
^- [(list move) _behn-gate]
~| %behn-take-not-implemented
!!
--