diff options
| -rw-r--r-- | Channels/README.md | 51 | ||||
| -rw-r--r-- | Channels/chans.b | 39 | ||||
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | Spawn/README.md | 39 | ||||
| -rw-r--r-- | Spawn/spawn.b | 43 |
5 files changed, 170 insertions, 4 deletions
diff --git a/Channels/README.md b/Channels/README.md index 7d19f2b..639b8ff 100644 --- a/Channels/README.md +++ b/Channels/README.md @@ -8,12 +8,59 @@ Further reading on CSP: http://www.usingcsp.com/cspbook.pdf ## Source +### chans.b:33,36 +This statement shows three channels being made. -## Demo +`done` is an unbuffered channel which transports integer values. + +`msgChan` is an unbuffered channel, instantiated using buffered channel syntax, which transports strings. + +`numChan` is a buffered channel which transports a tuple representing an integer pair. + +### chans.b:38 + +The `spawn` statement is used to create a new process running a given function, in this case `summer()`. + +### chans.b:40,45 + +This section loads number pairs from the variable `i` and the number 2 from 0 to 14, covering 15 total iterations. After the iterative statement completes, a (later discarded) value is passed to the channel `done`. The first (and only) value in `msgChan` is then read out and printed. + +Note: Writing to a channel whose buffer (or lack thereof) is currently full is a blocking operation. Similarly, reading from a channel whose buffer (or lack thereof) is currently empty is a blocking operation. +### chans.b:13,28 + +The function `summer()` operates an infinite loop which operates a single `alt` statement which is similar to a switch-case statement which operates on the presence of values within a channel. + +The three channels are used to coordinate operation between the two processes. + +`num` is checked first and a tuple of values is pulled out: a value and a power to raise said value to. The `n^p` operation is shown as `n**p` in Limbo, with the result being added to sum's current value. + +`done` is checked after `num` has no more values in its buffer. If a value is found, the sum is stringified and passed down `msg` and the looping condition is unset. + +The default value, indicated by `*=>`, is used when no channels have a value, so we sleep the current process for 5ms to de-schedule ourselves in case some form of scheduling is holding up our communications. + +## Demo + ; limbo chans.b + ; chans + Sum: 0 + Sum: 1 + Sum: 5 + Sum: 14 + Sum: 30 + Sum: 55 + Sum: 91 + Sum: 140 + Sum: 204 + Sum: 285 + Sum: 385 + Sum: 506 + Sum: 650 + Final sum: 650 + ; ## Exercises -- +- Can you pass an ADT over a channel? +- What happens if you pass a `ref` type over a channel? diff --git a/Channels/chans.b b/Channels/chans.b index 82945c8..700ea63 100644 --- a/Channels/chans.b +++ b/Channels/chans.b @@ -10,11 +10,46 @@ Chans: module { init: fn(nil: ref Draw->Context, nil: list of string); }; +summer(done: chan of int, msg: chan of string, num: chan of (int, int)) { + sum := big 0; + run := 1; + + while(run) + alt { + (n, p) := <-num => + sum += big n**p; + print("Sum: %bd\n", sum); + <-done => + msg <-= string sum; + run = 0; + * => + sys->sleep(5); + } +} + init(nil: ref Draw->Context, nil: list of string) { sys = load Sys Sys->PATH; - + n := 4; + done := chan of int; + msgChan := chan[0] of string; + numChan := chan[n] of (int, int); + + spawn summer(done, msgChan, numChan); + + for(i := 0; i < 15; i++) + numChan <-= (i, 2); + + done <-= 0; + + print("Final sum: %s\n", <-msgChan); + + buf := chan[20] of int; + + print("Len: %d\n", len buf); + + for(i = 0; i < 5; i++) + buf <-= i; exit; } - @@ -38,6 +38,8 @@ You could then run said file with: - [Slices](./Slices) - [Functions](./Functions) - [Function References](./Function-Refs) +- [Spawn](./Spawn) +- [Channels](./Channels) - [Abstract Data Types](./ADTs) - [Modules](./Modules) - [Generics, Picks, and Interfaces (kind of)](./Generics) diff --git a/Spawn/README.md b/Spawn/README.md new file mode 100644 index 0000000..ed942d7 --- /dev/null +++ b/Spawn/README.md @@ -0,0 +1,39 @@ +# Spawn + +Limbo supports the creation of processes operating on a given function via the `spawn` statement. Functions passed to spawn cannot have a return value. + +Inferno processes share memory with their parent processes which spawn them, bar the process's respective stack. Inferno processes are pre-emptively scheduled by the Inferno kernel. These processes are analogous, but not equivocal to, threads in unix-like systems. + +Synchronization between processes is recommended to be done through [channels](../Channels). + +For further reading on potential inspirations for Inferno processes, see [rfork(2)](http://man.cat-v.org/9front/2/fork). + +## Source + +### spawn.b:31,40 + +This section spawns four processes all of which will attempt to print to their standard output. Two functions spawn running the `quacker()` function and two function spawn running the `summer()` function with varying arguments. + +Note: The call to `sleep()` in this context within the `init()` function. + +## Demo + + ; limbo spawn.b + ; spawn + quack! + Sum (2): 0 + quack! + Sum (3): 0 + Sum (2): 1 + Sum (3): 1 + Sum (2): 3 + Sum (3): 3 + Final sum (2): 3 + Sum (3): 6 + Final sum (3): 6 + ; + +## Exercises + +- How many different orders do you see the print statements occur in? +- What happens if you remove the sleep? diff --git a/Spawn/spawn.b b/Spawn/spawn.b new file mode 100644 index 0000000..b375f6c --- /dev/null +++ b/Spawn/spawn.b @@ -0,0 +1,43 @@ +implement Spawn; + +include "sys.m"; +include "draw.m"; + +sys: Sys; +print: import sys; + +Spawn: module { + init: fn(nil: ref Draw->Context, nil: list of string); +}; + +summer(n: int) { + sum := 0; + + for(i := 0; i <= n; i++) { + sum += i; + print("Sum (%d): %d\n", n, sum); + } + + print("Final sum (%d): %d\n", n, sum); +} + +quacker() { + print("quack!\n"); +} + +init(nil: ref Draw->Context, nil: list of string) { + sys = load Sys Sys->PATH; + + spawn quacker(); + + spawn summer(2); + + spawn quacker(); + + n := 3; + spawn summer(n); + + sys->sleep(10); + + exit; +} |
