@@ -5,7 +5,8 @@ template = "doc.html"
5aliases = ["/docs/learn/arvo/gall/"]
5aliases = ["/docs/learn/arvo/gall/"]
8−This document describes Gall, the Arvo userspace vane. It is accurate as of 2019.12.02.
8+This document describes Gall, the Arvo userspace vane. It is split into two main
9+sections: Agents and [Threads](#threads).
@@ -557,3 +558,237 @@ If an error happens in `+on-poke`, the crash report goes into the
557`+on-subscription`, the crash report goes into the `%watch-ack`
558`+on-subscription`, the crash report goes into the `%watch-ack`
558response. If a crash happens in any of the other handlers, the report
559response. If a crash happens in any of the other handlers, the report
559is passed into this arm.
560is passed into this arm.
565+As discussed in [Agents](#agents), Urbit code lives in the following basic
568+- Runtime (Nock interpreter, persistence engine, IO drivers, jets)
569+- Kernel vanes (managed by Arvo)
570+- Userspace agents (managed by Gall, permanent state)
571+- Userspace threads (managed by Spider, transient state)
573+This describes the last category: Threads.
575+A thread is a monadic function that takes arguments and produces a
576+result. It may perform input and output while running, so it is not a
577+pure function. It may fail.
579+An agent's strength is that it's permanent and bulletproof. All state
580+transitions are defined, and each action it performs is a transaction.
581+Code upgrades preserve existing state.
583+An agent's weakness is complex input and output. Since each state
584+transition must be explicitly handled, the complexity of an agent
585+explodes with the amount of IO it handles. At best, this results in
586+long and complex code; at worst, unexpected states are mishandled,
587+corrupting permanent state.
589+A thread's strength is that it can easily perform complex IO operations.
590+It uses what's often called the IO monad (plus the exception monad) to
591+provide a natural framework for IO.
593+A thread's weakness is that it's impermanent and may fail unexpectedly.
594+In most of its intermediate states, it expects only a small number of
595+events (usually one), so if it receives anything it didn't expect, it
596+fails. When code is upgraded, it's impossible to upgrade a running
599+Thus, for anything that needs to be permament, use an agent. When you
600+need to do a long or complex sequence of IO operations, reduce that to a
601+single logical IO operation by spinning it out into a thread. If you
602+only change your agent's state in response to success of the thread, an
603+IO failure will never result in partially applied state changes.
605+A thread may also be run from the dojo by prefixing its name with `-`
606+and giving it any arguments it requires. If alone, any result will be
607+printed to the screen; else the output may be piped into an agent or
613++$ thread $-(vase _*form:(strand ,vase))
616+A thread is a running strand. It receives an argument as a vase and may
617+prodduce a vase of a result.
622+ [parent=(unit tid) use=(unit tid) file=term =vase]
625+To run a thread, poke Spider with mark `%spider-start` and a value of
626+type `start-args`. `parent` is an optional parent, `use` is an optional
627+id, `file` is the filename, and `vase` is the argument. If the parent
628+is specified (usually to the thread that spawned this thread), then
629+when the parent ends, the child will end too.
631+A thread may succeed or fail. You may recieve the return value or be
632+notified of failure by subscribing to Spider at `/thread-result/[tid]`,
633+where `tid` is the same one you passed in `use`. Take care to create a
634+`tid` that will be unique from any other that may be created, for
638+(scot %ta (cat 3 'my-agent_' (scot %uv (sham eny))))`
641+The `%fact` that comes back on this subscription will have mark either
642+`%thread-fail` or `%thread-done`. If it failed, the content will have
643+type `[term tang]` with an explanation of the error. If it succeeded,
644+the content will be whatever the thread produced.
647++$ input [=tid =cage]
650+You may poke a thread by poking Spider with `%spider-input`. `tid` is
651+the id of the thread you wish to poke, and `cage` is the data to poke it
654+You may subscribe to a thread by subscribing to Spider at
655+`/thread/[tid]/path`.
657+You may stop a thread by poking Spider with `%spider-stop` and data
658+`[tid ?]`, where `tid` is the thread you wish to stop and the loobean
659+decides whether to quit nicely (suppresses printfs).
663+A thread is just a function from a vase of arguments to a strand that
664+produces a vase of the result. We say "just" not because it's obvious
665+yet what that means but because it means we only need to explain how to
666+write strands, and threads are just a particular case.
668+The type of a strand is defined in lib/strand, but you will rarely touch
669+those types directly. Most of the time, you will use two functions
670+`pure` and `bind` combined with any of the functions defined in
673+### Strand fundamentals
675+When writing strands, you almost always want to start by specializing
676+`strand` to your return type. A strand can produce any type, but you
677+must specify up front what type it will produce. By convention, we use
678+the variable `m` for this. For example, if you are going to produce a
687+Note that `m` is a core that has three arms:
689+`+form` is the mold of the strand, suitable for `^-`.
691+`+pure` produces a strand that does nothing except return a value. So,
692+`(pure:(strand ,@tas) %foo)` is a strand that produces `%foo` without
693+doing any IO. Thus, the most trivial thread is:
698+=, strand=strand:spider
706+`+bind`, used with `;<`, takes two strands and runs one after the other,
707+letting you use the result of the first strand in the second. For
711+;< num=@ud bind:m (pure:m 5)
715+Has the same result as:
721+### Other useful functions
723+There are many useful strand functions in lib/strandio and some other
724+libraries. For example:
726+`+sleep` waits for the specified time.
728+`+get-time` gets the current time.
730+`+poke` pokes an agent.
732+`+watch` subscribes to an agent.
734+`+fetch-json` produces the JSON at a particular URL.
736+`+retry` tries a strand repeatedly with exponential backoff until it
739+`+start-thread` starts another thread.
741+`send-raw-card` sends any card.
748+=, strand=strand:spider
753+=+ !<([arg=@dr ~] arg)
754+;< now-1=@da bind:m get-time:strandio
755+;< ~ bind:m (sleep:strandio arg)
756+;< now-2=@da bind:m get-time:strandio
757+(pure:m !>(`@dr`(sub now-2 now-1)))
760+The first seven lines are the same boilerplate we saw before. After
761+that, it `!<`'s the argument to its expected type. It saves the current
762+time in `now-1`, sleeps how long the argument says to, then gets the
763+time again and produces the difference between the two times. This
764+number should be close to the argument you passed in, plus a little for
765+computation time. You can run this at the dojo with `-time ~s1`.
770+=, strand=strand:spider
774+;< ~ bind:m start-simple
775+;< ~ bind:m (raw-ship ~bud ~)
776+;< ~ bind:m (dojo ~bud "[%test-result (add 2 3)]")
777+;< ~ bind:m (wait-for-output ~bud "[%test-result 5]")
778+;< ~ bind:m end-simple
782+This is uses `lib/ph/io` to run a pH test. Aqua and pH are described
783+[elsewhere](@/docs/tutorials/hoon/hoon-school/aqua.md), but if you've initialized Aqua by running `|start %aqua` and
784+`:aqua +solid`, then you can run `-ph-add` to execute this thread.
786+It starts by running some virtualization initialization with
787+`start-simple`. Then, it boots a guest ship called ~bud, types a line
788+into the dojo, and waits for it to printed the expected output.
790+It's easy to see how this building blocks could be combined to perform
791+complex tests. For example, you could start several ships and have them
792+`|hi` each other, sync from each other, or do anything else. Check out
793+`lib/ph/io` and `lib/ph/azimuth` for other useful functions in constructing