shithub: limbobyexample

Download patch

ref: 577f8a21ded3a49c799ee49b90508801f1361842
parent: 5bd50f13c315024164a221eb5a86edabf412b4d1
author: seh <henesy.dev@gmail.com>
date: Mon Mar 18 11:42:43 EDT 2019

add spawn and channels examples

diff: cannot open b/Spawn//null: file does not exist: 'b/Spawn//null'
--- a/Channels/README.md
+++ b/Channels/README.md
@@ -8,12 +8,59 @@
 
 ## 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?
--- a/Channels/chans.b
+++ b/Channels/chans.b
@@ -10,11 +10,46 @@
 	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;
 }
-
--- a/README.md
+++ b/README.md
@@ -38,6 +38,8 @@
 - [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)
--- /dev/null
+++ b/Spawn/README.md
@@ -1,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?
--- /dev/null
+++ b/Spawn/spawn.b
@@ -1,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;
+}