about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2016-04-27 00:10:20 -0700
committerKartik K. Agaram <vc@akkartik.com>2016-04-27 00:10:20 -0700
commit5b1219ca1967d0602542a8f31f3e889837c63087 (patch)
treeb39276a08ba620cc1a826ba3f986612fae921c94
parent9109a91690e0ba2f8e094a9f92eabdae40b82481 (diff)
downloadmu-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.cc2
-rw-r--r--072channel.mu54
-rw-r--r--084console.mu1
-rw-r--r--chessboard.mu6
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