about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2015-01-25 16:40:11 -0800
committerKartik K. Agaram <vc@akkartik.com>2015-01-25 16:40:11 -0800
commit4f686be1ebb6713933298531531fbef0898c6b2b (patch)
tree3a46478c288a8b6fa835c16882363f41a5c891f4
parentd1f57fa1ab95a36a562d2b75a064bc387bd2d5d3 (diff)
downloadmu-4f686be1ebb6713933298531531fbef0898c6b2b.tar.gz
623 - 'nochange' to guard against race conditions
I dunno, this may all be a wild goose chase. I haven't been disciplined
in tagging in-out arguments in 'read-move' and its helpers. Maybe I
should just drop those 'nochange' oargs in 'read' and 'write'. Maybe I
should reserve output args only for return values that callers might
actually care about, and use more conventional metadata like 'const' or
'unique' or 'inout' on other args.
-rw-r--r--blocking.arc.t2
-rw-r--r--buffered-stdin.mu2
-rw-r--r--channel.mu4
-rw-r--r--chessboard.arc.t30
-rw-r--r--chessboard.mu6
-rw-r--r--mu.arc26
-rw-r--r--mu.arc.t76
-rw-r--r--stdin.mu2
8 files changed, 93 insertions, 55 deletions
diff --git a/blocking.arc.t b/blocking.arc.t
index e7535506..3cffb462 100644
--- a/blocking.arc.t
+++ b/blocking.arc.t
@@ -5,7 +5,7 @@
 (add-code
   '((function reader [
       (default-space:space-address <- new space:literal 30:literal/capacity)
-      (x:tagged-value 1:channel-address/space:global <- read 1:channel-address/space:global)
+      (x:tagged-value 1:channel-address/space:global/nochange <- read 1:channel-address/space:global)
      ])
     (function main [
       (default-space:space-address <- new space:literal 30:literal/capacity)
diff --git a/buffered-stdin.mu b/buffered-stdin.mu
index 3f4030b9..2e437b4e 100644
--- a/buffered-stdin.mu
+++ b/buffered-stdin.mu
@@ -15,7 +15,7 @@
     (s:string-address <- new "? ")
     (print-string nil:literal/terminal s:string-address)
     { begin
-      (x:tagged-value buffered-stdin:channel-address/deref <- read buffered-stdin:channel-address)
+      (x:tagged-value buffered-stdin:channel-address/deref/nochange <- read buffered-stdin:channel-address)
       (c:character <- maybe-coerce x:tagged-value character:literal)
 ;?       (print-primitive-to-host (("AAA " literal))) ;? 1
 ;?       (print-primitive-to-host c:character) ;? 1
diff --git a/channel.mu b/channel.mu
index 88055398..0e23db46 100644
--- a/channel.mu
+++ b/channel.mu
@@ -15,7 +15,7 @@
     ; channels take
     (n2:integer <- copy n:integer)
     (n3:tagged-value-address <- init-tagged-value integer:literal n2:integer)
-    (chan:channel-address/deref <- write chan:channel-address n3:tagged-value-address/deref)
+    (chan:channel-address/deref/nochange <- write chan:channel-address n3:tagged-value-address/deref)
     (n:integer <- add n:integer 1:literal)
     (loop)
   }
@@ -27,7 +27,7 @@
   (chan:channel-address <- next-input)
   { begin
     ; read a tagged value from the channel
-    (x:tagged-value chan:channel-address/deref <- read chan:channel-address)
+    (x:tagged-value chan:channel-address/deref/nochange <- read chan:channel-address)
     ; unbox the tagged value into an integer
     (n2:integer <- maybe-coerce x:tagged-value integer:literal)
     ; other threads might get between these prints
diff --git a/chessboard.arc.t b/chessboard.arc.t
index 78f9531a..1f93e905 100644
--- a/chessboard.arc.t
+++ b/chessboard.arc.t
@@ -10,22 +10,22 @@
       (r:integer/routine <- fork read-move:fn nil:literal/globals 2000:literal/limit stdin:channel-address)
       (c:character <- copy ((#\a literal)))
       (x:tagged-value <- save-type c:character)
-      (stdin:channel-address/deref <- write stdin:channel-address x:tagged-value)
+      (stdin:channel-address/deref/nochange <- write stdin:channel-address x:tagged-value)
       (c:character <- copy ((#\2 literal)))
       (x:tagged-value <- save-type c:character)
-      (stdin:channel-address/deref <- write stdin:channel-address x:tagged-value)
+      (stdin:channel-address/deref/nochange <- write stdin:channel-address x:tagged-value)
       (c:character <- copy ((#\- literal)))
       (x:tagged-value <- save-type c:character)
-      (stdin:channel-address/deref <- write stdin:channel-address x:tagged-value)
+      (stdin:channel-address/deref/nochange <- write stdin:channel-address x:tagged-value)
       (c:character <- copy ((#\a literal)))
       (x:tagged-value <- save-type c:character)
-      (stdin:channel-address/deref <- write stdin:channel-address x:tagged-value)
+      (stdin:channel-address/deref/nochange <- write stdin:channel-address x:tagged-value)
       (c:character <- copy ((#\4 literal)))
       (x:tagged-value <- save-type c:character)
-      (stdin:channel-address/deref <- write stdin:channel-address x:tagged-value)
+      (stdin:channel-address/deref/nochange <- write stdin:channel-address x:tagged-value)
       (c:character <- copy ((#\newline literal)))
       (x:tagged-value <- save-type c:character)
-      (stdin:channel-address/deref <- write stdin:channel-address x:tagged-value)
+      (stdin:channel-address/deref/nochange <- write stdin:channel-address x:tagged-value)
       (sleep until-routine-done:literal r:integer/routine)
      ])))
 ;? (set dump-trace*)
@@ -59,7 +59,7 @@
     (default-space:space-address <- new space:literal 30:literal/capacity)
     (c:character <- copy ((#\a literal)))
     (x:tagged-value <- save-type c:character)
-    (1:channel-address/raw/deref <- write 1:channel-address/raw x:tagged-value))
+    (1:channel-address/raw/deref/nochange <- write 1:channel-address/raw x:tagged-value))
   (wipe completed-routines*)
   ; check that read-move consumes it and then goes to sleep
   (enq read-move-routine running-routines*)
@@ -74,16 +74,16 @@
     (default-space:space-address <- new space:literal 30:literal/capacity)
     (c:character <- copy ((#\2 literal)))
     (x:tagged-value <- save-type c:character)
-    (1:channel-address/raw/deref <- write 1:channel-address/raw x:tagged-value)
+    (1:channel-address/raw/deref/nochange <- write 1:channel-address/raw x:tagged-value)
     (c:character <- copy ((#\- literal)))
     (x:tagged-value <- save-type c:character)
-    (1:channel-address/raw/deref <- write 1:channel-address/raw x:tagged-value)
+    (1:channel-address/raw/deref/nochange <- write 1:channel-address/raw x:tagged-value)
     (c:character <- copy ((#\a literal)))
     (x:tagged-value <- save-type c:character)
-    (1:channel-address/raw/deref <- write 1:channel-address/raw x:tagged-value)
+    (1:channel-address/raw/deref/nochange <- write 1:channel-address/raw x:tagged-value)
     (c:character <- copy ((#\4 literal)))
     (x:tagged-value <- save-type c:character)
-    (1:channel-address/raw/deref <- write 1:channel-address/raw x:tagged-value))
+    (1:channel-address/raw/deref/nochange <- write 1:channel-address/raw x:tagged-value))
   ; check that read-move consumes them and then goes to sleep
   (when (ran-to-completion 'read-move)
     (prn "F - chessboard waits after each subsequent letter of move until the last"))
@@ -96,7 +96,7 @@
     (default-space:space-address <- new space:literal 30:literal/capacity)
     (c:character <- copy ((#\newline literal)))
     (x:tagged-value <- save-type c:character)
-    (1:channel-address/raw/deref <- write 1:channel-address/raw x:tagged-value))
+    (1:channel-address/raw/deref/nochange <- write 1:channel-address/raw x:tagged-value))
   ; check that read-move consumes it and -- this time -- returns
   (when (~ran-to-completion 'read-move)
     (prn "F - 'read-move' completes after final letter of move"))
@@ -113,7 +113,7 @@
       (r:integer/routine <- fork-helper read-move:fn nil:literal/globals 2000:literal/limit stdin:channel-address dummy:terminal-address)
       (c:character <- copy ((#\q literal)))
       (x:tagged-value <- save-type c:character)
-      (stdin:channel-address/deref <- write stdin:channel-address x:tagged-value)
+      (stdin:channel-address/deref/nochange <- write stdin:channel-address x:tagged-value)
       (sleep until-routine-done:literal r:integer/routine)
      ])))
 (run 'main)
@@ -131,7 +131,7 @@
       (r:integer/routine <- fork-helper read-file:fn nil:literal/globals 2000:literal/limit stdin:channel-address dummy:terminal-address)
       (c:character <- copy ((#\i literal)))
       (x:tagged-value <- save-type c:character)
-      (stdin:channel-address/deref <- write stdin:channel-address x:tagged-value)
+      (stdin:channel-address/deref/nochange <- write stdin:channel-address x:tagged-value)
       (sleep until-routine-done:literal r:integer/routine)
      ])))
 ;? (= dump-trace* (obj whitelist '("schedule")))
@@ -154,7 +154,7 @@
       (r:integer/routine <- fork-helper read-rank:fn nil:literal/globals 2000:literal/limit stdin:channel-address dummy:terminal-address)
       (c:character <- copy ((#\9 literal)))
       (x:tagged-value <- save-type c:character)
-      (stdin:channel-address/deref <- write stdin:channel-address x:tagged-value)
+      (stdin:channel-address/deref/nochange <- write stdin:channel-address x:tagged-value)
       (sleep until-routine-done:literal r:integer/routine)
      ])))
 (run 'main)
diff --git a/chessboard.mu b/chessboard.mu
index b26401ab..8177a403 100644
--- a/chessboard.mu
+++ b/chessboard.mu
@@ -127,7 +127,7 @@
 (function read-file [
   (default-space:space-address <- new space:literal 30:literal)
   (stdin:channel-address <- next-input)
-  (x:tagged-value stdin:channel-address/deref <- read stdin:channel-address)
+  (x:tagged-value stdin:channel-address/deref/nochange <- read stdin:channel-address)
 ;?   (print-primitive-to-host x:tagged-value) ;? 1
 ;?   (print-primitive-to-host (("\n" literal))) ;? 1
   (a:character <- copy ((#\a literal)))
@@ -154,7 +154,7 @@
 (function read-rank [
   (default-space:space-address <- new space:literal 30:literal)
   (stdin:channel-address <- next-input)
-  (x:tagged-value stdin:channel-address/deref <- read stdin:channel-address)
+  (x:tagged-value stdin:channel-address/deref/nochange <- read stdin:channel-address)
   (c:character <- maybe-coerce x:tagged-value character:literal)
 ;?   (print-primitive-to-host (("BBB " literal))) ;? 1
 ;?   (print-primitive-to-host c:character) ;? 1
@@ -180,7 +180,7 @@
 (function expect-stdin [
   (default-space:space-address <- new space:literal 30:literal)
   (stdin:channel-address <- next-input)
-  (x:tagged-value stdin:channel-address/deref <- read stdin:channel-address)
+  (x:tagged-value stdin:channel-address/deref/nochange <- read stdin:channel-address)
   (c:character <- maybe-coerce x:tagged-value character:literal)
   (expected:character <- next-input)
   (match?:boolean <- equal c:character expected:character)
diff --git a/mu.arc b/mu.arc
index b06d402f..ca4b0216 100644
--- a/mu.arc
+++ b/mu.arc
@@ -267,6 +267,8 @@
 
 (mac results (routine)  ; assignable
   `((((rep ,routine) 'call-stack) 0) 'results))
+(mac reply-args(routine)  ; assignable
+  `((((rep ,routine) 'call-stack) 0) 'reply-args))
 
 (def waiting-for-exact-cycle? (routine)
   (is 'until rep.routine!sleep.0))
@@ -794,13 +796,18 @@
                 reply
                   (do (when arg
                         (prepare-reply arg))
-                      (let results results.routine*
+                      (with (results results.routine*
+                             reply-args reply-args.routine*)
                         (pop-stack routine*)
                         (if empty.routine* (return ninstrs))
                         (let (caller-oargs _ _)  (parse-instr (body.routine* pc.routine*))
                           (trace "reply" repr.arg " " repr.caller-oargs)
-                          (each (dest val)  (zip caller-oargs results)
+                          (each (dest reply-arg val)  (zip caller-oargs reply-args results)
+;?                             (prn dest " / " reply-arg " => " val) ;? 1
                             (when nondummy.dest
+                              (when (pos '(nochange) metadata.reply-arg)
+                                (unless (is dest (m reply-arg))
+                                  (die "'nochange' arg in @repr.reply-args can't bind to @repr.caller-oargs")))
                               (trace "reply" repr.val " => " dest)
                               (setm dest val))))
                         (++ pc.routine*)
@@ -845,7 +852,8 @@
   (= results.routine*
      (accum yield
        (each a args
-         (yield (m a))))))
+         (yield (m a)))))
+  (= reply-args.routine* args))
 
 ; helpers for memory access respecting
 ;   immediate addressing - 'literal' and 'offset'
@@ -2038,15 +2046,15 @@
   (stdin:channel-address <- next-input)
 ;?   (c:character <- copy ((#\a literal))) ;? 1
 ;?   (curr:tagged-value <- save-type c:character) ;? 1
-;?   (stdin:channel-address/deref <- write stdin:channel-address curr:tagged-value) ;? 1
+;?   (stdin:channel-address/deref/nochange <- write stdin:channel-address curr:tagged-value) ;? 1
 ;?   (c:character <- copy ((#\newline literal))) ;? 1
 ;?   (curr:tagged-value <- save-type c:character) ;? 1
-;?   (stdin:channel-address/deref <- write stdin:channel-address curr:tagged-value) ;? 1
+;?   (stdin:channel-address/deref/nochange <- write stdin:channel-address curr:tagged-value) ;? 1
   { begin ;? 1
     (c:character <- read-key k:keyboard-address) ;? 1
     (loop-unless c:character) ;? 1
     (curr:tagged-value <- save-type c:character) ;? 1
-    (stdin:channel-address/deref <- write stdin:channel-address curr:tagged-value) ;? 1
+    (stdin:channel-address/deref/nochange <- write stdin:channel-address curr:tagged-value) ;? 1
     (eof?:boolean <- equal c:character ((#\null literal))) ;? 1
     (break-if eof?:boolean) ;? 1
     (loop) ;? 1
@@ -2063,7 +2071,7 @@
 ;?     ($dump-channel 1093:literal) ;? 1
     ; read characters from stdin until newline, copy into line
     { begin
-      (x:tagged-value stdin:channel-address/deref <- read stdin:channel-address)
+      (x:tagged-value stdin:channel-address/deref/nochange <- read stdin:channel-address)
       (c:character <- maybe-coerce x:tagged-value character:literal)
       (assert c:character)
 ;?       (print-primitive-to-host line:buffer-address) ;? 1
@@ -2095,7 +2103,7 @@
       (curr:tagged-value <- save-type c:character)
 ;?       ($dump-channel 1093:literal) ;? 1
 ;?       ($start-tracing) ;? 1
-      (buffered-stdin:channel-address/deref <- write buffered-stdin:channel-address curr:tagged-value)
+      (buffered-stdin:channel-address/deref/nochange <- write buffered-stdin:channel-address curr:tagged-value)
 ;?       ($stop-tracing) ;? 1
 ;?       ($dump-channel 1093:literal) ;? 1
 ;?       ($quit) ;? 1
@@ -2345,7 +2353,7 @@
   (screen:terminal-address <- next-input)
   (stdout:channel-address <- next-input)
   { begin
-    (x:tagged-value stdout:channel-address/deref <- read stdout:channel-address)
+    (x:tagged-value stdout:channel-address/deref/nochange <- read stdout:channel-address)
     (c:character <- maybe-coerce x:tagged-value character:literal)
     (done?:boolean <- equal c:character ((#\null literal)))
     (break-if done?:boolean)
diff --git a/mu.arc.t b/mu.arc.t
index 9c321af6..f6ba0534 100644
--- a/mu.arc.t
+++ b/mu.arc.t
@@ -1321,6 +1321,7 @@
                          4 1  5 3  6 4))
   (prn "F - 'reply' permits a function to return multiple values at once"))
 
+; 'prepare-reply' is useful for doing cleanup before exiting a function
 (reset)
 (new-trace "new-fn-prepare-reply")
 (add-code
@@ -1344,6 +1345,35 @@
                          4 1  5 3  6 4))
   (prn "F - without args, 'reply' returns values from previous 'prepare-reply'."))
 
+; When you have arguments that are both read from and written to, include them
+; redundantly in both ingredients and results. That'll help tools track what
+; changed.
+
+; To enforce that the result and ingredient must always match, use the
+; 'nochange' property. Results with 'nochange' properties should only be
+; copied to themselves.
+(reset)
+(new-trace "new-fn-nochange")
+(add-code
+  '((function test1 [
+      ; increment the contents of an address
+      (default-space:space-address <- new space:literal 2:literal)
+      (x:integer-address <- next-input)
+      (x:integer-address/deref <- add x:integer-address/deref 1:literal)
+      (reply x:integer-address/nochange)
+    ])
+    (function main [
+      (1:integer-address <- new integer:literal)
+      (1:integer-address/deref <- copy 0:literal)
+      (2:integer-address <- test1 1:integer-address)
+    ])))
+(run 'main)
+(let routine (car completed-routines*)
+;?   (prn rep.routine!error) ;? 1
+  (when (no rep.routine!error)
+    (prn "F - 'nochange' results are never copied to other locations")))
+;? (quit) ;? 1
+
 )  ; section 20
 
 (section 11
@@ -3039,7 +3069,7 @@
       (1:channel-address <- init-channel 3:literal)
       (2:integer <- copy 34:literal)
       (3:tagged-value <- save-type 2:integer)
-      (1:channel-address/deref <- write 1:channel-address 3:tagged-value)
+      (1:channel-address/deref/nochange <- write 1:channel-address 3:tagged-value)
       (5:integer <- get 1:channel-address/deref first-full:offset)
       (6:integer <- get 1:channel-address/deref first-free:offset)
      ])))
@@ -3064,8 +3094,8 @@
       (1:channel-address <- init-channel 3:literal)
       (2:integer <- copy 34:literal)
       (3:tagged-value <- save-type 2:integer)
-      (1:channel-address/deref <- write 1:channel-address 3:tagged-value)
-      (5:tagged-value 1:channel-address/deref <- read 1:channel-address)
+      (1:channel-address/deref/nochange <- write 1:channel-address 3:tagged-value)
+      (5:tagged-value 1:channel-address/deref/nochange <- read 1:channel-address)
       (7:integer <- maybe-coerce 5:tagged-value integer:literal)
       (8:integer <- get 1:channel-address/deref first-full:offset)
       (9:integer <- get 1:channel-address/deref first-free:offset)
@@ -3089,13 +3119,13 @@
       ; write a value
       (2:integer <- copy 34:literal)
       (3:tagged-value <- save-type 2:integer)
-      (1:channel-address/deref <- write 1:channel-address 3:tagged-value)
+      (1:channel-address/deref/nochange <- write 1:channel-address 3:tagged-value)
       ; first-free will now be 1
       (5:integer <- get 1:channel-address/deref first-free:offset)
       ; read one value
-      (_ 1:channel-address/deref <- read 1:channel-address)
+      (_ 1:channel-address/deref/nochange <- read 1:channel-address)
       ; write a second value; verify that first-free wraps around to 0.
-      (1:channel-address/deref <- write 1:channel-address 3:tagged-value)
+      (1:channel-address/deref/nochange <- write 1:channel-address 3:tagged-value)
       (6:integer <- get 1:channel-address/deref first-free:offset)
      ])))
 ;? (set dump-trace*)
@@ -3115,15 +3145,15 @@
       ; write a value
       (2:integer <- copy 34:literal)
       (3:tagged-value <- save-type 2:integer)
-      (1:channel-address/deref <- write 1:channel-address 3:tagged-value)
+      (1:channel-address/deref/nochange <- write 1:channel-address 3:tagged-value)
       ; read one value
-      (_ 1:channel-address/deref <- read 1:channel-address)
+      (_ 1:channel-address/deref/nochange <- read 1:channel-address)
       ; first-full will now be 1
       (5:integer <- get 1:channel-address/deref first-full:offset)
       ; write a second value
-      (1:channel-address/deref <- write 1:channel-address 3:tagged-value)
+      (1:channel-address/deref/nochange <- write 1:channel-address 3:tagged-value)
       ; read second value; verify that first-full wraps around to 0.
-      (_ 1:channel-address/deref <- read 1:channel-address)
+      (_ 1:channel-address/deref/nochange <- read 1:channel-address)
       (6:integer <- get 1:channel-address/deref first-full:offset)
      ])))
 ;? (set dump-trace*)
@@ -3156,7 +3186,7 @@
       (1:channel-address <- init-channel 3:literal)
       (2:integer <- copy 34:literal)
       (3:tagged-value <- save-type 2:integer)
-      (1:channel-address/deref <- write 1:channel-address 3:tagged-value)
+      (1:channel-address/deref/nochange <- write 1:channel-address 3:tagged-value)
       (5:boolean <- empty? 1:channel-address/deref)
       (6:boolean <- full? 1:channel-address/deref)
      ])))
@@ -3174,7 +3204,7 @@
       (1:channel-address <- init-channel 1:literal)
       (2:integer <- copy 34:literal)
       (3:tagged-value <- save-type 2:integer)
-      (1:channel-address/deref <- write 1:channel-address 3:tagged-value)
+      (1:channel-address/deref/nochange <- write 1:channel-address 3:tagged-value)
       (5:boolean <- empty? 1:channel-address/deref)
       (6:boolean <- full? 1:channel-address/deref)
      ])))
@@ -3192,9 +3222,9 @@
       (1:channel-address <- init-channel 3:literal)
       (2:integer <- copy 34:literal)
       (3:tagged-value <- save-type 2:integer)
-      (1:channel-address/deref <- write 1:channel-address 3:tagged-value)
-      (1:channel-address/deref <- write 1:channel-address 3:tagged-value)
-      (_ 1:channel-address/deref <- read 1:channel-address)
+      (1:channel-address/deref/nochange <- write 1:channel-address 3:tagged-value)
+      (1:channel-address/deref/nochange <- write 1:channel-address 3:tagged-value)
+      (_ 1:channel-address/deref/nochange <- read 1:channel-address)
       (5:boolean <- empty? 1:channel-address/deref)
       (6:boolean <- full? 1:channel-address/deref)
      ])))
@@ -3213,7 +3243,7 @@
       (2:integer <- copy 34:literal)
       (3:tagged-value <- save-type 2:integer)
       (1:channel-address/deref <- write 1:channel-address 3:tagged-value)
-      (_ 1:channel-address/deref <- read 1:channel-address)
+      (_ 1:channel-address/deref/nochange <- read 1:channel-address)
       (5:boolean <- empty? 1:channel-address/deref)
       (6:boolean <- full? 1:channel-address/deref)
      ])))
@@ -3233,7 +3263,7 @@
   '((function main [
       (1:channel-address <- init-channel 3:literal)
       ; channel is empty, but receives a read
-      (2:tagged-value 1:channel-address/deref <- read 1:channel-address)
+      (2:tagged-value 1:channel-address/deref/nochange <- read 1:channel-address)
      ])))
 ;? (set dump-trace*)
 ;? (= dump-trace* (obj whitelist '("run" "schedule")))
@@ -3257,9 +3287,9 @@
       (1:channel-address <- init-channel 1:literal)
       (2:integer <- copy 34:literal)
       (3:tagged-value <- save-type 2:integer)
-      (1:channel-address/deref <- write 1:channel-address 3:tagged-value)
+      (1:channel-address/deref/nochange <- write 1:channel-address 3:tagged-value)
       ; channel has capacity 1, but receives a second write
-      (1:channel-address/deref <- write 1:channel-address 3:tagged-value)
+      (1:channel-address/deref/nochange <- write 1:channel-address 3:tagged-value)
      ])))
 ;? (set dump-trace*)
 ;? (= dump-trace* (obj whitelist '("run" "schedule" "addr")))
@@ -3284,14 +3314,14 @@
       (default-space:space-address <- new space:literal 30:literal)
       (chan:channel-address <- init-channel 3:literal)  ; create a channel
       (fork producer:fn nil:literal/globals nil:literal/limit chan:channel-address)  ; fork a routine to produce a value in it
-      (1:tagged-value/raw <- read chan:channel-address)  ; wait for input on channel
+      (1:tagged-value/raw/nochange <- read chan:channel-address)  ; wait for input on channel
      ])
     (function producer [
       (default-space:space-address <- new space:literal 30:literal)
       (n:integer <- copy 24:literal)
       (ochan:channel-address <- next-input)
       (x:tagged-value <- save-type n:integer)
-      (ochan:channel-address/deref <- write ochan:channel-address x:tagged-value)
+      (ochan:channel-address/deref/nochange <- write ochan:channel-address x:tagged-value)
      ])))
 ;? (set dump-trace*)
 ;? (= dump-trace* (obj whitelist '("schedule" "run" "addr")))
@@ -3311,13 +3341,13 @@
       (default-space:space-address <- new space:literal 30:literal)
       (1:channel-address <- init-channel 3:literal)  ; create a channel
       (fork producer:fn default-space:space-address/globals nil:literal/limit)  ; pass it as a global to another routine
-      (1:tagged-value/raw <- read 1:channel-address)  ; wait for input on channel
+      (1:tagged-value/raw/nochange <- read 1:channel-address)  ; wait for input on channel
      ])
     (function producer [
       (default-space:space-address <- new space:literal 30:literal)
       (n:integer <- copy 24:literal)
       (x:tagged-value <- save-type n:integer)
-      (1:channel-address/space:global/deref <- write 1:channel-address/space:global x:tagged-value)
+      (1:channel-address/space:global/deref/nochange <- write 1:channel-address/space:global x:tagged-value)
      ])))
 (run 'consumer)
 (each routine completed-routines*
diff --git a/stdin.mu b/stdin.mu
index 4ffded52..a8c41182 100644
--- a/stdin.mu
+++ b/stdin.mu
@@ -14,7 +14,7 @@
   ; now read characters from stdin until a 'q' is typed
   (print-primitive-to-host (("? " literal)))
   { begin
-    (x:tagged-value stdin:channel-address/deref <- read stdin:channel-address)
+    (x:tagged-value stdin:channel-address/deref/nochange <- read stdin:channel-address)
     (c:character <- maybe-coerce x:tagged-value character:literal)
 ;?     (print-primitive-to-host (("main: stdin is " literal)))
 ;?     (print-primitive-to-host stdin:channel-address)