Cheng Shao pushed to branch wip/clear-block-info at Glasgow Haskell Compiler / GHC
Commits:
-
b4b1720d
by Ben Gamari at 2025-11-29T23:35:57+01:00
9 changed files:
- rts/RaiseAsync.c
- rts/Schedule.c
- rts/Threads.c
- rts/include/rts/storage/TSO.h
- rts/posix/Poll.c
- rts/posix/Select.c
- rts/posix/Timeout.c
- rts/sm/Sanity.c
- rts/win32/AsyncMIO.c
Changes:
| ... | ... | @@ -716,12 +716,13 @@ removeFromQueues(Capability *cap, StgTSO *tso) |
| 716 | 716 | syncDelayCancel(cap, tso);
|
| 717 | 717 | goto done;
|
| 718 | 718 | |
| 719 | - default:
|
|
| 719 | + default:
|
|
| 720 | 720 | barf("removeFromQueues: %d", tso->why_blocked);
|
| 721 | 721 | }
|
| 722 | 722 | |
| 723 | 723 | done:
|
| 724 | 724 | RELAXED_STORE(&tso->why_blocked, NotBlocked);
|
| 725 | + tso->block_info.closure = (StgClosure *)END_TSO_QUEUE;
|
|
| 725 | 726 | appendToRunQueue(cap, tso);
|
| 726 | 727 | }
|
| 727 | 728 | |
| ... | ... | @@ -1087,6 +1088,7 @@ done: |
| 1087 | 1088 | // wake it up
|
| 1088 | 1089 | if (tso->why_blocked != NotBlocked) {
|
| 1089 | 1090 | tso->why_blocked = NotBlocked;
|
| 1091 | + tso->block_info.closure = (StgClosure *)END_TSO_QUEUE;
|
|
| 1090 | 1092 | appendToRunQueue(cap,tso);
|
| 1091 | 1093 | }
|
| 1092 | 1094 |
| ... | ... | @@ -2589,7 +2589,8 @@ resumeThread (void *task_) |
| 2589 | 2589 | traceEventRunThread(cap, tso);
|
| 2590 | 2590 | |
| 2591 | 2591 | /* Reset blocking status */
|
| 2592 | - tso->why_blocked = NotBlocked;
|
|
| 2592 | + tso->why_blocked = NotBlocked;
|
|
| 2593 | + tso->block_info.closure = (StgClosure *)END_TSO_QUEUE;
|
|
| 2593 | 2594 | |
| 2594 | 2595 | if ((tso->flags & TSO_BLOCKEX) == 0) {
|
| 2595 | 2596 | // avoid locking the TSO if we don't have to
|
| ... | ... | @@ -338,6 +338,7 @@ unblock: |
| 338 | 338 | // just run the thread now, if the BH is not really available,
|
| 339 | 339 | // we'll block again.
|
| 340 | 340 | tso->why_blocked = NotBlocked;
|
| 341 | + tso->block_info.closure = (StgClosure *)END_TSO_QUEUE;
|
|
| 341 | 342 | appendToRunQueue(cap,tso);
|
| 342 | 343 | |
| 343 | 344 | // We used to set the context switch flag here, which would
|
| ... | ... | @@ -297,8 +297,8 @@ void setTSOPrev (Capability *cap, StgTSO *tso, StgTSO *target); |
| 297 | 297 | void dirty_STACK (Capability *cap, StgStack *stack);
|
| 298 | 298 | |
| 299 | 299 | /* -----------------------------------------------------------------------------
|
| 300 | - Invariants:
|
|
| 301 | - |
|
| 300 | + Note [TSO invariants]
|
|
| 301 | + ~~~~~~~~~~~~~~~~~~~~~
|
|
| 302 | 302 | An active thread has the following properties:
|
| 303 | 303 | |
| 304 | 304 | tso->stack < tso->sp < tso->stack+tso->stack_size
|
| ... | ... | @@ -313,7 +313,8 @@ void dirty_STACK (Capability *cap, StgStack *stack); |
| 313 | 313 | |
| 314 | 314 | tso->why_blocked tso->block_info location
|
| 315 | 315 | ----------------------------------------------------------------------
|
| 316 | - NotBlocked END_TSO_QUEUE runnable_queue, or running
|
|
| 316 | + NotBlocked END_TSO_QUEUE running
|
|
| 317 | + NotBlocked prev TSO runnable_queue (block_info.prev back-link)
|
|
| 317 | 318 | |
| 318 | 319 | BlockedOnBlackHole MessageBlackHole * TSO->bq
|
| 319 | 320 |
| ... | ... | @@ -261,6 +261,7 @@ static void notifyIOCompletion(Capability *cap, StgAsyncIOOp *aiop) |
| 261 | 261 | */
|
| 262 | 262 | StgTSO *tso = aiop->notify.tso;
|
| 263 | 263 | tso->why_blocked = NotBlocked;
|
| 264 | + tso->block_info.closure = (StgClosure *)END_TSO_QUEUE;
|
|
| 264 | 265 | tso->_link = END_TSO_QUEUE;
|
| 265 | 266 | pushOnRunQueue(cap, tso);
|
| 266 | 267 | }
|
| ... | ... | @@ -106,6 +106,7 @@ static bool wakeUpSleepingThreads (Capability *cap, LowResTime now) |
| 106 | 106 | }
|
| 107 | 107 | iomgr->sleeping_queue = tso->_link;
|
| 108 | 108 | RELAXED_STORE(&tso->why_blocked, NotBlocked);
|
| 109 | + tso->block_info.closure = (StgClosure *)END_TSO_QUEUE;
|
|
| 109 | 110 | tso->_link = END_TSO_QUEUE;
|
| 110 | 111 | IF_DEBUG(scheduler, debugBelch("Waking up sleeping thread %"
|
| 111 | 112 | FMT_StgThreadID "\n", tso->id));
|
| ... | ... | @@ -437,6 +438,7 @@ awaitCompletedTimeoutsOrIOSelect(Capability *cap, bool wait) |
| 437 | 438 | debugBelch("Waking up blocked thread %" FMT_StgThreadID "\n",
|
| 438 | 439 | tso->id));
|
| 439 | 440 | tso->why_blocked = NotBlocked;
|
| 441 | + tso->block_info.closure = (StgClosure *)END_TSO_QUEUE;
|
|
| 440 | 442 | tso->_link = END_TSO_QUEUE;
|
| 441 | 443 | pushOnRunQueue(cap,tso);
|
| 442 | 444 | break;
|
| ... | ... | @@ -122,6 +122,7 @@ static void notifyTimeoutCompletion(Capability *cap, StgTimeout *timeout) |
| 122 | 122 | {
|
| 123 | 123 | StgTSO *tso = timeout->notify.tso;
|
| 124 | 124 | tso->why_blocked = NotBlocked;
|
| 125 | + tso->block_info.closure = (StgClosure *)END_TSO_QUEUE;
|
|
| 125 | 126 | tso->_link = END_TSO_QUEUE;
|
| 126 | 127 | pushOnRunQueue(cap, tso);
|
| 127 | 128 | break;
|
| ... | ... | @@ -226,4 +227,3 @@ struct timespec *timeoutInNanoseconds(CapIOManager *iomgr, bool wait, |
| 226 | 227 | #endif
|
| 227 | 228 | |
| 228 | 229 | #endif // defined(IOMGR_ENABLED_POLL) |
| 229 | - |
| ... | ... | @@ -767,7 +767,6 @@ checkSTACK (StgStack *stack) |
| 767 | 767 | *
|
| 768 | 768 | * See #19146.
|
| 769 | 769 | */
|
| 770 | - |
|
| 771 | 770 | void
|
| 772 | 771 | checkTSO(StgTSO *tso)
|
| 773 | 772 | {
|
| ... | ... | @@ -788,6 +787,14 @@ checkTSO(StgTSO *tso) |
| 788 | 787 | ASSERT(LOOKS_LIKE_CLOSURE_PTR(tso->block_info.closure));
|
| 789 | 788 | }
|
| 790 | 789 | |
| 790 | + /* See Note [TSO invariants] in TSO.h */
|
|
| 791 | + if (tso->why_blocked == NotBlocked) {
|
|
| 792 | + // When on a run queue we use block_info.prev as the back-link.
|
|
| 793 | + // Otherwise (running) we expect END_TSO_QUEUE.
|
|
| 794 | + ASSERT(tso->block_info.closure == (StgClosure *)END_TSO_QUEUE ||
|
|
| 795 | + get_itbl(tso->block_info.closure)->type == TSO);
|
|
| 796 | + }
|
|
| 797 | + |
|
| 791 | 798 | ASSERT(LOOKS_LIKE_CLOSURE_PTR(tso->bq));
|
| 792 | 799 | ASSERT(LOOKS_LIKE_CLOSURE_PTR(tso->blocked_exceptions));
|
| 793 | 800 | ASSERT(LOOKS_LIKE_CLOSURE_PTR(tso->stackobj));
|
| ... | ... | @@ -319,14 +319,16 @@ start: |
| 319 | 319 | : END_TSO_QUEUE;
|
| 320 | 320 | }
|
| 321 | 321 | |
| 322 | - // Terminates the run queue + this inner for-loop.
|
|
| 323 | - tso->_link = END_TSO_QUEUE;
|
|
| 324 | - tso->why_blocked = NotBlocked;
|
|
| 325 | 322 | // save the StgAsyncIOResult in the
|
| 326 | 323 | // stg_block_async_info stack frame, because
|
| 327 | 324 | // the block_info field will be overwritten by
|
| 328 | 325 | // pushOnRunQueue().
|
| 329 | 326 | tso->stackobj->sp[1] = (W_)tso->block_info.async_result;
|
| 327 | + |
|
| 328 | + tso->why_blocked = NotBlocked;
|
|
| 329 | + tso->block_info.closure = (StgClosure *)END_TSO_QUEUE;
|
|
| 330 | + // Terminates the run queue + this inner for-loop.
|
|
| 331 | + tso->_link = END_TSO_QUEUE;
|
|
| 330 | 332 | pushOnRunQueue(&MainCapability, tso);
|
| 331 | 333 | break;
|
| 332 | 334 | }
|