| 1 | /* --------------------------------------------------------------------------- |
|---|
| 2 | * |
|---|
| 3 | * (c) The GHC Team, 2001-2006 |
|---|
| 4 | * |
|---|
| 5 | * Capabilities |
|---|
| 6 | * |
|---|
| 7 | * For details on the high-level design, see |
|---|
| 8 | * http://hackage.haskell.org/trac/ghc/wiki/Commentary/Rts/Scheduler |
|---|
| 9 | * |
|---|
| 10 | * A Capability holds all the state an OS thread/task needs to run |
|---|
| 11 | * Haskell code: its STG registers, a pointer to its TSO, a nursery |
|---|
| 12 | * etc. During STG execution, a pointer to the Capabilitity is kept in |
|---|
| 13 | * a register (BaseReg). |
|---|
| 14 | * |
|---|
| 15 | * Only in a THREADED_RTS build will there be multiple capabilities, |
|---|
| 16 | * in the non-threaded RTS there is one global capability, called |
|---|
| 17 | * MainCapability. |
|---|
| 18 | * |
|---|
| 19 | * --------------------------------------------------------------------------*/ |
|---|
| 20 | |
|---|
| 21 | #ifndef CAPABILITY_H |
|---|
| 22 | #define CAPABILITY_H |
|---|
| 23 | |
|---|
| 24 | #include "sm/GC.h" // for evac_fn |
|---|
| 25 | #include "Task.h" |
|---|
| 26 | #include "Sparks.h" |
|---|
| 27 | |
|---|
| 28 | #include "BeginPrivate.h" |
|---|
| 29 | |
|---|
| 30 | struct Capability_ { |
|---|
| 31 | // State required by the STG virtual machine when running Haskell |
|---|
| 32 | // code. During STG execution, the BaseReg register always points |
|---|
| 33 | // to the StgRegTable of the current Capability (&cap->r). |
|---|
| 34 | StgFunTable f; |
|---|
| 35 | StgRegTable r; |
|---|
| 36 | |
|---|
| 37 | nat no; // capability number. |
|---|
| 38 | |
|---|
| 39 | // The Task currently holding this Capability. This task has |
|---|
| 40 | // exclusive access to the contents of this Capability (apart from |
|---|
| 41 | // returning_tasks_hd/returning_tasks_tl). |
|---|
| 42 | // Locks required: cap->lock. |
|---|
| 43 | Task *running_task; |
|---|
| 44 | |
|---|
| 45 | // true if this Capability is running Haskell code, used for |
|---|
| 46 | // catching unsafe call-ins. |
|---|
| 47 | rtsBool in_haskell; |
|---|
| 48 | |
|---|
| 49 | // Has there been any activity on this Capability since the last GC? |
|---|
| 50 | nat idle; |
|---|
| 51 | |
|---|
| 52 | rtsBool disabled; |
|---|
| 53 | |
|---|
| 54 | // The run queue. The Task owning this Capability has exclusive |
|---|
| 55 | // access to its run queue, so can wake up threads without |
|---|
| 56 | // taking a lock, and the common path through the scheduler is |
|---|
| 57 | // also lock-free. |
|---|
| 58 | StgTSO *run_queue_hd; |
|---|
| 59 | StgTSO *run_queue_tl; |
|---|
| 60 | |
|---|
| 61 | // Tasks currently making safe foreign calls. Doubly-linked. |
|---|
| 62 | // When returning, a task first acquires the Capability before |
|---|
| 63 | // removing itself from this list, so that the GC can find all |
|---|
| 64 | // the suspended TSOs easily. Hence, when migrating a Task from |
|---|
| 65 | // the returning_tasks list, we must also migrate its entry from |
|---|
| 66 | // this list. |
|---|
| 67 | InCall *suspended_ccalls; |
|---|
| 68 | |
|---|
| 69 | // One mutable list per generation, so we don't need to take any |
|---|
| 70 | // locks when updating an old-generation thunk. This also lets us |
|---|
| 71 | // keep track of which closures this CPU has been mutating, so we |
|---|
| 72 | // can traverse them using the right thread during GC and avoid |
|---|
| 73 | // unnecessarily moving the data from one cache to another. |
|---|
| 74 | bdescr **mut_lists; |
|---|
| 75 | bdescr **saved_mut_lists; // tmp use during GC |
|---|
| 76 | |
|---|
| 77 | // block for allocating pinned objects into |
|---|
| 78 | bdescr *pinned_object_block; |
|---|
| 79 | // full pinned object blocks allocated since the last GC |
|---|
| 80 | bdescr *pinned_object_blocks; |
|---|
| 81 | |
|---|
| 82 | // Context switch flag. When non-zero, this means: stop running |
|---|
| 83 | // Haskell code, and switch threads. |
|---|
| 84 | int context_switch; |
|---|
| 85 | |
|---|
| 86 | // Interrupt flag. Like the context_switch flag, this also |
|---|
| 87 | // indicates that we should stop running Haskell code, but we do |
|---|
| 88 | // *not* switch threads. This is used to stop a Capability in |
|---|
| 89 | // order to do GC, for example. |
|---|
| 90 | // |
|---|
| 91 | // The interrupt flag is always reset before we start running |
|---|
| 92 | // Haskell code, unlike the context_switch flag which is only |
|---|
| 93 | // reset after we have executed the context switch. |
|---|
| 94 | int interrupt; |
|---|
| 95 | |
|---|
| 96 | #if defined(THREADED_RTS) |
|---|
| 97 | // Worker Tasks waiting in the wings. Singly-linked. |
|---|
| 98 | Task *spare_workers; |
|---|
| 99 | nat n_spare_workers; // count of above |
|---|
| 100 | |
|---|
| 101 | // This lock protects: |
|---|
| 102 | // running_task |
|---|
| 103 | // returning_tasks_{hd,tl} |
|---|
| 104 | // wakeup_queue |
|---|
| 105 | // inbox |
|---|
| 106 | Mutex lock; |
|---|
| 107 | |
|---|
| 108 | // Tasks waiting to return from a foreign call, or waiting to make |
|---|
| 109 | // a new call-in using this Capability (NULL if empty). |
|---|
| 110 | // NB. this field needs to be modified by tasks other than the |
|---|
| 111 | // running_task, so it requires cap->lock to modify. A task can |
|---|
| 112 | // check whether it is NULL without taking the lock, however. |
|---|
| 113 | Task *returning_tasks_hd; // Singly-linked, with head/tail |
|---|
| 114 | Task *returning_tasks_tl; |
|---|
| 115 | |
|---|
| 116 | // Messages, or END_TSO_QUEUE. |
|---|
| 117 | // Locks required: cap->lock |
|---|
| 118 | Message *inbox; |
|---|
| 119 | |
|---|
| 120 | SparkPool *sparks; |
|---|
| 121 | |
|---|
| 122 | // Stats on spark creation/conversion |
|---|
| 123 | SparkCounters spark_stats; |
|---|
| 124 | #endif |
|---|
| 125 | // Total words allocated by this cap since rts start |
|---|
| 126 | lnat total_allocated; |
|---|
| 127 | |
|---|
| 128 | // Per-capability STM-related data |
|---|
| 129 | StgTVarWatchQueue *free_tvar_watch_queues; |
|---|
| 130 | StgInvariantCheckQueue *free_invariant_check_queues; |
|---|
| 131 | StgTRecChunk *free_trec_chunks; |
|---|
| 132 | StgTRecHeader *free_trec_headers; |
|---|
| 133 | nat transaction_tokens; |
|---|
| 134 | } // typedef Capability is defined in RtsAPI.h |
|---|
| 135 | // Capabilities are stored in an array, so make sure that adjacent |
|---|
| 136 | // Capabilities don't share any cache-lines: |
|---|
| 137 | #ifndef mingw32_HOST_OS |
|---|
| 138 | ATTRIBUTE_ALIGNED(64) |
|---|
| 139 | #endif |
|---|
| 140 | ; |
|---|
| 141 | |
|---|
| 142 | |
|---|
| 143 | #if defined(THREADED_RTS) |
|---|
| 144 | #define ASSERT_TASK_ID(task) ASSERT(task->id == osThreadId()) |
|---|
| 145 | #else |
|---|
| 146 | #define ASSERT_TASK_ID(task) /*empty*/ |
|---|
| 147 | #endif |
|---|
| 148 | |
|---|
| 149 | // These properties should be true when a Task is holding a Capability |
|---|
| 150 | #define ASSERT_FULL_CAPABILITY_INVARIANTS(cap,task) \ |
|---|
| 151 | ASSERT(cap->running_task != NULL && cap->running_task == task); \ |
|---|
| 152 | ASSERT(task->cap == cap); \ |
|---|
| 153 | ASSERT_PARTIAL_CAPABILITY_INVARIANTS(cap,task) |
|---|
| 154 | |
|---|
| 155 | // Sometimes a Task holds a Capability, but the Task is not associated |
|---|
| 156 | // with that Capability (ie. task->cap != cap). This happens when |
|---|
| 157 | // (a) a Task holds multiple Capabilities, and (b) when the current |
|---|
| 158 | // Task is bound, its thread has just blocked, and it may have been |
|---|
| 159 | // moved to another Capability. |
|---|
| 160 | #define ASSERT_PARTIAL_CAPABILITY_INVARIANTS(cap,task) \ |
|---|
| 161 | ASSERT(cap->run_queue_hd == END_TSO_QUEUE ? \ |
|---|
| 162 | cap->run_queue_tl == END_TSO_QUEUE : 1); \ |
|---|
| 163 | ASSERT(myTask() == task); \ |
|---|
| 164 | ASSERT_TASK_ID(task); |
|---|
| 165 | |
|---|
| 166 | #if defined(THREADED_RTS) |
|---|
| 167 | rtsBool checkSparkCountInvariant (void); |
|---|
| 168 | #endif |
|---|
| 169 | |
|---|
| 170 | // Converts a *StgRegTable into a *Capability. |
|---|
| 171 | // |
|---|
| 172 | INLINE_HEADER Capability * |
|---|
| 173 | regTableToCapability (StgRegTable *reg) |
|---|
| 174 | { |
|---|
| 175 | return (Capability *)((void *)((unsigned char*)reg - STG_FIELD_OFFSET(Capability,r))); |
|---|
| 176 | } |
|---|
| 177 | |
|---|
| 178 | // Initialise the available capabilities. |
|---|
| 179 | // |
|---|
| 180 | void initCapabilities (void); |
|---|
| 181 | |
|---|
| 182 | // Add and initialise more Capabilities |
|---|
| 183 | // |
|---|
| 184 | Capability * moreCapabilities (nat from, nat to); |
|---|
| 185 | |
|---|
| 186 | // Release a capability. This is called by a Task that is exiting |
|---|
| 187 | // Haskell to make a foreign call, or in various other cases when we |
|---|
| 188 | // want to relinquish a Capability that we currently hold. |
|---|
| 189 | // |
|---|
| 190 | // ASSUMES: cap->running_task is the current Task. |
|---|
| 191 | // |
|---|
| 192 | #if defined(THREADED_RTS) |
|---|
| 193 | void releaseCapability (Capability* cap); |
|---|
| 194 | void releaseAndWakeupCapability (Capability* cap); |
|---|
| 195 | void releaseCapability_ (Capability* cap, rtsBool always_wakeup); |
|---|
| 196 | // assumes cap->lock is held |
|---|
| 197 | #else |
|---|
| 198 | // releaseCapability() is empty in non-threaded RTS |
|---|
| 199 | INLINE_HEADER void releaseCapability (Capability* cap STG_UNUSED) {}; |
|---|
| 200 | INLINE_HEADER void releaseAndWakeupCapability (Capability* cap STG_UNUSED) {}; |
|---|
| 201 | INLINE_HEADER void releaseCapability_ (Capability* cap STG_UNUSED, |
|---|
| 202 | rtsBool always_wakeup STG_UNUSED) {}; |
|---|
| 203 | #endif |
|---|
| 204 | |
|---|
| 205 | // declared in includes/rts/Threads.h: |
|---|
| 206 | // extern Capability MainCapability; |
|---|
| 207 | |
|---|
| 208 | // declared in includes/rts/Threads.h: |
|---|
| 209 | // extern nat n_capabilities; |
|---|
| 210 | |
|---|
| 211 | extern nat enabled_capabilities; |
|---|
| 212 | |
|---|
| 213 | // Array of all the capabilities |
|---|
| 214 | // |
|---|
| 215 | extern Capability *capabilities; |
|---|
| 216 | |
|---|
| 217 | // The Capability that was last free. Used as a good guess for where |
|---|
| 218 | // to assign new threads. |
|---|
| 219 | // |
|---|
| 220 | extern Capability *last_free_capability; |
|---|
| 221 | |
|---|
| 222 | // |
|---|
| 223 | // Indicates that the RTS wants to synchronise all the Capabilities |
|---|
| 224 | // for some reason. All Capabilities should stop and return to the |
|---|
| 225 | // scheduler. |
|---|
| 226 | // |
|---|
| 227 | #define SYNC_GC_SEQ 1 |
|---|
| 228 | #define SYNC_GC_PAR 2 |
|---|
| 229 | #define SYNC_OTHER 3 |
|---|
| 230 | extern volatile StgWord pending_sync; |
|---|
| 231 | |
|---|
| 232 | // Acquires a capability at a return point. If *cap is non-NULL, then |
|---|
| 233 | // this is taken as a preference for the Capability we wish to |
|---|
| 234 | // acquire. |
|---|
| 235 | // |
|---|
| 236 | // OS threads waiting in this function get priority over those waiting |
|---|
| 237 | // in waitForCapability(). |
|---|
| 238 | // |
|---|
| 239 | // On return, *cap is non-NULL, and points to the Capability acquired. |
|---|
| 240 | // |
|---|
| 241 | void waitForReturnCapability (Capability **cap/*in/out*/, Task *task); |
|---|
| 242 | |
|---|
| 243 | EXTERN_INLINE void recordMutableCap (StgClosure *p, Capability *cap, nat gen); |
|---|
| 244 | |
|---|
| 245 | EXTERN_INLINE void recordClosureMutated (Capability *cap, StgClosure *p); |
|---|
| 246 | |
|---|
| 247 | #if defined(THREADED_RTS) |
|---|
| 248 | |
|---|
| 249 | // Gives up the current capability IFF there is a higher-priority |
|---|
| 250 | // thread waiting for it. This happens in one of two ways: |
|---|
| 251 | // |
|---|
| 252 | // (a) we are passing the capability to another OS thread, so |
|---|
| 253 | // that it can run a bound Haskell thread, or |
|---|
| 254 | // |
|---|
| 255 | // (b) there is an OS thread waiting to return from a foreign call |
|---|
| 256 | // |
|---|
| 257 | // On return: *pCap is NULL if the capability was released. The |
|---|
| 258 | // current task should then re-acquire it using waitForCapability(). |
|---|
| 259 | // |
|---|
| 260 | void yieldCapability (Capability** pCap, Task *task); |
|---|
| 261 | |
|---|
| 262 | // Acquires a capability for doing some work. |
|---|
| 263 | // |
|---|
| 264 | // On return: pCap points to the capability. |
|---|
| 265 | // |
|---|
| 266 | void waitForCapability (Task *task, Mutex *mutex, Capability **pCap); |
|---|
| 267 | |
|---|
| 268 | // Wakes up a worker thread on just one Capability, used when we |
|---|
| 269 | // need to service some global event. |
|---|
| 270 | // |
|---|
| 271 | void prodOneCapability (void); |
|---|
| 272 | void prodCapability (Capability *cap, Task *task); |
|---|
| 273 | |
|---|
| 274 | // Similar to prodOneCapability(), but prods all of them. |
|---|
| 275 | // |
|---|
| 276 | void prodAllCapabilities (void); |
|---|
| 277 | |
|---|
| 278 | // Attempt to gain control of a Capability if it is free. |
|---|
| 279 | // |
|---|
| 280 | rtsBool tryGrabCapability (Capability *cap, Task *task); |
|---|
| 281 | |
|---|
| 282 | // Try to find a spark to run |
|---|
| 283 | // |
|---|
| 284 | StgClosure *findSpark (Capability *cap); |
|---|
| 285 | |
|---|
| 286 | // True if any capabilities have sparks |
|---|
| 287 | // |
|---|
| 288 | rtsBool anySparks (void); |
|---|
| 289 | |
|---|
| 290 | INLINE_HEADER rtsBool emptySparkPoolCap (Capability *cap); |
|---|
| 291 | INLINE_HEADER nat sparkPoolSizeCap (Capability *cap); |
|---|
| 292 | INLINE_HEADER void discardSparksCap (Capability *cap); |
|---|
| 293 | |
|---|
| 294 | #else // !THREADED_RTS |
|---|
| 295 | |
|---|
| 296 | // Grab a capability. (Only in the non-threaded RTS; in the threaded |
|---|
| 297 | // RTS one of the waitFor*Capability() functions must be used). |
|---|
| 298 | // |
|---|
| 299 | extern void grabCapability (Capability **pCap); |
|---|
| 300 | |
|---|
| 301 | #endif /* !THREADED_RTS */ |
|---|
| 302 | |
|---|
| 303 | // Waits for a capability to drain of runnable threads and workers, |
|---|
| 304 | // and then acquires it. Used at shutdown time. |
|---|
| 305 | // |
|---|
| 306 | void shutdownCapability (Capability *cap, Task *task, rtsBool wait_foreign); |
|---|
| 307 | |
|---|
| 308 | // Shut down all capabilities. |
|---|
| 309 | // |
|---|
| 310 | void shutdownCapabilities(Task *task, rtsBool wait_foreign); |
|---|
| 311 | |
|---|
| 312 | // cause all capabilities to context switch as soon as possible. |
|---|
| 313 | void contextSwitchAllCapabilities(void); |
|---|
| 314 | INLINE_HEADER void contextSwitchCapability(Capability *cap); |
|---|
| 315 | |
|---|
| 316 | // cause all capabilities to stop running Haskell code and return to |
|---|
| 317 | // the scheduler as soon as possible. |
|---|
| 318 | void interruptAllCapabilities(void); |
|---|
| 319 | INLINE_HEADER void interruptCapability(Capability *cap); |
|---|
| 320 | |
|---|
| 321 | // Free all capabilities |
|---|
| 322 | void freeCapabilities (void); |
|---|
| 323 | |
|---|
| 324 | // For the GC: |
|---|
| 325 | void markCapability (evac_fn evac, void *user, Capability *cap, |
|---|
| 326 | rtsBool no_mark_sparks USED_IF_THREADS); |
|---|
| 327 | |
|---|
| 328 | void markCapabilities (evac_fn evac, void *user); |
|---|
| 329 | |
|---|
| 330 | void traverseSparkQueues (evac_fn evac, void *user); |
|---|
| 331 | |
|---|
| 332 | /* ----------------------------------------------------------------------------- |
|---|
| 333 | Messages |
|---|
| 334 | -------------------------------------------------------------------------- */ |
|---|
| 335 | |
|---|
| 336 | #ifdef THREADED_RTS |
|---|
| 337 | |
|---|
| 338 | INLINE_HEADER rtsBool emptyInbox(Capability *cap); |
|---|
| 339 | |
|---|
| 340 | #endif // THREADED_RTS |
|---|
| 341 | |
|---|
| 342 | /* ----------------------------------------------------------------------------- |
|---|
| 343 | * INLINE functions... private below here |
|---|
| 344 | * -------------------------------------------------------------------------- */ |
|---|
| 345 | |
|---|
| 346 | EXTERN_INLINE void |
|---|
| 347 | recordMutableCap (StgClosure *p, Capability *cap, nat gen) |
|---|
| 348 | { |
|---|
| 349 | bdescr *bd; |
|---|
| 350 | |
|---|
| 351 | // We must own this Capability in order to modify its mutable list. |
|---|
| 352 | // ASSERT(cap->running_task == myTask()); |
|---|
| 353 | // NO: assertion is violated by performPendingThrowTos() |
|---|
| 354 | bd = cap->mut_lists[gen]; |
|---|
| 355 | if (bd->free >= bd->start + BLOCK_SIZE_W) { |
|---|
| 356 | bdescr *new_bd; |
|---|
| 357 | new_bd = allocBlock_lock(); |
|---|
| 358 | new_bd->link = bd; |
|---|
| 359 | bd = new_bd; |
|---|
| 360 | cap->mut_lists[gen] = bd; |
|---|
| 361 | } |
|---|
| 362 | *bd->free++ = (StgWord)p; |
|---|
| 363 | } |
|---|
| 364 | |
|---|
| 365 | EXTERN_INLINE void |
|---|
| 366 | recordClosureMutated (Capability *cap, StgClosure *p) |
|---|
| 367 | { |
|---|
| 368 | bdescr *bd; |
|---|
| 369 | bd = Bdescr((StgPtr)p); |
|---|
| 370 | if (bd->gen_no != 0) recordMutableCap(p,cap,bd->gen_no); |
|---|
| 371 | } |
|---|
| 372 | |
|---|
| 373 | |
|---|
| 374 | #if defined(THREADED_RTS) |
|---|
| 375 | INLINE_HEADER rtsBool |
|---|
| 376 | emptySparkPoolCap (Capability *cap) |
|---|
| 377 | { return looksEmpty(cap->sparks); } |
|---|
| 378 | |
|---|
| 379 | INLINE_HEADER nat |
|---|
| 380 | sparkPoolSizeCap (Capability *cap) |
|---|
| 381 | { return sparkPoolSize(cap->sparks); } |
|---|
| 382 | |
|---|
| 383 | INLINE_HEADER void |
|---|
| 384 | discardSparksCap (Capability *cap) |
|---|
| 385 | { discardSparks(cap->sparks); } |
|---|
| 386 | #endif |
|---|
| 387 | |
|---|
| 388 | INLINE_HEADER void |
|---|
| 389 | stopCapability (Capability *cap) |
|---|
| 390 | { |
|---|
| 391 | // setting HpLim to NULL tries to make the next heap check will |
|---|
| 392 | // fail, which will cause the thread to return to the scheduler. |
|---|
| 393 | // It may not work - the thread might be updating HpLim itself |
|---|
| 394 | // at the same time - so we also have the context_switch/interrupted |
|---|
| 395 | // flags as a sticky way to tell the thread to stop. |
|---|
| 396 | cap->r.rHpLim = NULL; |
|---|
| 397 | } |
|---|
| 398 | |
|---|
| 399 | INLINE_HEADER void |
|---|
| 400 | interruptCapability (Capability *cap) |
|---|
| 401 | { |
|---|
| 402 | stopCapability(cap); |
|---|
| 403 | cap->interrupt = 1; |
|---|
| 404 | } |
|---|
| 405 | |
|---|
| 406 | INLINE_HEADER void |
|---|
| 407 | contextSwitchCapability (Capability *cap) |
|---|
| 408 | { |
|---|
| 409 | stopCapability(cap); |
|---|
| 410 | cap->context_switch = 1; |
|---|
| 411 | } |
|---|
| 412 | |
|---|
| 413 | #ifdef THREADED_RTS |
|---|
| 414 | |
|---|
| 415 | INLINE_HEADER rtsBool emptyInbox(Capability *cap) |
|---|
| 416 | { |
|---|
| 417 | return (cap->inbox == (Message*)END_TSO_QUEUE); |
|---|
| 418 | } |
|---|
| 419 | |
|---|
| 420 | #endif |
|---|
| 421 | |
|---|
| 422 | #include "EndPrivate.h" |
|---|
| 423 | |
|---|
| 424 | #endif /* CAPABILITY_H */ |
|---|