diff options
Diffstat (limited to 'html/073wait.cc.html')
-rw-r--r-- | html/073wait.cc.html | 314 |
1 files changed, 215 insertions, 99 deletions
diff --git a/html/073wait.cc.html b/html/073wait.cc.html index 926c6b29..b99b8cc5 100644 --- a/html/073wait.cc.html +++ b/html/073wait.cc.html @@ -16,6 +16,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color .Constant { color: #00a0a0; } .cSpecial { color: #008000; } .traceContains { color: #008000; } +.SalientComment { color: #00ffff; } .Comment { color: #9090ff; } .Delimiter { color: #800080; } .Special { color: #c00000; } @@ -40,18 +41,22 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color <span class="Delimiter">:(scenario wait_for_location)</span> def f1 [ - <span class="Constant">1</span>:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Constant">10</span>:number<span class="Special"> <- </span>copy <span class="Constant">34</span> start-running f2 - <span class="Constant">2</span>:location<span class="Special"> <- </span>copy <span class="Constant">1</span>/unsafe - wait-<span class="Normal">for</span>-location <span class="Constant">2</span>:location - <span class="Comment"># now wait for f2 to run and modify location 1 before using its value</span> - <span class="Constant">3</span>:number<span class="Special"> <- </span>copy <span class="Constant">1</span>:number + <span class="Constant">20</span>:location<span class="Special"> <- </span>copy <span class="Constant">10</span>/unsafe + wait-<span class="Normal">for</span>-reset-then-set <span class="Constant">20</span>:location + <span class="Comment"># wait for f2 to run and reset location 1</span> + <span class="Constant">30</span>:number<span class="Special"> <- </span>copy <span class="Constant">10</span>:number ] def f2 [ - <span class="Constant">1</span>:number<span class="Special"> <- </span>copy <span class="Constant">34</span> + <span class="Constant">10</span>:location<span class="Special"> <- </span>copy <span class="Constant">0</span>/unsafe ] -<span class="Comment"># if we got the synchronization wrong we'd be storing 0 in location 3</span> -<span class="traceContains">+mem: storing 34 in location 3</span> +<span class="traceContains">+schedule: f1</span> +<span class="traceContains">+run: waiting for location 10 to reset</span> +<span class="traceContains">+schedule: f2</span> +<span class="traceContains">+schedule: waking up routine 1</span> +<span class="traceContains">+schedule: f1</span> +<span class="traceContains">+mem: storing 1 in location 30</span> <span class="Comment">//: define the new state that all routines can be in</span> @@ -60,9 +65,8 @@ WAITING<span class="Delimiter">,</span> <span class="Delimiter">:(before "End routine Fields")</span> <span class="Comment">// only if state == WAITING</span> <span class="Normal">int</span> waiting_on_location<span class="Delimiter">;</span> -<span class="Normal">int</span> old_value_of_waiting_location<span class="Delimiter">;</span> <span class="Delimiter">:(before "End routine Constructor")</span> -waiting_on_location = old_value_of_waiting_location = <span class="Constant">0</span><span class="Delimiter">;</span> +waiting_on_location = <span class="Constant">0</span><span class="Delimiter">;</span> <span class="Delimiter">:(before "End Mu Test Teardown")</span> <span class="Normal">if</span> <span class="Delimiter">(</span>Passed && any_routines_waiting<span class="Delimiter">())</span> <span class="Delimiter">{</span> @@ -94,30 +98,61 @@ waiting_on_location = old_value_of_waiting_location = <span class="Constant">0</ <span class="Delimiter">}</span> <span class="Delimiter">}</span> -<span class="Comment">//: primitive recipe to put routines in that state</span> +<span class="Comment">//: Primitive recipe to put routines in that state.</span> +<span class="Comment">//: This primitive is also known elsewhere as compare-and-set (CAS). Used to</span> +<span class="Comment">//: build locks.</span> <span class="Delimiter">:(before "End Primitive Recipe Declarations")</span> -WAIT_FOR_LOCATION<span class="Delimiter">,</span> +WAIT_FOR_RESET_THEN_SET<span class="Delimiter">,</span> <span class="Delimiter">:(before "End Primitive Recipe Numbers")</span> -put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span> <span class="Constant">"wait-for-location"</span><span class="Delimiter">,</span> WAIT_FOR_LOCATION<span class="Delimiter">);</span> +put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span> <span class="Constant">"wait-for-reset-then-set"</span><span class="Delimiter">,</span> WAIT_FOR_RESET_THEN_SET<span class="Delimiter">);</span> <span class="Delimiter">:(before "End Primitive Recipe Checks")</span> -<span class="Normal">case</span> WAIT_FOR_LOCATION: <span class="Delimiter">{</span> +<span class="Normal">case</span> WAIT_FOR_RESET_THEN_SET: <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">)</span> != <span class="Constant">1</span><span class="Delimiter">)</span> <span class="Delimiter">{</span> - raise << maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> << <span class="Constant">"'wait-for-location' requires exactly one ingredient, but got '"</span> << inst<span class="Delimiter">.</span>original_string << <span class="Constant">"'</span><span class="cSpecial">\n</span><span class="Constant">"</span> << end<span class="Delimiter">();</span> + raise << maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> << <span class="Constant">"'wait-for-reset-then-set' requires exactly one ingredient, but got '"</span> << inst<span class="Delimiter">.</span>original_string << <span class="Constant">"'</span><span class="cSpecial">\n</span><span class="Constant">"</span> << end<span class="Delimiter">();</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Normal">if</span> <span class="Delimiter">(</span>!is_mu_location<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)))</span> <span class="Delimiter">{</span> - raise << maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> << <span class="Constant">"'wait-for-location' requires a location ingredient, but got '"</span> << inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>original_string << <span class="Constant">"'</span><span class="cSpecial">\n</span><span class="Constant">"</span> << end<span class="Delimiter">();</span> + raise << maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> << <span class="Constant">"'wait-for-reset-then-set' requires a location ingredient, but got '"</span> << inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>original_string << <span class="Constant">"'</span><span class="cSpecial">\n</span><span class="Constant">"</span> << end<span class="Delimiter">();</span> <span class="Delimiter">}</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">:(before "End Primitive Recipe Implementations")</span> -<span class="Normal">case</span> WAIT_FOR_LOCATION: <span class="Delimiter">{</span> - <span class="Normal">int</span> loc = ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">);</span> +<span class="Normal">case</span> WAIT_FOR_RESET_THEN_SET: <span class="Delimiter">{</span> + <span class="Normal">int</span> loc = <span class="Normal">static_cast</span><<span class="Normal">int</span>><span class="Delimiter">(</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">));</span> + trace<span class="Delimiter">(</span><span class="Constant">9998</span><span class="Delimiter">,</span> <span class="Constant">"run"</span><span class="Delimiter">)</span> << <span class="Constant">"wait: *"</span> << loc << <span class="Constant">" = "</span> << get_or_insert<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> loc<span class="Delimiter">)</span> << end<span class="Delimiter">();</span> + <span class="Normal">if</span> <span class="Delimiter">(</span>get_or_insert<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> loc<span class="Delimiter">)</span> == <span class="Constant">0</span><span class="Delimiter">)</span> <span class="Delimiter">{</span> + trace<span class="Delimiter">(</span><span class="Constant">9998</span><span class="Delimiter">,</span> <span class="Constant">"run"</span><span class="Delimiter">)</span> << <span class="Constant">"location "</span> << loc << <span class="Constant">" is already 0; setting"</span> << end<span class="Delimiter">();</span> + put<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> loc<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span> + <span class="Identifier">break</span><span class="Delimiter">;</span> + <span class="Delimiter">}</span> + trace<span class="Delimiter">(</span><span class="Constant">9998</span><span class="Delimiter">,</span> <span class="Constant">"run"</span><span class="Delimiter">)</span> << <span class="Constant">"waiting for location "</span> << loc << <span class="Constant">" to reset"</span> << end<span class="Delimiter">();</span> Current_routine<span class="Delimiter">-></span>state = WAITING<span class="Delimiter">;</span> Current_routine<span class="Delimiter">-></span>waiting_on_location = loc<span class="Delimiter">;</span> - Current_routine<span class="Delimiter">-></span>old_value_of_waiting_location = get_or_insert<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> loc<span class="Delimiter">);</span> - trace<span class="Delimiter">(</span><span class="Constant">9998</span><span class="Delimiter">,</span> <span class="Constant">"run"</span><span class="Delimiter">)</span> << <span class="Constant">"waiting for location "</span> << loc << <span class="Constant">" to change from "</span> << no_scientific<span class="Delimiter">(</span>get_or_insert<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> loc<span class="Delimiter">))</span> << end<span class="Delimiter">();</span> + <span class="Identifier">break</span><span class="Delimiter">;</span> +<span class="Delimiter">}</span> + +<span class="Comment">//: Counterpart to unlock a lock.</span> +<span class="Delimiter">:(before "End Primitive Recipe Declarations")</span> +RESET<span class="Delimiter">,</span> +<span class="Delimiter">:(before "End Primitive Recipe Numbers")</span> +put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span> <span class="Constant">"reset"</span><span class="Delimiter">,</span> RESET<span class="Delimiter">);</span> +<span class="Delimiter">:(before "End Primitive Recipe Checks")</span> +<span class="Normal">case</span> RESET: <span class="Delimiter">{</span> + <span class="Normal">if</span> <span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">)</span> != <span class="Constant">1</span><span class="Delimiter">)</span> <span class="Delimiter">{</span> + raise << maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> << <span class="Constant">"'reset' requires exactly one ingredient, but got '"</span> << inst<span class="Delimiter">.</span>original_string << <span class="Constant">"'</span><span class="cSpecial">\n</span><span class="Constant">"</span> << end<span class="Delimiter">();</span> + <span class="Identifier">break</span><span class="Delimiter">;</span> + <span class="Delimiter">}</span> + <span class="Normal">if</span> <span class="Delimiter">(</span>!is_mu_location<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)))</span> <span class="Delimiter">{</span> + raise << maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> << <span class="Constant">"'reset' requires a location ingredient, but got '"</span> << inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>original_string << <span class="Constant">"'</span><span class="cSpecial">\n</span><span class="Constant">"</span> << end<span class="Delimiter">();</span> + <span class="Delimiter">}</span> + <span class="Identifier">break</span><span class="Delimiter">;</span> +<span class="Delimiter">}</span> +<span class="Delimiter">:(before "End Primitive Recipe Implementations")</span> +<span class="Normal">case</span> RESET: <span class="Delimiter">{</span> + <span class="Normal">int</span> loc = <span class="Normal">static_cast</span><<span class="Normal">int</span>><span class="Delimiter">(</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">));</span> + put<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> loc<span class="Delimiter">,</span> <span class="Constant">0</span><span class="Delimiter">);</span> + trace<span class="Delimiter">(</span><span class="Constant">9998</span><span class="Delimiter">,</span> <span class="Constant">"run"</span><span class="Delimiter">)</span> << <span class="Constant">"reset: *"</span> << loc << <span class="Constant">" = "</span> << get_or_insert<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> loc<span class="Delimiter">)</span> << end<span class="Delimiter">();</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> @@ -126,17 +161,18 @@ put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span <span class="Delimiter">:(before "End Scheduler State Transitions")</span> <span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> i = <span class="Constant">0</span><span class="Delimiter">;</span> i < SIZE<span class="Delimiter">(</span>Routines<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>Routines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)-></span>state != WAITING<span class="Delimiter">)</span> <span class="Identifier">continue</span><span class="Delimiter">;</span> - <span class="Normal">if</span> <span class="Delimiter">(</span>Routines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)-></span>waiting_on_location && - get_or_insert<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> Routines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)-></span>waiting_on_location<span class="Delimiter">)</span> != Routines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)-></span>old_value_of_waiting_location<span class="Delimiter">)</span> <span class="Delimiter">{</span> - trace<span class="Delimiter">(</span><span class="Constant">9999</span><span class="Delimiter">,</span> <span class="Constant">"schedule"</span><span class="Delimiter">)</span> << <span class="Constant">"waking up routine</span><span class="cSpecial">\n</span><span class="Constant">"</span> << end<span class="Delimiter">();</span> + <span class="Normal">int</span> loc = Routines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)-></span>waiting_on_location<span class="Delimiter">;</span> + <span class="Normal">if</span> <span class="Delimiter">(</span>loc && get_or_insert<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> loc<span class="Delimiter">)</span> == <span class="Constant">0</span><span class="Delimiter">)</span> <span class="Delimiter">{</span> + trace<span class="Delimiter">(</span><span class="Constant">9999</span><span class="Delimiter">,</span> <span class="Constant">"schedule"</span><span class="Delimiter">)</span> << <span class="Constant">"waking up routine "</span> << Routines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)-></span>id << end<span class="Delimiter">();</span> + put<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> loc<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span> Routines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)-></span>state = RUNNING<span class="Delimiter">;</span> - Routines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)-></span>waiting_on_location = Routines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)-></span>old_value_of_waiting_location = <span class="Constant">0</span><span class="Delimiter">;</span> + Routines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)-></span>waiting_on_location = <span class="Constant">0</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">}</span> -<span class="Comment">//: primitive to help compute locations to wait for</span> -<span class="Comment">//: only supports elements inside containers, no arrays or containers within</span> -<span class="Comment">//: containers yet.</span> +<span class="Comment">//: Primitive to help compute locations to wait on.</span> +<span class="Comment">//: Only supports elements immediately inside containers; no arrays or</span> +<span class="Comment">//: containers within containers yet.</span> <span class="Delimiter">:(scenario get_location)</span> def main [ @@ -275,166 +311,219 @@ def main [ ] <span class="traceContains">+mem: storing 11 in location 21</span> -<span class="Comment">//: also allow waiting on a routine to block</span> -<span class="Comment">//: (just for tests; use wait_for_routine below wherever possible)</span> +<span class="Comment">//: allow waiting on a routine to complete</span> -<span class="Delimiter">:(scenario wait_for_routine_to_block)</span> +<span class="Delimiter">:(scenario wait_for_routine)</span> def f1 [ + <span class="Comment"># add a few routines to run</span> <span class="Constant">1</span>:number/routine<span class="Special"> <- </span>start-running f2 - wait-<span class="Normal">for</span>-routine-to-block <span class="Constant">1</span>:number/routine - <span class="Comment"># now wait for f2 to run and modify location 10 before using its value</span> - <span class="Constant">11</span>:number<span class="Special"> <- </span>copy <span class="Constant">10</span>:number + <span class="Constant">2</span>:number/routine<span class="Special"> <- </span>start-running f3 + wait-<span class="Normal">for</span>-routine <span class="Constant">1</span>:number/routine + <span class="Comment"># now wait for f2 to *complete* and modify location 13 before using its value</span> + <span class="Constant">20</span>:number<span class="Special"> <- </span>copy <span class="Constant">13</span>:number ] def f2 [ - <span class="Constant">10</span>:number<span class="Special"> <- </span>copy <span class="Constant">34</span> + <span class="Constant">10</span>:number<span class="Special"> <- </span>copy <span class="Constant">0</span> <span class="Comment"># just padding</span> + <span class="Normal">switch</span> <span class="Comment"># simulate a block; routine f1 shouldn't restart at this point</span> + <span class="Constant">13</span>:number<span class="Special"> <- </span>copy <span class="Constant">34</span> +] +def f3 [ + <span class="Comment"># padding routine just to help simulate the block in f2 using 'switch'</span> + <span class="Constant">11</span>:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Constant">12</span>:number<span class="Special"> <- </span>copy <span class="Constant">0</span> ] <span class="traceContains">+schedule: f1</span> -<span class="traceContains">+run: waiting for routine 2 to block</span> +<span class="traceContains">+run: waiting for routine 2</span> <span class="traceContains">+schedule: f2</span> -<span class="traceContains">+schedule: waking up blocked routine 1</span> +<span class="traceContains">+schedule: f3</span> +<span class="traceContains">+schedule: f2</span> +<span class="traceContains">+schedule: waking up routine 1</span> <span class="traceContains">+schedule: f1</span> -<span class="Comment"># if we got the synchronization wrong we'd be storing 0 in location 11</span> -<span class="traceContains">+mem: storing 34 in location 11</span> +<span class="Comment"># if we got the synchronization wrong we'd be storing 0 in location 20</span> +<span class="traceContains">+mem: storing 34 in location 20</span> <span class="Delimiter">:(before "End routine Fields")</span> <span class="Comment">// only if state == WAITING</span> -<span class="Normal">int</span> waiting_on_routine_to_block<span class="Delimiter">;</span> +<span class="Normal">int</span> waiting_on_routine<span class="Delimiter">;</span> <span class="Delimiter">:(before "End routine Constructor")</span> -waiting_on_routine_to_block = <span class="Constant">0</span><span class="Delimiter">;</span> +waiting_on_routine = <span class="Constant">0</span><span class="Delimiter">;</span> <span class="Delimiter">:(before "End Primitive Recipe Declarations")</span> -WAIT_FOR_ROUTINE_TO_BLOCK<span class="Delimiter">,</span> +WAIT_FOR_ROUTINE<span class="Delimiter">,</span> <span class="Delimiter">:(before "End Primitive Recipe Numbers")</span> -put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span> <span class="Constant">"wait-for-routine-to-block"</span><span class="Delimiter">,</span> WAIT_FOR_ROUTINE_TO_BLOCK<span class="Delimiter">);</span> +put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span> <span class="Constant">"wait-for-routine"</span><span class="Delimiter">,</span> WAIT_FOR_ROUTINE<span class="Delimiter">);</span> <span class="Delimiter">:(before "End Primitive Recipe Checks")</span> -<span class="Normal">case</span> WAIT_FOR_ROUTINE_TO_BLOCK: <span class="Delimiter">{</span> +<span class="Normal">case</span> WAIT_FOR_ROUTINE: <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">)</span> != <span class="Constant">1</span><span class="Delimiter">)</span> <span class="Delimiter">{</span> - raise << maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> << <span class="Constant">"'wait-for-routine-to-block' requires exactly one ingredient, but got '"</span> << inst<span class="Delimiter">.</span>original_string << <span class="Constant">"'</span><span class="cSpecial">\n</span><span class="Constant">"</span> << end<span class="Delimiter">();</span> + raise << maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> << <span class="Constant">"'wait-for-routine' requires exactly one ingredient, but got '"</span> << inst<span class="Delimiter">.</span>original_string << <span class="Constant">"'</span><span class="cSpecial">\n</span><span class="Constant">"</span> << end<span class="Delimiter">();</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Normal">if</span> <span class="Delimiter">(</span>!is_mu_number<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)))</span> <span class="Delimiter">{</span> - raise << maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> << <span class="Constant">"first ingredient of 'wait-for-routine-to-block' should be a routine id generated by 'start-running', but got '"</span> << inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>original_string << <span class="Constant">"'</span><span class="cSpecial">\n</span><span class="Constant">"</span> << end<span class="Delimiter">();</span> + raise << maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> << <span class="Constant">"first ingredient of 'wait-for-routine' should be a routine id generated by 'start-running', but got '"</span> << inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>original_string << <span class="Constant">"'</span><span class="cSpecial">\n</span><span class="Constant">"</span> << end<span class="Delimiter">();</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">:(before "End Primitive Recipe Implementations")</span> -<span class="Normal">case</span> WAIT_FOR_ROUTINE_TO_BLOCK: <span class="Delimiter">{</span> +<span class="Normal">case</span> WAIT_FOR_ROUTINE: <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)</span> == Current_routine<span class="Delimiter">-></span>id<span class="Delimiter">)</span> <span class="Delimiter">{</span> raise << maybe<span class="Delimiter">(</span>current_recipe_name<span class="Delimiter">())</span> << <span class="Constant">"routine can't wait for itself! '"</span> << to_original_string<span class="Delimiter">(</span>current_instruction<span class="Delimiter">())</span> << <span class="Constant">"'</span><span class="cSpecial">\n</span><span class="Constant">"</span> << end<span class="Delimiter">();</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> Current_routine<span class="Delimiter">-></span>state = WAITING<span class="Delimiter">;</span> - Current_routine<span class="Delimiter">-></span>waiting_on_routine_to_block = ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">);</span> - trace<span class="Delimiter">(</span><span class="Constant">9998</span><span class="Delimiter">,</span> <span class="Constant">"run"</span><span class="Delimiter">)</span> << <span class="Constant">"waiting for routine "</span> << ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)</span> << <span class="Constant">" to block"</span> << end<span class="Delimiter">();</span> -<span class="CommentedCode">//? cerr << Current_routine->id << ": waiting for routine " << ingredients.at(0).at(0) << " to block\n";</span> + Current_routine<span class="Delimiter">-></span>waiting_on_routine = ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">);</span> + trace<span class="Delimiter">(</span><span class="Constant">9998</span><span class="Delimiter">,</span> <span class="Constant">"run"</span><span class="Delimiter">)</span> << <span class="Constant">"waiting for routine "</span> << ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)</span> << end<span class="Delimiter">();</span> +<span class="CommentedCode">//? cerr << Current_routine->id << ": waiting for routine " << ingredients.at(0).at(0) << '\n';</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">:(before "End Scheduler State Transitions")</span> -<span class="Comment">// Wake up any routines waiting for other routines to stop running.</span> +<span class="Comment">// Wake up any routines waiting for other routines to complete.</span> +<span class="Comment">// Important: this must come after the scheduler loop above giving routines</span> +<span class="Comment">// waiting for locations to change a chance to wake up.</span> <span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> i = <span class="Constant">0</span><span class="Delimiter">;</span> i < SIZE<span class="Delimiter">(</span>Routines<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>Routines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)-></span>state != WAITING<span class="Delimiter">)</span> <span class="Identifier">continue</span><span class="Delimiter">;</span> routine* waiter = Routines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">);</span> - <span class="Normal">if</span> <span class="Delimiter">(</span>!waiter<span class="Delimiter">-></span>waiting_on_routine_to_block<span class="Delimiter">)</span> <span class="Identifier">continue</span><span class="Delimiter">;</span> - <span class="Normal">int</span> id = waiter<span class="Delimiter">-></span>waiting_on_routine_to_block<span class="Delimiter">;</span> + <span class="Normal">if</span> <span class="Delimiter">(</span>!waiter<span class="Delimiter">-></span>waiting_on_routine<span class="Delimiter">)</span> <span class="Identifier">continue</span><span class="Delimiter">;</span> + <span class="Normal">int</span> id = waiter<span class="Delimiter">-></span>waiting_on_routine<span class="Delimiter">;</span> assert<span class="Delimiter">(</span>id != waiter<span class="Delimiter">-></span>id<span class="Delimiter">);</span> <span class="Comment">// routine can't wait on itself</span> <span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> j = <span class="Constant">0</span><span class="Delimiter">;</span> j < SIZE<span class="Delimiter">(</span>Routines<span class="Delimiter">);</span> ++j<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Normal">const</span> routine* waitee = Routines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>j<span class="Delimiter">);</span> - <span class="Normal">if</span> <span class="Delimiter">(</span>waitee<span class="Delimiter">-></span>id == id && waitee<span class="Delimiter">-></span>state != RUNNING<span class="Delimiter">)</span> <span class="Delimiter">{</span> - <span class="Comment">// routine is WAITING or COMPLETED or DISCONTINUED</span> - trace<span class="Delimiter">(</span><span class="Constant">9999</span><span class="Delimiter">,</span> <span class="Constant">"schedule"</span><span class="Delimiter">)</span> << <span class="Constant">"waking up blocked routine "</span> << waiter<span class="Delimiter">-></span>id << end<span class="Delimiter">();</span> -<span class="CommentedCode">//? cerr << id << " is now unblocked (" << waitee->state << "); waking up waiting routine " << waiter->id << '\n';</span> + <span class="Normal">if</span> <span class="Delimiter">(</span>waitee<span class="Delimiter">-></span>id == id && waitee<span class="Delimiter">-></span>state != RUNNING && waitee<span class="Delimiter">-></span>state != WAITING<span class="Delimiter">)</span> <span class="Delimiter">{</span> + <span class="Comment">// routine is COMPLETED or DISCONTINUED</span> + trace<span class="Delimiter">(</span><span class="Constant">9999</span><span class="Delimiter">,</span> <span class="Constant">"schedule"</span><span class="Delimiter">)</span> << <span class="Constant">"waking up routine "</span> << waiter<span class="Delimiter">-></span>id << end<span class="Delimiter">();</span> +<span class="CommentedCode">//? cerr << id << " is now done (" << waitee->state << "); waking up waiting routine " << waiter->id << '\n';</span> waiter<span class="Delimiter">-></span>state = RUNNING<span class="Delimiter">;</span> - waiter<span class="Delimiter">-></span>waiting_on_routine_to_block = <span class="Constant">0</span><span class="Delimiter">;</span> + waiter<span class="Delimiter">-></span>waiting_on_routine = <span class="Constant">0</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">}</span> <span class="Delimiter">}</span> -<span class="Comment">//: allow waiting on a routine to complete</span> +<span class="SalientComment">//:: helpers for manipulating routines in tests</span> +<span class="Comment">//:</span> +<span class="Comment">//: Managing arbitrary scenarios requires the ability to:</span> +<span class="Comment">//: a) stop the current routine (`switch`)</span> +<span class="Comment">//: b) restart a routine (`restart`)</span> +<span class="Comment">//: c) tell when a routine is blocked</span> +<span class="Comment">//:</span> +<span class="Comment">//: A routine is blocked either if it's waiting or if it explicitly signals</span> +<span class="Comment">//: that it's blocked (even as it periodically wakes up and polls for some</span> +<span class="Comment">//: event).</span> +<span class="Comment">//:</span> +<span class="Comment">//: Signalling blockedness might well be a huge hack. But Mu doesn't have Unix</span> +<span class="Comment">//: signals to avoid polling with, because signals are also pretty hacky.</span> -<span class="Delimiter">:(scenario wait_for_routine)</span> +<span class="Delimiter">:(before "End routine Fields")</span> +<span class="Normal">bool</span> blocked<span class="Delimiter">;</span> +<span class="Delimiter">:(before "End routine Constructor")</span> +blocked = <span class="Constant">false</span><span class="Delimiter">;</span> + +<span class="Delimiter">:(before "End Primitive Recipe Declarations")</span> +CURRENT_ROUTINE_IS_BLOCKED<span class="Delimiter">,</span> +<span class="Delimiter">:(before "End Primitive Recipe Numbers")</span> +put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span> <span class="Constant">"current-routine-is-blocked"</span><span class="Delimiter">,</span> CURRENT_ROUTINE_IS_BLOCKED<span class="Delimiter">);</span> +<span class="Delimiter">:(before "End Primitive Recipe Checks")</span> +<span class="Normal">case</span> CURRENT_ROUTINE_IS_BLOCKED: <span class="Delimiter">{</span> + <span class="Normal">if</span> <span class="Delimiter">(</span>!inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>empty<span class="Delimiter">())</span> <span class="Delimiter">{</span> + raise << maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> << <span class="Constant">"'current-routine-is-blocked' should have no ingredients, but got '"</span> << inst<span class="Delimiter">.</span>original_string << <span class="Constant">"'</span><span class="cSpecial">\n</span><span class="Constant">"</span> << end<span class="Delimiter">();</span> + <span class="Identifier">break</span><span class="Delimiter">;</span> + <span class="Delimiter">}</span> + <span class="Identifier">break</span><span class="Delimiter">;</span> +<span class="Delimiter">}</span> +<span class="Delimiter">:(before "End Primitive Recipe Implementations")</span> +<span class="Normal">case</span> CURRENT_ROUTINE_IS_BLOCKED: <span class="Delimiter">{</span> + Current_routine<span class="Delimiter">-></span>blocked = <span class="Constant">true</span><span class="Delimiter">;</span> + <span class="Identifier">break</span><span class="Delimiter">;</span> +<span class="Delimiter">}</span> + +<span class="Delimiter">:(before "End Primitive Recipe Declarations")</span> +CURRENT_ROUTINE_IS_UNBLOCKED<span class="Delimiter">,</span> +<span class="Delimiter">:(before "End Primitive Recipe Numbers")</span> +put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span> <span class="Constant">"current-routine-is-unblocked"</span><span class="Delimiter">,</span> CURRENT_ROUTINE_IS_UNBLOCKED<span class="Delimiter">);</span> +<span class="Delimiter">:(before "End Primitive Recipe Checks")</span> +<span class="Normal">case</span> CURRENT_ROUTINE_IS_UNBLOCKED: <span class="Delimiter">{</span> + <span class="Normal">if</span> <span class="Delimiter">(</span>!inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>empty<span class="Delimiter">())</span> <span class="Delimiter">{</span> + raise << maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> << <span class="Constant">"'current-routine-is-unblocked' should have no ingredients, but got '"</span> << inst<span class="Delimiter">.</span>original_string << <span class="Constant">"'</span><span class="cSpecial">\n</span><span class="Constant">"</span> << end<span class="Delimiter">();</span> + <span class="Identifier">break</span><span class="Delimiter">;</span> + <span class="Delimiter">}</span> + <span class="Identifier">break</span><span class="Delimiter">;</span> +<span class="Delimiter">}</span> +<span class="Delimiter">:(before "End Primitive Recipe Implementations")</span> +<span class="Normal">case</span> CURRENT_ROUTINE_IS_UNBLOCKED: <span class="Delimiter">{</span> + Current_routine<span class="Delimiter">-></span>blocked = <span class="Constant">false</span><span class="Delimiter">;</span> + <span class="Identifier">break</span><span class="Delimiter">;</span> +<span class="Delimiter">}</span> + +<span class="Comment">//: also allow waiting on a routine to block</span> +<span class="Comment">//: (just for tests; use wait_for_routine above wherever possible)</span> + +<span class="Delimiter">:(scenario wait_for_routine_to_block)</span> def f1 [ - <span class="Comment"># add a few routines to run</span> <span class="Constant">1</span>:number/routine<span class="Special"> <- </span>start-running f2 - <span class="Constant">2</span>:number/routine<span class="Special"> <- </span>start-running f3 - wait-<span class="Normal">for</span>-routine <span class="Constant">1</span>:number/routine - <span class="Comment"># now wait for f2 to *complete* and modify location 13 before using its value</span> - <span class="Constant">20</span>:number<span class="Special"> <- </span>copy <span class="Constant">13</span>:number + wait-<span class="Normal">for</span>-routine-to-block <span class="Constant">1</span>:number/routine + <span class="Comment"># now wait for f2 to run and modify location 10 before using its value</span> + <span class="Constant">11</span>:number<span class="Special"> <- </span>copy <span class="Constant">10</span>:number ] def f2 [ - <span class="Constant">10</span>:number<span class="Special"> <- </span>copy <span class="Constant">0</span> <span class="Comment"># just padding</span> - <span class="Normal">switch</span> <span class="Comment"># simulate a block; routine f1 shouldn't restart at this point</span> - <span class="Constant">13</span>:number<span class="Special"> <- </span>copy <span class="Constant">34</span> -] -def f3 [ - <span class="Comment"># padding routine just to help simulate the block in f2 using 'switch'</span> - <span class="Constant">11</span>:number<span class="Special"> <- </span>copy <span class="Constant">0</span> - <span class="Constant">12</span>:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Constant">10</span>:number<span class="Special"> <- </span>copy <span class="Constant">34</span> ] <span class="traceContains">+schedule: f1</span> -<span class="traceContains">+run: waiting for routine 2</span> -<span class="traceContains">+schedule: f2</span> -<span class="traceContains">+schedule: f3</span> +<span class="traceContains">+run: waiting for routine 2 to block</span> <span class="traceContains">+schedule: f2</span> -<span class="traceContains">+schedule: waking up routine 1</span> +<span class="traceContains">+schedule: waking up routine 1 because routine 2 is blocked</span> <span class="traceContains">+schedule: f1</span> -<span class="Comment"># if we got the synchronization wrong we'd be storing 0 in location 20</span> -<span class="traceContains">+mem: storing 34 in location 20</span> +<span class="Comment"># if we got the synchronization wrong we'd be storing 0 in location 11</span> +<span class="traceContains">+mem: storing 34 in location 11</span> <span class="Delimiter">:(before "End routine Fields")</span> <span class="Comment">// only if state == WAITING</span> -<span class="Normal">int</span> waiting_on_routine<span class="Delimiter">;</span> +<span class="Normal">int</span> waiting_on_routine_to_block<span class="Delimiter">;</span> <span class="Delimiter">:(before "End routine Constructor")</span> -waiting_on_routine = <span class="Constant">0</span><span class="Delimiter">;</span> +waiting_on_routine_to_block = <span class="Constant">0</span><span class="Delimiter">;</span> <span class="Delimiter">:(before "End Primitive Recipe Declarations")</span> -WAIT_FOR_ROUTINE<span class="Delimiter">,</span> +WAIT_FOR_ROUTINE_TO_BLOCK<span class="Delimiter">,</span> <span class="Delimiter">:(before "End Primitive Recipe Numbers")</span> -put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span> <span class="Constant">"wait-for-routine"</span><span class="Delimiter">,</span> WAIT_FOR_ROUTINE<span class="Delimiter">);</span> +put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span> <span class="Constant">"wait-for-routine-to-block"</span><span class="Delimiter">,</span> WAIT_FOR_ROUTINE_TO_BLOCK<span class="Delimiter">);</span> <span class="Delimiter">:(before "End Primitive Recipe Checks")</span> -<span class="Normal">case</span> WAIT_FOR_ROUTINE: <span class="Delimiter">{</span> +<span class="Normal">case</span> WAIT_FOR_ROUTINE_TO_BLOCK: <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">)</span> != <span class="Constant">1</span><span class="Delimiter">)</span> <span class="Delimiter">{</span> - raise << maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> << <span class="Constant">"'wait-for-routine' requires exactly one ingredient, but got '"</span> << inst<span class="Delimiter">.</span>original_string << <span class="Constant">"'</span><span class="cSpecial">\n</span><span class="Constant">"</span> << end<span class="Delimiter">();</span> + raise << maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> << <span class="Constant">"'wait-for-routine-to-block' requires exactly one ingredient, but got '"</span> << inst<span class="Delimiter">.</span>original_string << <span class="Constant">"'</span><span class="cSpecial">\n</span><span class="Constant">"</span> << end<span class="Delimiter">();</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Normal">if</span> <span class="Delimiter">(</span>!is_mu_number<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)))</span> <span class="Delimiter">{</span> - raise << maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> << <span class="Constant">"first ingredient of 'wait-for-routine' should be a routine id generated by 'start-running', but got '"</span> << inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>original_string << <span class="Constant">"'</span><span class="cSpecial">\n</span><span class="Constant">"</span> << end<span class="Delimiter">();</span> + raise << maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> << <span class="Constant">"first ingredient of 'wait-for-routine-to-block' should be a routine id generated by 'start-running', but got '"</span> << inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>original_string << <span class="Constant">"'</span><span class="cSpecial">\n</span><span class="Constant">"</span> << end<span class="Delimiter">();</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">:(before "End Primitive Recipe Implementations")</span> -<span class="Normal">case</span> WAIT_FOR_ROUTINE: <span class="Delimiter">{</span> +<span class="Normal">case</span> WAIT_FOR_ROUTINE_TO_BLOCK: <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)</span> == Current_routine<span class="Delimiter">-></span>id<span class="Delimiter">)</span> <span class="Delimiter">{</span> raise << maybe<span class="Delimiter">(</span>current_recipe_name<span class="Delimiter">())</span> << <span class="Constant">"routine can't wait for itself! '"</span> << to_original_string<span class="Delimiter">(</span>current_instruction<span class="Delimiter">())</span> << <span class="Constant">"'</span><span class="cSpecial">\n</span><span class="Constant">"</span> << end<span class="Delimiter">();</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> Current_routine<span class="Delimiter">-></span>state = WAITING<span class="Delimiter">;</span> - Current_routine<span class="Delimiter">-></span>waiting_on_routine = ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">);</span> - trace<span class="Delimiter">(</span><span class="Constant">9998</span><span class="Delimiter">,</span> <span class="Constant">"run"</span><span class="Delimiter">)</span> << <span class="Constant">"waiting for routine "</span> << ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)</span> << end<span class="Delimiter">();</span> -<span class="CommentedCode">//? cerr << Current_routine->id << ": waiting for routine " << ingredients.at(0).at(0) << '\n';</span> + Current_routine<span class="Delimiter">-></span>waiting_on_routine_to_block = ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">);</span> + trace<span class="Delimiter">(</span><span class="Constant">9998</span><span class="Delimiter">,</span> <span class="Constant">"run"</span><span class="Delimiter">)</span> << <span class="Constant">"waiting for routine "</span> << ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)</span> << <span class="Constant">" to block"</span> << end<span class="Delimiter">();</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">:(before "End Scheduler State Transitions")</span> -<span class="Comment">// Wake up any routines waiting for other routines to complete.</span> -<span class="Comment">// Important: this must come after the scheduler loop above giving routines</span> -<span class="Comment">// waiting for locations to change a chance to wake up.</span> +<span class="Comment">// Wake up any routines waiting for other routines to stop running.</span> <span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> i = <span class="Constant">0</span><span class="Delimiter">;</span> i < SIZE<span class="Delimiter">(</span>Routines<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>Routines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)-></span>state != WAITING<span class="Delimiter">)</span> <span class="Identifier">continue</span><span class="Delimiter">;</span> routine* waiter = Routines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">);</span> - <span class="Normal">if</span> <span class="Delimiter">(</span>!waiter<span class="Delimiter">-></span>waiting_on_routine<span class="Delimiter">)</span> <span class="Identifier">continue</span><span class="Delimiter">;</span> - <span class="Normal">int</span> id = waiter<span class="Delimiter">-></span>waiting_on_routine<span class="Delimiter">;</span> + <span class="Normal">if</span> <span class="Delimiter">(</span>!waiter<span class="Delimiter">-></span>waiting_on_routine_to_block<span class="Delimiter">)</span> <span class="Identifier">continue</span><span class="Delimiter">;</span> + <span class="Normal">int</span> id = waiter<span class="Delimiter">-></span>waiting_on_routine_to_block<span class="Delimiter">;</span> assert<span class="Delimiter">(</span>id != waiter<span class="Delimiter">-></span>id<span class="Delimiter">);</span> <span class="Comment">// routine can't wait on itself</span> <span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> j = <span class="Constant">0</span><span class="Delimiter">;</span> j < SIZE<span class="Delimiter">(</span>Routines<span class="Delimiter">);</span> ++j<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Normal">const</span> routine* waitee = Routines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>j<span class="Delimiter">);</span> - <span class="Normal">if</span> <span class="Delimiter">(</span>waitee<span class="Delimiter">-></span>id == id && waitee<span class="Delimiter">-></span>state != RUNNING && waitee<span class="Delimiter">-></span>state != WAITING<span class="Delimiter">)</span> <span class="Delimiter">{</span> - <span class="Comment">// routine is COMPLETED or DISCONTINUED</span> - trace<span class="Delimiter">(</span><span class="Constant">9999</span><span class="Delimiter">,</span> <span class="Constant">"schedule"</span><span class="Delimiter">)</span> << <span class="Constant">"waking up routine "</span> << waiter<span class="Delimiter">-></span>id << end<span class="Delimiter">();</span> -<span class="CommentedCode">//? cerr << id << " is now done (" << waitee->state << "); waking up waiting routine " << waiter->id << '\n';</span> + <span class="Normal">if</span> <span class="Delimiter">(</span>waitee<span class="Delimiter">-></span>id != id<span class="Delimiter">)</span> <span class="Identifier">continue</span><span class="Delimiter">;</span> + <span class="Normal">if</span> <span class="Delimiter">(</span>waitee<span class="Delimiter">-></span>state != RUNNING || waitee<span class="Delimiter">-></span>blocked<span class="Delimiter">)</span> <span class="Delimiter">{</span> + trace<span class="Delimiter">(</span><span class="Constant">9999</span><span class="Delimiter">,</span> <span class="Constant">"schedule"</span><span class="Delimiter">)</span> << <span class="Constant">"waking up routine "</span> << waiter<span class="Delimiter">-></span>id << <span class="Constant">" because routine "</span> << waitee<span class="Delimiter">-></span>id << <span class="Constant">" is blocked"</span> << end<span class="Delimiter">();</span> waiter<span class="Delimiter">-></span>state = RUNNING<span class="Delimiter">;</span> - waiter<span class="Delimiter">-></span>waiting_on_routine = <span class="Constant">0</span><span class="Delimiter">;</span> + waiter<span class="Delimiter">-></span>waiting_on_routine_to_block = <span class="Constant">0</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">}</span> <span class="Delimiter">}</span> @@ -498,6 +587,7 @@ put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span <span class="Normal">if</span> <span class="Delimiter">(</span>Routines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)-></span>id == id<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>Routines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)-></span>state == WAITING<span class="Delimiter">)</span> Routines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)-></span>state = RUNNING<span class="Delimiter">;</span> + Routines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)-></span>blocked = <span class="Constant">false</span><span class="Delimiter">;</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">}</span> @@ -518,6 +608,32 @@ def f [ <span class="Constant">1</span>:number/<span class="Special">raw <- </span>copy <span class="Constant">1</span> ] <span class="Comment"># shouldn't crash</span> + +<span class="Delimiter">:(scenario restart_blocked_routine)</span> +<span class="Special">% Scheduling_interval = 1;</span> +def main [ + local-scope + <span class="Normal">r</span>:number/routine-id<span class="Special"> <- </span>start-running f + wait-<span class="Normal">for</span>-routine-to-block r <span class="Comment"># get past the block in f below</span> + restart r + wait-<span class="Normal">for</span>-routine-to-block r <span class="Comment"># should run f to completion</span> +] +<span class="Comment"># function with one block</span> +def f [ + current-routine-is-blocked + <span class="Comment"># 8 instructions of padding, many more than 'main' above</span> + <span class="Constant">1</span>:number<span class="Special"> <- </span>add <span class="Constant">1</span>:number<span class="Delimiter">,</span> <span class="Constant">1</span> + <span class="Constant">1</span>:number<span class="Special"> <- </span>add <span class="Constant">1</span>:number<span class="Delimiter">,</span> <span class="Constant">1</span> + <span class="Constant">1</span>:number<span class="Special"> <- </span>add <span class="Constant">1</span>:number<span class="Delimiter">,</span> <span class="Constant">1</span> + <span class="Constant">1</span>:number<span class="Special"> <- </span>add <span class="Constant">1</span>:number<span class="Delimiter">,</span> <span class="Constant">1</span> + <span class="Constant">1</span>:number<span class="Special"> <- </span>add <span class="Constant">1</span>:number<span class="Delimiter">,</span> <span class="Constant">1</span> + <span class="Constant">1</span>:number<span class="Special"> <- </span>add <span class="Constant">1</span>:number<span class="Delimiter">,</span> <span class="Constant">1</span> + <span class="Constant">1</span>:number<span class="Special"> <- </span>add <span class="Constant">1</span>:number<span class="Delimiter">,</span> <span class="Constant">1</span> + <span class="Constant">1</span>:number<span class="Special"> <- </span>add <span class="Constant">1</span>:number<span class="Delimiter">,</span> <span class="Constant">1</span> + <span class="Constant">1</span>:number<span class="Special"> <- </span>add <span class="Constant">1</span>:number<span class="Delimiter">,</span> <span class="Constant">1</span> +] +<span class="Comment"># make sure all of f ran</span> +<span class="traceContains">+mem: storing 8 in location 1</span> </pre> </body> </html> |