diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2016-04-27 00:10:20 -0700 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2016-04-27 00:10:20 -0700 |
commit | 5b1219ca1967d0602542a8f31f3e889837c63087 (patch) | |
tree | b39276a08ba620cc1a826ba3f986612fae921c94 | |
parent | 9109a91690e0ba2f8e094a9f92eabdae40b82481 (diff) | |
download | mu-5b1219ca1967d0602542a8f31f3e889837c63087.tar.gz |
2870 - fix the final long-standing failing test
The solution for avoiding deadlock is for routines to close channels before they exit. So that's good. Once I implemented 'close', I also found and fixed 2 unrelated bugs in chessboard.mu: a) one long-missed and long-masked case of forgetting to store character literals in character variables b) one typo in translating get-address to put So that's good. What's not so good: in the process of fixing this I've found three unrelated bugs (marked 'BUG:' in the changes). All three have workarounds, so existing tests pass for now. But they are my top priority next.
-rw-r--r-- | 057shape_shifting_container.cc | 2 | ||||
-rw-r--r-- | 072channel.mu | 54 | ||||
-rw-r--r-- | 084console.mu | 1 | ||||
-rw-r--r-- | chessboard.mu | 6 |
4 files changed, 60 insertions, 3 deletions
diff --git a/057shape_shifting_container.cc b/057shape_shifting_container.cc index d5eacbc2..036302af 100644 --- a/057shape_shifting_container.cc +++ b/057shape_shifting_container.cc @@ -85,7 +85,7 @@ void read_type_ingredients(string& name) { while (has_data(in)) { string curr = slurp_until(in, ':'); if (info.type_ingredient_names.find(curr) != info.type_ingredient_names.end()) { - raise << "can't repeat type ingredient names in a single container definition\n" << end(); + raise << "can't repeat type ingredient names in a single container definition: " << curr << '\n' << end(); return; } put(info.type_ingredient_names, curr, next_type_ordinal++); diff --git a/072channel.mu b/072channel.mu index e1d6f805..7af7353e 100644 --- a/072channel.mu +++ b/072channel.mu @@ -61,6 +61,10 @@ def write out:address:sink:_elem, val:_elem -> out:address:sink:_elem [ local-scope load-ingredients chan:address:channel:_elem <- get *out, chan:offset + <channel-write-initial> + # BUG: delete next 2 lines after enabling the tangle directives below + closed?:boolean <- get *chan, closed?:offset + reply-if closed? { # block if chan is full full:boolean <- channel-full? chan @@ -94,6 +98,10 @@ def read in:address:source:_elem -> result:_elem, in:address:source:_elem [ # block if chan is empty empty?:boolean <- channel-empty? chan break-unless empty? + <channel-read-empty> + # BUG: delete next 2 lines after enabling the tangle directives below + closed?:boolean <- get *chan, closed?:offset + reply-if closed?, 0 # hack, will only work for scalar _elem; we need a method to clear arbitrary types free-address:location <- get-location *chan, first-free:offset wait-for-location free-address } @@ -250,6 +258,47 @@ scenario channel-read-not-full [ ] ] +## cancelling channels + +# every channel comes with a boolean signifying if it's been closed +# initially this boolean is false +# BUG: can't yet include type ingredients when extending containers +container channel [ + closed?:boolean +] + +# a channel can be closed from either the source or the sink +# both threads can modify it, but they can only set it, so this is a benign race +def close x:address:source:_elem -> x:address:source:_elem [ + local-scope + load-ingredients + chan:address:channel:_elem <- get *x, chan:offset + *chan <- put *chan, closed?:offset, 1/true +] +def close x:address:sink:_elem -> x:address:sink:_elem [ + local-scope + load-ingredients + chan:address:channel:_elem <- get *x, chan:offset + *chan <- put *chan, closed?:offset, 1/true +] + +# once a channel is closed from one side, no further operations are expected from that side +# if a channel is closed for reading, +# no further writes will be let through +# if a channel is closed for writing, +# future reads continue until the channel empties, +# then the channel is also closed for reading +# BUG: tangle directives don't work for some reason +#? after <channel-write-initial> [ +#? closed?:boolean <- get *chan, closed?:offset +#? reply-if closed? +#? ] +#? +#? after <channel-read-empty> [ +#? closed?:boolean <- get *chan, closed?:offset +#? reply-if closed? +#? ] + ## helpers # An empty channel has first-empty and first-full both at the same value. @@ -337,6 +386,11 @@ def buffer-lines in:address:source:character, buffered-out:address:sink:characte i <- add i, 1 loop } + { + break-unless eof? + buffered-out <- close buffered-out + reply + } loop } ] diff --git a/084console.mu b/084console.mu index d2259b65..e736642f 100644 --- a/084console.mu +++ b/084console.mu @@ -82,6 +82,7 @@ def send-keys-to-channel console:address:console, chan:address:sink:character, s chan <- write chan, c loop } + chan <- close chan ] def wait-for-event console:address:console -> console:address:console [ diff --git a/chessboard.mu b/chessboard.mu index 0e13afce..3d6b93e2 100644 --- a/chessboard.mu +++ b/chessboard.mu @@ -35,7 +35,8 @@ scenario print-board-and-read-move [ run [ screen:address:screen, console:address:console <- chessboard screen:address:screen, console:address:console # icon for the cursor - screen <- print screen, 9251/␣ + 1:character/cursor-icon <- copy 9251/␣ + screen <- print screen, 1:character/cursor-icon ] screen-should-contain [ # 1 2 3 4 5 6 7 8 9 10 11 @@ -255,9 +256,10 @@ def read-move stdin:address:source:character, screen:address:screen -> result:ad to-rank:number, quit?, error? <- read-rank stdin, screen return-if quit?, 0/dummy return-if error?, 0/dummy - *result <- put *result, to-rank:offset, to-file + *result <- put *result, to-rank:offset, to-rank error? <- expect-from-channel stdin, 10/newline, screen return-if error?, 0/dummy, 0/quit + return result # BUG: why is this statement required? ] # valid values for file: 0-7 |