diff --git a/compiler/prelude/primops.txt.pp b/compiler/prelude/primops.txt.pp
index 6d551d9..0ff7e2c 100644
|
a
|
b
|
|
| 1839 | 1839 | out_of_line = True |
| 1840 | 1840 | has_side_effects = True |
| 1841 | 1841 | |
| | 1842 | primop SetTicketsOp "setTickets#" GenPrimOp |
| | 1843 | ThreadId# -> Int# -> State# RealWorld -> State# RealWorld |
| | 1844 | with |
| | 1845 | out_of_line = True |
| | 1846 | has_side_effects = True |
| | 1847 | |
| | 1848 | primop GetTicketsOp "getTickets#" GenPrimOp |
| | 1849 | ThreadId# -> State# RealWorld -> (# State# RealWorld, Int# #) |
| | 1850 | with |
| | 1851 | out_of_line = True |
| | 1852 | has_side_effects = True |
| | 1853 | |
| | 1854 | primop ModifyTicketsOp "modifyTickets#" GenPrimOp |
| | 1855 | ThreadId# -> Int# -> Int# -> Int# -> State# RealWorld -> (# State# RealWorld, Int# #) |
| | 1856 | with |
| | 1857 | out_of_line = True |
| | 1858 | has_side_effects = True |
| | 1859 | |
| 1842 | 1860 | ------------------------------------------------------------------------ |
| 1843 | 1861 | section "Weak pointers" |
| 1844 | 1862 | ------------------------------------------------------------------------ |
diff --git a/includes/rts/storage/TSO.h b/includes/rts/storage/TSO.h
index 82f5a75..20a67a2 100644
|
a
|
b
|
|
| 168 | 168 | */ |
| 169 | 169 | StgWord32 tot_stack_size; |
| 170 | 170 | |
| | 171 | // These are bounded above by STRIDE1, which is less than a max 32-bit word. |
| | 172 | StgWord32 ss_tickets; |
| | 173 | // 64-bit to prevent overflows; only ever accessed by the task which owns TSO. |
| | 174 | StgWord64 ss_pass; |
| | 175 | |
| 171 | 176 | } *StgTSOPtr; |
| 172 | 177 | |
| 173 | 178 | typedef struct StgStack_ { |
diff --git a/includes/stg/MiscClosures.h b/includes/stg/MiscClosures.h
index 61e6b09..e6d5fcd 100644
|
a
|
b
|
|
| 402 | 402 | RTS_FUN_DECL(stg_unmaskAsyncExceptionszh); |
| 403 | 403 | RTS_FUN_DECL(stg_myThreadIdzh); |
| 404 | 404 | RTS_FUN_DECL(stg_labelThreadzh); |
| | 405 | RTS_FUN_DECL(stg_getTicketszh); |
| | 406 | RTS_FUN_DECL(stg_setTicketszh); |
| | 407 | RTS_FUN_DECL(stg_modifyTicketszh); |
| 405 | 408 | RTS_FUN_DECL(stg_isCurrentThreadBoundzh); |
| 406 | 409 | RTS_FUN_DECL(stg_threadStatuszh); |
| 407 | 410 | |
diff --git a/rts/Capability.h b/rts/Capability.h
index 3348f88..81322c8 100644
|
a
|
b
|
|
| 58 | 58 | StgTSO *run_queue_hd; |
| 59 | 59 | StgTSO *run_queue_tl; |
| 60 | 60 | |
| | 61 | // [SSS] Stride scheduling extensions. The Task with this |
| | 62 | // Capability has exclusive access to this variable. |
| | 63 | StgWord64 ss_pass; |
| | 64 | |
| 61 | 65 | // Tasks currently making safe foreign calls. Doubly-linked. |
| 62 | 66 | // When returning, a task first acquires the Capability before |
| 63 | 67 | // removing itself from this list, so that the GC can find all |
diff --git a/rts/Linker.c b/rts/Linker.c
index fa1de89..c673bac 100644
|
a
|
b
|
|
| 1130 | 1130 | SymI_HasProto(stg_mkApUpd0zh) \ |
| 1131 | 1131 | SymI_HasProto(stg_myThreadIdzh) \ |
| 1132 | 1132 | SymI_HasProto(stg_labelThreadzh) \ |
| | 1133 | SymI_HasProto(stg_getTicketszh) \ |
| | 1134 | SymI_HasProto(stg_setTicketszh) \ |
| | 1135 | SymI_HasProto(stg_modifyTicketszh) \ |
| 1133 | 1136 | SymI_HasProto(stg_newArrayzh) \ |
| 1134 | 1137 | SymI_HasProto(stg_newArrayArrayzh) \ |
| 1135 | 1138 | SymI_HasProto(stg_newBCOzh) \ |
diff --git a/rts/PrimOps.cmm b/rts/PrimOps.cmm
index ebcee6a..a737508 100644
|
a
|
b
|
|
| 628 | 628 | return (); |
| 629 | 629 | } |
| 630 | 630 | |
| | 631 | stg_setTicketszh ( gcptr threadid, W_ n ) |
| | 632 | { |
| | 633 | ccall setTickets(threadid "ptr", n); |
| | 634 | return (); |
| | 635 | } |
| | 636 | |
| | 637 | stg_getTicketszh ( gcptr threadid ) |
| | 638 | { |
| | 639 | W_ r; |
| | 640 | (r) = ccall getTickets(threadid "ptr"); |
| | 641 | return (r); |
| | 642 | } |
| | 643 | |
| | 644 | stg_modifyTicketszh ( gcptr threadid, W_ n, W_ d, W_ x ) |
| | 645 | { |
| | 646 | W_ r; |
| | 647 | (r) = ccall modifyTickets(threadid "ptr", n, d, x); |
| | 648 | return (r); |
| | 649 | } |
| | 650 | |
| 631 | 651 | stg_isCurrentThreadBoundzh (/* no args */) |
| 632 | 652 | { |
| 633 | 653 | W_ r; |
diff --git a/rts/RaiseAsync.c b/rts/RaiseAsync.c
index f5669cb..a32749c 100644
|
a
|
b
|
|
| 683 | 683 | |
| 684 | 684 | done: |
| 685 | 685 | tso->why_blocked = NotBlocked; |
| 686 | | appendToRunQueue(cap, tso); |
| | 686 | joinRunQueue(cap, tso); |
| 687 | 687 | } |
| 688 | 688 | |
| 689 | 689 | /* ----------------------------------------------------------------------------- |
| … |
… |
|
| 1045 | 1045 | // wake it up |
| 1046 | 1046 | if (tso->why_blocked != NotBlocked) { |
| 1047 | 1047 | tso->why_blocked = NotBlocked; |
| 1048 | | appendToRunQueue(cap,tso); |
| | 1048 | joinRunQueue(cap,tso); |
| 1049 | 1049 | } |
| 1050 | 1050 | |
| 1051 | 1051 | return tso; |
diff --git a/rts/Schedule.c b/rts/Schedule.c
index a21b312..3de00c5 100644
|
a
|
b
|
|
| 148 | 148 | static rtsBool scheduleHandleHeapOverflow( Capability *cap, StgTSO *t ); |
| 149 | 149 | static rtsBool scheduleHandleYield( Capability *cap, StgTSO *t, |
| 150 | 150 | nat prev_what_next ); |
| 151 | | static void scheduleHandleThreadBlocked( StgTSO *t ); |
| | 151 | static void scheduleHandleThreadBlocked( Capability *cap, StgTSO *t ); |
| 152 | 152 | static rtsBool scheduleHandleThreadFinished( Capability *cap, Task *task, |
| 153 | 153 | StgTSO *t ); |
| 154 | 154 | static rtsBool scheduleNeedHeapProfile(rtsBool ready_to_gc); |
| … |
… |
|
| 537 | 537 | break; |
| 538 | 538 | |
| 539 | 539 | case ThreadBlocked: |
| 540 | | scheduleHandleThreadBlocked(t); |
| | 540 | scheduleHandleThreadBlocked(cap, t); |
| 541 | 541 | break; |
| 542 | 542 | |
| 543 | 543 | case ThreadFinished: |
| … |
… |
|
| 781 | 781 | setTSOPrev(cap, t, prev); |
| 782 | 782 | prev = t; |
| 783 | 783 | } else { |
| 784 | | appendToRunQueue(free_caps[i],t); |
| | 784 | leaveRunQueue(cap,t); |
| | 785 | joinRunQueue(free_caps[i],t); |
| 785 | 786 | |
| 786 | 787 | traceEventMigrateThread (cap, t, free_caps[i]->no); |
| 787 | 788 | |
| … |
… |
|
| 1217 | 1218 | * -------------------------------------------------------------------------- */ |
| 1218 | 1219 | |
| 1219 | 1220 | static void |
| 1220 | | scheduleHandleThreadBlocked( StgTSO *t |
| 1221 | | #if !defined(DEBUG) |
| 1222 | | STG_UNUSED |
| 1223 | | #endif |
| 1224 | | ) |
| | 1221 | scheduleHandleThreadBlocked( Capability *cap, StgTSO *t ) |
| 1225 | 1222 | { |
| 1226 | 1223 | |
| 1227 | 1224 | // We don't need to do anything. The thread is blocked, and it |
| … |
… |
|
| 1234 | 1231 | // threadPaused() might have raised a blocked throwTo |
| 1235 | 1232 | // exception, see maybePerformBlockedException(). |
| 1236 | 1233 | |
| | 1234 | leaveRunQueue(cap, t); |
| | 1235 | |
| 1237 | 1236 | #ifdef DEBUG |
| 1238 | 1237 | traceThreadStatus(DEBUG_sched, t); |
| 1239 | 1238 | #endif |
| … |
… |
|
| 1257 | 1256 | // blocked mode (see #2910). |
| 1258 | 1257 | awakenBlockedExceptionQueue (cap, t); |
| 1259 | 1258 | |
| | 1259 | leaveRunQueue(cap, t); |
| | 1260 | |
| 1260 | 1261 | // |
| 1261 | 1262 | // Check whether the thread that just completed was a bound |
| 1262 | 1263 | // thread, and if so return with the result. |
| … |
… |
|
| 1277 | 1278 | // queue also ensures that the garbage collector knows about |
| 1278 | 1279 | // this thread and its return value (it gets dropped from the |
| 1279 | 1280 | // step->threads list so there's no other way to find it). |
| 1280 | | appendToRunQueue(cap,t); |
| | 1281 | joinRunQueue(cap,t); |
| 1281 | 1282 | return rtsFalse; |
| 1282 | 1283 | #else |
| 1283 | 1284 | // this cannot happen in the threaded RTS, because a |
| … |
… |
|
| 2296 | 2297 | { |
| 2297 | 2298 | // The thread goes at the *end* of the run-queue, to avoid possible |
| 2298 | 2299 | // starvation of any threads already on the queue. |
| 2299 | | appendToRunQueue(cap,tso); |
| | 2300 | joinRunQueue(cap,tso); |
| 2300 | 2301 | } |
| 2301 | 2302 | |
| 2302 | 2303 | void |
| … |
… |
|
| 2307 | 2308 | #if defined(THREADED_RTS) |
| 2308 | 2309 | cpu %= enabled_capabilities; |
| 2309 | 2310 | if (cpu == cap->no) { |
| 2310 | | appendToRunQueue(cap,tso); |
| | 2311 | joinRunQueue(cap,tso); |
| 2311 | 2312 | } else { |
| 2312 | 2313 | migrateThread(cap, tso, &capabilities[cpu]); |
| 2313 | 2314 | } |
| 2314 | 2315 | #else |
| 2315 | | appendToRunQueue(cap,tso); |
| | 2316 | joinRunQueue(cap,tso); |
| 2316 | 2317 | #endif |
| 2317 | 2318 | } |
| 2318 | 2319 | |
| … |
… |
|
| 2337 | 2338 | task->incall->ret = ret; |
| 2338 | 2339 | task->incall->stat = NoStatus; |
| 2339 | 2340 | |
| 2340 | | appendToRunQueue(cap,tso); |
| | 2341 | joinRunQueue(cap,tso); |
| 2341 | 2342 | |
| 2342 | 2343 | DEBUG_ONLY( id = tso->id ); |
| 2343 | 2344 | debugTrace(DEBUG_sched, "new bound thread (%lu)", (unsigned long)id); |
diff --git a/rts/Schedule.h b/rts/Schedule.h
index 8b7caea..e4425af 100644
|
a
|
b
|
|
| 116 | 116 | |
| 117 | 117 | void resurrectThreads (StgTSO *); |
| 118 | 118 | |
| | 119 | // STRIDE1 defines the maximum resolution we can achieve in scheduling. |
| | 120 | #define STRIDE1 (1 << 20) |
| | 121 | // Defualt tickets is set to STRIDE1, so that the IO manager gets |
| | 122 | // maximum priority. |
| | 123 | #define DEFAULT_TICKETS (1 << 20) |
| | 124 | |
| 119 | 125 | /* ----------------------------------------------------------------------------- |
| 120 | 126 | * Some convenient macros/inline functions... |
| 121 | 127 | */ |
| … |
… |
|
| 145 | 151 | cap->run_queue_tl = tso; |
| 146 | 152 | } |
| 147 | 153 | |
| | 154 | EXTERN_INLINE void |
| | 155 | joinRunQueue(Capability *cap, StgTSO *tso); |
| | 156 | |
| | 157 | EXTERN_INLINE void |
| | 158 | joinRunQueue(Capability *cap, StgTSO *tso) |
| | 159 | { |
| | 160 | appendToRunQueue(cap, tso); |
| | 161 | } |
| | 162 | |
| 148 | 163 | /* Push a thread on the beginning of the run queue. |
| 149 | 164 | * ASSUMES: cap->running_task is the current task. |
| 150 | 165 | */ |
| … |
… |
|
| 165 | 180 | } |
| 166 | 181 | } |
| 167 | 182 | |
| | 183 | EXTERN_INLINE void |
| | 184 | fastJoinRunQueue(Capability *cap, StgTSO *tso); |
| | 185 | |
| | 186 | EXTERN_INLINE void |
| | 187 | fastJoinRunQueue(Capability *cap, StgTSO *tso) |
| | 188 | { |
| | 189 | pushOnRunQueue(cap, tso); |
| | 190 | } |
| | 191 | |
| 168 | 192 | /* Pop the first thread off the runnable queue. |
| 169 | 193 | */ |
| 170 | 194 | INLINE_HEADER StgTSO * |
| … |
… |
|
| 189 | 213 | return cap->run_queue_hd; |
| 190 | 214 | } |
| 191 | 215 | |
| | 216 | EXTERN_INLINE void |
| | 217 | leaveRunQueue (Capability *cap, StgTSO *tso); |
| | 218 | |
| | 219 | EXTERN_INLINE void |
| | 220 | leaveRunQueue (Capability *cap, StgTSO *tso) |
| | 221 | { |
| | 222 | // XXX implement me |
| | 223 | } |
| | 224 | |
| 192 | 225 | void removeFromRunQueue (Capability *cap, StgTSO *tso); |
| 193 | 226 | extern void promoteInRunQueue (Capability *cap, StgTSO *tso); |
| 194 | 227 | |
diff --git a/rts/Sparks.c b/rts/Sparks.c
index 4241656..4e9b5a5 100644
|
a
|
b
|
|
| 45 | 45 | |
| 46 | 46 | traceEventCreateSparkThread(cap, tso->id); |
| 47 | 47 | |
| 48 | | appendToRunQueue(cap,tso); |
| | 48 | joinRunQueue(cap,tso); |
| 49 | 49 | } |
| 50 | 50 | |
| 51 | 51 | /* -------------------------------------------------------------------------- |
diff --git a/rts/Threads.c b/rts/Threads.c
index b617616..758d368 100644
|
a
|
b
|
|
| 112 | 112 | |
| 113 | 113 | tso->trec = NO_TREC; |
| 114 | 114 | |
| | 115 | tso->ss_tickets = DEFAULT_TICKETS; |
| | 116 | |
| 115 | 117 | #ifdef PROFILING |
| 116 | 118 | tso->prof.cccs = CCS_MAIN; |
| 117 | 119 | #endif |
| … |
… |
|
| 136 | 138 | } |
| 137 | 139 | |
| 138 | 140 | /* --------------------------------------------------------------------------- |
| | 141 | * Ticket allocations on threads |
| | 142 | * ------------------------------------------------------------------------ */ |
| | 143 | |
| | 144 | #define TICKET_ERROR (STRIDE1 + 1) |
| | 145 | |
| | 146 | void |
| | 147 | setTickets(StgTSO *tso, W_ tickets) |
| | 148 | { |
| | 149 | if (tickets > STRIDE1) { |
| | 150 | barf("setTickets: too many tickets"); |
| | 151 | } else if (tickets <= 0) { |
| | 152 | barf("setTickets: too few tickets"); |
| | 153 | } |
| | 154 | ACQUIRE_LOCK(&sched_mutex); |
| | 155 | tso->ss_tickets = tickets; |
| | 156 | RELEASE_LOCK(&sched_mutex); |
| | 157 | } |
| | 158 | |
| | 159 | W_ |
| | 160 | modifyTickets(StgTSO *tso, W_ n, W_ d, W_ x) |
| | 161 | { |
| | 162 | ACQUIRE_LOCK(&sched_mutex); |
| | 163 | W_ tickets = (tso->ss_tickets * n) / d + x; |
| | 164 | W_ delta; |
| | 165 | if (tickets > STRIDE1 || tickets <= 0) { |
| | 166 | delta = TICKET_ERROR; |
| | 167 | goto cleanup; |
| | 168 | } |
| | 169 | delta = tso->ss_tickets - tickets; |
| | 170 | tso->ss_tickets = tickets; |
| | 171 | cleanup: |
| | 172 | RELEASE_LOCK(&sched_mutex); |
| | 173 | return delta; |
| | 174 | } |
| | 175 | |
| | 176 | W_ |
| | 177 | getTickets(StgTSO *tso) |
| | 178 | { |
| | 179 | return tso->ss_tickets; |
| | 180 | } |
| | 181 | |
| | 182 | /* --------------------------------------------------------------------------- |
| 139 | 183 | * Comparing Thread ids. |
| 140 | 184 | * |
| 141 | 185 | * This is used from STG land in the implementation of the |
| … |
… |
|
| 296 | 340 | // just run the thread now, if the BH is not really available, |
| 297 | 341 | // we'll block again. |
| 298 | 342 | tso->why_blocked = NotBlocked; |
| 299 | | appendToRunQueue(cap,tso); |
| | 343 | joinRunQueue(cap, tso); |
| 300 | 344 | |
| 301 | 345 | // We used to set the context switch flag here, which would |
| 302 | 346 | // trigger a context switch a short time in the future (at the end |
| … |
… |
|
| 322 | 366 | traceEventMigrateThread (from, tso, to->no); |
| 323 | 367 | // ThreadMigrating tells the target cap that it needs to be added to |
| 324 | 368 | // the run queue when it receives the MSG_TRY_WAKEUP. |
| | 369 | leaveRunQueue(from, tso); |
| 325 | 370 | tso->why_blocked = ThreadMigrating; |
| 326 | 371 | tso->cap = to; |
| 327 | 372 | tryWakeupThread(from, tso); |
diff --git a/rts/Threads.h b/rts/Threads.h
index 6d26610..39794f3 100644
|
a
|
b
|
|
| 13 | 13 | |
| 14 | 14 | #define END_BLOCKED_EXCEPTIONS_QUEUE ((MessageThrowTo*)END_TSO_QUEUE) |
| 15 | 15 | |
| | 16 | void setTickets(StgTSO *tso, W_ n); |
| | 17 | W_ modifyTickets(StgTSO *tso, W_ n, W_ d, W_ x); |
| | 18 | W_ getTickets(StgTSO *tso); |
| | 19 | |
| 16 | 20 | StgTSO * unblockOne (Capability *cap, StgTSO *tso); |
| 17 | 21 | StgTSO * unblockOne_ (Capability *cap, StgTSO *tso, rtsBool allow_migrate); |
| 18 | 22 | |
diff --git a/rts/posix/Select.c b/rts/posix/Select.c
index 3d92a46..b39338b 100644
|
a
|
b
|
|
| 107 | 107 | tso->_link = END_TSO_QUEUE; |
| 108 | 108 | IF_DEBUG(scheduler,debugBelch("Waking up sleeping thread %lu\n", (unsigned long)tso->id)); |
| 109 | 109 | // MainCapability: this code is !THREADED_RTS |
| 110 | | pushOnRunQueue(&MainCapability,tso); |
| | 110 | fastJoinRunQueue(&MainCapability,tso); |
| 111 | 111 | flag = rtsTrue; |
| 112 | 112 | } |
| 113 | 113 | return flag; |
| … |
… |
|
| 305 | 305 | IF_DEBUG(scheduler,debugBelch("Waking up blocked thread %lu\n", (unsigned long)tso->id)); |
| 306 | 306 | tso->why_blocked = NotBlocked; |
| 307 | 307 | tso->_link = END_TSO_QUEUE; |
| 308 | | pushOnRunQueue(&MainCapability,tso); |
| | 308 | fastJoinRunQueue(&MainCapability,tso); |
| 309 | 309 | } else { |
| 310 | 310 | if (prev == NULL) |
| 311 | 311 | blocked_queue_hd = tso; |
diff --git a/rts/win32/AsyncIO.c b/rts/win32/AsyncIO.c
index 979df0c..cfd2c0f 100644
|
a
|
b
|
|
| 303 | 303 | // save the StgAsyncIOResult in the |
| 304 | 304 | // stg_block_async_info stack frame, because |
| 305 | 305 | // the block_info field will be overwritten by |
| 306 | | // pushOnRunQueue(). |
| | 306 | // fastJoinRunQueue(). |
| 307 | 307 | tso->stackobj->sp[1] = (W_)tso->block_info.async_result; |
| 308 | | pushOnRunQueue(&MainCapability, tso); |
| | 308 | fastJoinRunQueue(&MainCapability, tso); |
| 309 | 309 | break; |
| 310 | 310 | } |
| 311 | 311 | break; |