diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2015-05-05 21:17:24 -0700 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2015-05-05 21:17:24 -0700 |
commit | b96af395b9af2ff9df94b3e82213171f30827c8d (patch) | |
tree | 17c8c12648ccc25625e2534ec8d74fbe8f1542cc /cpp/061channel.mu | |
parent | 2e3b597fe85b654e82b891c22d50754fa5a26156 (diff) | |
download | mu-b96af395b9af2ff9df94b3e82213171f30827c8d.tar.gz |
1276 - make C++ version the default
I've tried to update the Readme, but there are at least a couple of issues.
Diffstat (limited to 'cpp/061channel.mu')
-rw-r--r-- | cpp/061channel.mu | 266 |
1 files changed, 0 insertions, 266 deletions
diff --git a/cpp/061channel.mu b/cpp/061channel.mu deleted file mode 100644 index bee6b785..00000000 --- a/cpp/061channel.mu +++ /dev/null @@ -1,266 +0,0 @@ -# Mu synchronizes using channels rather than locks, like Erlang and Go. -# -# The two ends of a channel will usually belong to different routines, but -# each end should only be used by a single one. Don't try to read from or -# write to it from multiple routines at once. -# -# The key property of channels is that writing to a full channel or reading -# from an empty one will put the current routine in 'waiting' state until the -# operation can be completed. - -scenario channel [ - run [ - 1:address:channel <- init-channel 3:literal/capacity - 1:address:channel <- write 1:address:channel, 34:literal - 2:integer, 1:address:channel <- read 1:address:channel - ] - memory-should-contain [ - 2 <- 34 - ] -] - -container channel [ - # To avoid locking, writer and reader will never write to the same location. - # So channels will include fields in pairs, one for the writer and one for the - # reader. - first-full:integer # for write - first-free:integer # for read - # A circular buffer contains values from index first-full up to (but not - # including) index first-empty. The reader always modifies it at first-full, - # while the writer always modifies it at first-empty. - data:address:array:location -] - -# result:address:channel <- init-channel capacity:integer -recipe init-channel [ - default-space:address:array:location <- new location:type, 30:literal - # result = new channel - result:address:channel <- new channel:type - # result.first-full = 0 - full:address:integer <- get-address result:address:channel/deref, first-full:offset - full:address:integer/deref <- copy 0:literal - # result.first-free = 0 - free:address:integer <- get-address result:address:channel/deref, first-free:offset - free:address:integer/deref <- copy 0:literal - # result.data = new location[ingredient+1] - capacity:integer <- next-ingredient - capacity:integer <- add capacity:integer, 1:literal # unused slot for 'full?' below - dest:address:address:array:location <- get-address result:address:channel/deref, data:offset - dest:address:address:array:location/deref <- new location:type, capacity:integer - reply result:address:channel -] - -# chan:address:channel <- write chan:address:channel, val:location -recipe write [ - default-space:address:array:location <- new location:type, 30:literal - chan:address:channel <- next-ingredient - val:location <- next-ingredient - { - # block if chan is full - full:boolean <- channel-full? chan:address:channel - break-unless full:boolean - full-address:address:integer <- get-address chan:address:channel/deref, first-full:offset - wait-for-location full-address:address:integer/deref - } - # store val - circular-buffer:address:array:location <- get chan:address:channel/deref, data:offset - free:address:integer <- get-address chan:address:channel/deref, first-free:offset - dest:address:location <- index-address circular-buffer:address:array:location/deref, free:address:integer/deref - dest:address:location/deref <- copy val:location - # increment free - free:address:integer/deref <- add free:address:integer/deref, 1:literal - { - # wrap free around to 0 if necessary - len:integer <- length circular-buffer:address:array:location/deref - at-end?:boolean <- greater-or-equal free:address:integer/deref, len:integer - break-unless at-end?:boolean - free:address:integer/deref <- copy 0:literal - } - reply chan:address:channel/same-as-ingredient:0 -] - -# result:location, chan:address:channel <- read chan:address:channel -recipe read [ - default-space:address:array:location <- new location:type, 30:literal - chan:address:channel <- next-ingredient - { - # block if chan is empty - empty:boolean <- channel-empty? chan:address:channel - break-unless empty:boolean - free-address:address:integer <- get-address chan:address:channel/deref, first-free:offset - wait-for-location free-address:address:integer/deref - } - # read result - full:address:integer <- get-address chan:address:channel/deref, first-full:offset - circular-buffer:address:array:location <- get chan:address:channel/deref, data:offset - result:location <- index circular-buffer:address:array:location/deref, full:address:integer/deref - # increment full - full:address:integer/deref <- add full:address:integer/deref, 1:literal - { - # wrap full around to 0 if necessary - len:integer <- length circular-buffer:address:array:location/deref - at-end?:boolean <- greater-or-equal full:address:integer/deref, len:integer - break-unless at-end?:boolean - full:address:integer/deref <- copy 0:literal - } - reply result:location, chan:address:channel/same-as-ingredient:0 -] - -scenario channel-initialization [ - run [ - 1:address:channel <- init-channel 3:literal/capacity - 2:integer <- get 1:address:channel/deref, first-full:offset - 3:integer <- get 1:address:channel/deref, first-free:offset - ] - memory-should-contain [ - 2 <- 0 # first-full - 3 <- 0 # first-free - ] -] - -scenario channel-write-increments-free [ - run [ - 1:address:channel <- init-channel 3:literal/capacity - 1:address:channel <- write 1:address:channel, 34:literal - 2:integer <- get 1:address:channel/deref, first-full:offset - 3:integer <- get 1:address:channel/deref, first-free:offset - ] - memory-should-contain [ - 2 <- 0 # first-full - 3 <- 1 # first-free - ] -] - -scenario channel-read-increments-full [ - run [ - 1:address:channel <- init-channel 3:literal/capacity - 1:address:channel <- write 1:address:channel, 34:literal - _, 1:address:channel <- read 1:address:channel - 2:integer <- get 1:address:channel/deref, first-full:offset - 3:integer <- get 1:address:channel/deref, first-free:offset - ] - memory-should-contain [ - 2 <- 1 # first-full - 3 <- 1 # first-free - ] -] - -scenario channel-wrap [ - run [ - # channel with just 1 slot - 1:address:channel <- init-channel 1:literal/capacity - # write and read a value - 1:address:channel <- write 1:address:channel, 34:literal - _, 1:address:channel <- read 1:address:channel - # first-free will now be 1 - 2:integer <- get 1:address:channel/deref, first-free:offset - 3:integer <- get 1:address:channel/deref, first-free:offset - # write second value, verify that first-free wraps - 1:address:channel <- write 1:address:channel, 34:literal - 4:integer <- get 1:address:channel/deref, first-free:offset - # read second value, verify that first-full wraps - _, 1:address:channel <- read 1:address:channel - 5:integer <- get 1:address:channel/deref, first-full:offset - ] - memory-should-contain [ - 2 <- 1 # first-free after first write - 3 <- 1 # first-full after first read - 4 <- 0 # first-free after second write, wrapped - 5 <- 0 # first-full after second read, wrapped - ] -] - -## helpers - -# An empty channel has first-empty and first-full both at the same value. -recipe channel-empty? [ - default-space:address:array:location <- new location:type, 30:literal - chan:address:channel <- next-ingredient - # return chan.first-full == chan.first-free - full:integer <- get chan:address:channel/deref, first-full:offset - free:integer <- get chan:address:channel/deref, first-free:offset - result:boolean <- equal full:integer, free:integer - reply result:boolean -] - -# A full channel has first-empty just before first-full, wasting one slot. -# (Other alternatives: https://en.wikipedia.org/wiki/Circular_buffer#Full_.2F_Empty_Buffer_Distinction) -recipe channel-full? [ - default-space:address:array:location <- new location:type, 30:literal - chan:address:channel <- next-ingredient - # tmp = chan.first-free + 1 - tmp:integer <- get chan:address:channel/deref, first-free:offset - tmp:integer <- add tmp:integer, 1:literal - { - # if tmp == chan.capacity, tmp = 0 - len:integer <- channel-capacity chan:address:channel - at-end?:boolean <- greater-or-equal tmp:integer, len:integer - break-unless at-end?:boolean - tmp:integer <- copy 0:literal - } - # return chan.first-full == tmp - full:integer <- get chan:address:channel/deref, first-full:offset - result:boolean <- equal full:integer, tmp:integer - reply result:boolean -] - -# result:integer <- channel-capacity chan:address:channel -recipe channel-capacity [ - default-space:address:array:location <- new location:type, 30:literal - chan:address:channel <- next-ingredient - q:address:array:location <- get chan:address:channel/deref, data:offset - result:integer <- length q:address:array:location/deref - reply result:integer -] - -scenario channel-new-empty-not-full [ - run [ - 1:address:channel <- init-channel 3:literal/capacity - 2:integer <- channel-empty? 1:address:channel - 3:integer <- channel-full? 1:address:channel - ] - memory-should-contain [ - 2 <- 1 # empty? - 3 <- 0 # full? - ] -] - -scenario channel-write-not-empty [ - run [ - 1:address:channel <- init-channel 3:literal/capacity - 1:address:channel <- write 1:address:channel, 34:literal - 2:integer <- channel-empty? 1:address:channel - 3:integer <- channel-full? 1:address:channel - ] - memory-should-contain [ - 2 <- 0 # empty? - 3 <- 0 # full? - ] -] - -scenario channel-write-full [ - run [ - 1:address:channel <- init-channel 1:literal/capacity - 1:address:channel <- write 1:address:channel, 34:literal - 2:integer <- channel-empty? 1:address:channel - 3:integer <- channel-full? 1:address:channel - ] - memory-should-contain [ - 2 <- 0 # empty? - 3 <- 1 # full? - ] -] - -scenario channel-read-not-full [ - run [ - 1:address:channel <- init-channel 1:literal/capacity - 1:address:channel <- write 1:address:channel, 34:literal - _, 1:address:channel <- read 1:address:channel - 2:integer <- channel-empty? 1:address:channel - 3:integer <- channel-full? 1:address:channel - ] - memory-should-contain [ - 2 <- 1 # empty? - 3 <- 0 # full? - ] -] |