Fix numa001 failure with "too many NUMA nodes"
[ghc.git] / rts / Task.h
index 58798bd..9323459 100644 (file)
@@ -94,7 +94,7 @@ typedef struct InCall_ {
                                 // without owning a Capability in the
                                 // first place.
 
-    SchedulerStatus  stat;      // return status
+    SchedulerStatus  rstat;     // return status
     StgClosure **    ret;       // return value
 
     struct Task_ *task;
@@ -115,6 +115,12 @@ typedef struct Task_ {
 #if defined(THREADED_RTS)
     OSThreadId id;              // The OS Thread ID of this task
 
+    // The NUMA node this Task belongs to.  If this is a worker thread, then the
+    // OS thread will be bound to this node (see workerStart()).  If this is an
+    // external thread calling into Haskell, it can be bound to a node using
+    // rts_setInCallCapability().
+    uint32_t node;
+
     Condition cond;             // used for sleeping & waking up this task
     Mutex lock;                 // lock for the condition variable
 
@@ -125,32 +131,34 @@ typedef struct Task_ {
     rtsBool wakeup;
 #endif
 
-    // This points to the Capability that the Task "belongs" to.  If
-    // the Task owns a Capability, then task->cap points to it.  If
-    // the task does not own a Capability, then either (a) if the task
-    // is a worker, then task->cap points to the Capability it belongs
-    // to, or (b) it is returning from a foreign call, then task->cap
-    // points to the Capability with the returning_worker queue that this
-    // this Task is on.
+    // If the task owns a Capability, task->cap points to it.  (occasionally a
+    // task may own multiple capabilities, in which case task->cap may point to
+    // any of them.  We must be careful to set task->cap to the appropriate one
+    // when using Capability APIs.)
+    //
+    // If the task is a worker, task->cap points to the Capability on which it
+    // is queued.
     //
-    // When a task goes to sleep, it may be migrated to a different
-    // Capability.  Hence, we always check task->cap on wakeup.  To
-    // syncrhonise between the migrater and the migratee, task->lock
-    // must be held when modifying task->cap.
+    // If the task is in an unsafe foreign call, then task->cap can be used to
+    // retrieve the capability (see rts_unsafeGetMyCapability()).
     struct Capability_ *cap;
 
     // The current top-of-stack InCall
     struct InCall_ *incall;
 
-    nat n_spare_incalls;
+    uint32_t n_spare_incalls;
     struct InCall_ *spare_incalls;
 
     rtsBool    worker;          // == rtsTrue if this is a worker Task
-    rtsBool    stopped;         // this task has stopped or exited Haskell
+    rtsBool    stopped;         // == rtsTrue between newBoundTask and
+                                // boundTaskExiting, or in a worker Task.
 
     // So that we can detect when a finalizer illegally calls back into Haskell
     rtsBool running_finalizers;
 
+    // if >= 0, this Capability will be used for in-calls
+    int preferred_capability;
+
     // Links tasks on the returning_tasks queue of a Capability, and
     // on spare_workers.
     struct Task_ *next;
@@ -191,14 +199,19 @@ extern Mutex all_tasks_mutex;
 // Requires: sched_mutex.
 //
 void initTaskManager (void);
-nat  freeTaskManager (void);
+uint32_t  freeTaskManager (void);
 
 // Create a new Task for a bound thread.  This Task must be released
 // by calling boundTaskExiting.  The Task is cached in
 // thread-local storage and will remain even after boundTaskExiting()
 // has been called; to free the memory, see freeMyTask().
 //
-Task *newBoundTask (void);
+Task* newBoundTask (void);
+
+// Return the current OS thread's Task, which is created if it doesn't already
+// exist.  After you have finished using RTS APIs, you should call freeMyTask()
+// to release this thread's Task.
+Task* getTask (void);
 
 // The current task is a bound task that is exiting.
 //
@@ -246,9 +259,9 @@ void interruptWorkerTask (Task *task);
 #endif /* THREADED_RTS */
 
 // For stats
-extern nat taskCount;
-extern nat workerCount;
-extern nat peakWorkerCount;
+extern uint32_t taskCount;
+extern uint32_t workerCount;
+extern uint32_t peakWorkerCount;
 
 // -----------------------------------------------------------------------------
 // INLINE functions... private from here on down:
@@ -324,11 +337,7 @@ INLINE_HEADER TaskId serialiseTaskId (OSThreadId taskID) {
 // Get a serialisable Id for the Task's OS thread
 // Needed mainly for logging since the OSThreadId is an opaque type
 INLINE_HEADER TaskId
-serialisableTaskId (Task *task
-#if !defined(THREADED_RTS)
-                               STG_UNUSED
-#endif
-                                         )
+serialisableTaskId (Task *task)
 {
 #if defined(THREADED_RTS)
     return serialiseTaskId(task->id);