diff options
Diffstat (limited to 'html/073wait.cc.html')
-rw-r--r-- | html/073wait.cc.html | 103 |
1 files changed, 53 insertions, 50 deletions
diff --git a/html/073wait.cc.html b/html/073wait.cc.html index ffc27bb9..b5339856 100644 --- a/html/073wait.cc.html +++ b/html/073wait.cc.html @@ -16,7 +16,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color .Constant { color: #00a0a0; } .cSpecial { color: #008000; } .muRecipe { color: #ff8700; } -.CommentedCode { color: #6c6c6c; } +.SalientComment { color: #00ffff; } .Comment { color: #9090ff; } .Delimiter { color: #800080; } .Special { color: #c00000; } @@ -24,7 +24,6 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color .Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; } .muData { color: #ffff00; } .Identifier { color: #fcb165; } -.SalientComment { color: #00ffff; } --> </style> @@ -87,19 +86,28 @@ waiting_on_location = <span class="Constant">0</span><span class="Delimiter">;</ <span class="Delimiter">}</span> <span class="Delimiter">:(code)</span> <span class="Normal">bool</span> any_routines_waiting<span class="Delimiter">()</span> <span class="Delimiter">{</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">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">return</span> <span class="Constant">true</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Identifier">return</span> <span class="Constant">false</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Normal">void</span> dump_waiting_routines<span class="Delimiter">()</span> <span class="Delimiter">{</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">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> cerr << i << <span class="Constant">": "</span> << routine_label<span class="Delimiter">(</span>Routines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">))</span> << <span class="cSpecial">'\n'</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">}</span> +<span class="Delimiter">:(scenario wait_for_location_can_deadlock)</span> +<span class="Special">% Hide_errors = true;</span> +<span class="muRecipe">def</span> main [ + <span class="Constant">10</span>:num<span class="Special"> <- </span>copy <span class="Constant">1</span> + <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="traceContains">+error: deadlock!</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> @@ -161,7 +169,7 @@ put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span <span class="Comment">//: scheduler tweak to get routines out of that state</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">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">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> @@ -242,7 +250,7 @@ put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span <span class="Normal">int</span> offset = ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">);</span> <span class="Normal">if</span> <span class="Delimiter">(</span>offset < <span class="Constant">0</span> || offset >= SIZE<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> base_root_type<span class="Delimiter">-></span>value<span class="Delimiter">).</span>elements<span class="Delimiter">))</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Comment">// copied from Check above</span> <span class="Normal">int</span> result = base_address<span class="Delimiter">;</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 < offset<span class="Delimiter">;</span> ++i<span class="Delimiter">)</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 < offset<span class="Delimiter">;</span> ++i<span class="Delimiter">)</span> result += size_of<span class="Delimiter">(</span>element_type<span class="Delimiter">(</span>base<span class="Delimiter">.</span>type<span class="Delimiter">,</span> i<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">"address to copy is "</span> << result << end<span class="Delimiter">();</span> products<span class="Delimiter">.</span>resize<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">);</span> @@ -375,7 +383,6 @@ put<span class="Delimiter">(</span>Recipe_ordinal<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> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> @@ -383,30 +390,60 @@ put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</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">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> 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">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> 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> <span class="Delimiter">}</span> <span class="Delimiter">}</span> <span class="Delimiter">}</span> +<span class="Comment">//: yield voluntarily to let some other routine run</span> + +<span class="Delimiter">:(before "End Primitive Recipe Declarations")</span> +SWITCH<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">"switch"</span><span class="Delimiter">,</span> SWITCH<span class="Delimiter">);</span> +<span class="Delimiter">:(before "End Primitive Recipe Checks")</span> +<span class="Normal">case</span> SWITCH: <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> SWITCH: <span class="Delimiter">{</span> + ++current_step_index<span class="Delimiter">();</span> + <span class="Identifier">goto</span> stop_running_current_routine<span class="Delimiter">;</span> +<span class="Delimiter">}</span> + +<span class="Delimiter">:(scenario switch_preempts_current_routine)</span> +<span class="muRecipe">def</span> f1 [ + start-running f2 + <span class="Constant">1</span>:num<span class="Special"> <- </span>copy <span class="Constant">34</span> + <span class="Normal">switch</span> + <span class="Constant">3</span>:num<span class="Special"> <- </span>copy <span class="Constant">36</span> +] +<span class="muRecipe">def</span> f2 [ + <span class="Constant">2</span>:num<span class="Special"> <- </span>copy <span class="Constant">35</span> +] +<span class="traceContains">+mem: storing 34 in location 1</span> +<span class="Comment"># context switch</span> +<span class="traceContains">+mem: storing 35 in location 2</span> +<span class="Comment"># back to original thread</span> +<span class="traceContains">+mem: storing 36 in location 3</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">//: a) check if a routine is blocked</span> +<span class="Comment">//: b) restart a blocked routine (`restart`)</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> @@ -513,13 +550,13 @@ put<span class="Delimiter">(</span>Recipe_ordinal<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="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">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> 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">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<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> @@ -530,40 +567,6 @@ put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span <span class="Delimiter">}</span> <span class="Delimiter">}</span> -<span class="Comment">//: yield voluntarily to let some other routine run</span> - -<span class="Delimiter">:(before "End Primitive Recipe Declarations")</span> -SWITCH<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">"switch"</span><span class="Delimiter">,</span> SWITCH<span class="Delimiter">);</span> -<span class="Delimiter">:(before "End Primitive Recipe Checks")</span> -<span class="Normal">case</span> SWITCH: <span class="Delimiter">{</span> - <span class="Identifier">break</span><span class="Delimiter">;</span> -<span class="Delimiter">}</span> -<span class="Comment">//: pick another RUNNING routine at random and wait for it to get a chance</span> -<span class="Comment">//: there might be a better implementation than this</span> -<span class="Delimiter">:(before "End Primitive Recipe Implementations")</span> -<span class="Normal">case</span> SWITCH: <span class="Delimiter">{</span> - <span class="Normal">int</span> id = some_other_running_routine<span class="Delimiter">();</span> - <span class="Normal">if</span> <span class="Delimiter">(</span>id<span class="Delimiter">)</span> <span class="Delimiter">{</span> - assert<span class="Delimiter">(</span>id != Current_routine<span class="Delimiter">-></span>id<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 = id<span class="Delimiter">;</span> - <span class="Delimiter">}</span> - <span class="Identifier">break</span><span class="Delimiter">;</span> -<span class="Delimiter">}</span> -<span class="Delimiter">:(code)</span> -<span class="Normal">int</span> some_other_running_routine<span class="Delimiter">()</span> <span class="Delimiter">{</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>i == Current_routine_index<span class="Delimiter">)</span> <span class="Identifier">continue</span><span class="Delimiter">;</span> - assert<span class="Delimiter">(</span>Routines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)</span> != Current_routine<span class="Delimiter">);</span> - assert<span class="Delimiter">(</span>Routines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)-></span>id != Current_routine<span class="Delimiter">-></span>id<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 == RUNNING<span class="Delimiter">)</span> - <span class="Identifier">return</span> Routines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)-></span>id<span class="Delimiter">;</span> - <span class="Delimiter">}</span> - <span class="Identifier">return</span> <span class="Constant">0</span><span class="Delimiter">;</span> -<span class="Delimiter">}</span> - <span class="Comment">//: helper for restarting blocking routines in tests</span> <span class="Delimiter">:(before "End Primitive Recipe Declarations")</span> @@ -585,7 +588,7 @@ put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span <span class="Delimiter">:(before "End Primitive Recipe Implementations")</span> <span class="Normal">case</span> RESTART: <span class="Delimiter">{</span> <span class="Normal">int</span> id = 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">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">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>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> |