fix haddock submodule pointer
[ghc-hetmet.git] / rts / Task.c
index 98f083c..e77a030 100644 (file)
@@ -24,7 +24,7 @@
 #endif
 
 // Task lists and global counters.
-// Locks required: sched_mutex.
+// Locks required: all_tasks_mutex.
 Task *all_tasks = NULL;
 static nat taskCount;
 static int tasksInitialized = 0;
@@ -33,6 +33,10 @@ static void   freeTask  (Task *task);
 static Task * allocTask (void);
 static Task * newTask   (rtsBool);
 
+#if defined(THREADED_RTS)
+static Mutex all_tasks_mutex;
+#endif
+
 /* -----------------------------------------------------------------------------
  * Remembering the current thread's Task
  * -------------------------------------------------------------------------- */
@@ -59,9 +63,12 @@ initTaskManager (void)
     if (!tasksInitialized) {
        taskCount = 0;
        tasksInitialized = 1;
-#if defined(THREADED_RTS) && !defined(MYTASK_USE_TLV)
+#if defined(THREADED_RTS)
+#if !defined(MYTASK_USE_TLV)
        newThreadLocalKey(&currentTaskKey);
 #endif
+        initMutex(&all_tasks_mutex);
+#endif
     }
 }
 
@@ -71,7 +78,7 @@ freeTaskManager (void)
     Task *task, *next;
     nat tasksRunning = 0;
 
-    ASSERT_LOCK_HELD(&sched_mutex);
+    ACQUIRE_LOCK(&all_tasks_mutex);
 
     for (task = all_tasks; task != NULL; task = next) {
         next = task->all_link;
@@ -86,7 +93,11 @@ freeTaskManager (void)
                tasksRunning);
 
     all_tasks = NULL;
+
+    RELEASE_LOCK(&all_tasks_mutex);
+
 #if defined(THREADED_RTS) && !defined(MYTASK_USE_TLV)
+    closeMutex(&all_tasks_mutex); 
     freeThreadLocalKey(&currentTaskKey);
 #endif
 
@@ -154,8 +165,6 @@ newTask (rtsBool worker)
     task->worker        = worker;
     task->stopped       = rtsFalse;
     task->running_finalizers = rtsFalse;
-    task->stat          = NoStatus;
-    task->ret           = NULL;
     task->n_spare_incalls = 0;
     task->spare_incalls = NULL;
     task->incall        = NULL;
@@ -179,14 +188,14 @@ newTask (rtsBool worker)
 
     task->next = NULL;
 
-    ACQUIRE_LOCK(&sched_mutex);
+    ACQUIRE_LOCK(&all_tasks_mutex);
 
     task->all_link = all_tasks;
     all_tasks = task;
 
     taskCount++;
 
-    RELEASE_LOCK(&sched_mutex);
+    RELEASE_LOCK(&all_tasks_mutex);
 
     return task;
 }
@@ -211,6 +220,8 @@ newInCall (Task *task)
     incall->task = task;
     incall->suspended_tso = NULL;
     incall->suspended_cap = NULL;
+    incall->stat          = NoStatus;
+    incall->ret           = NULL;
     incall->next = NULL;
     incall->prev = NULL;
     incall->prev_stack = task->incall;
@@ -259,8 +270,6 @@ newBoundTask (void)
 void
 boundTaskExiting (Task *task)
 {
-    task->stopped = rtsTrue;
-
 #if defined(THREADED_RTS)
     ASSERT(osThreadId() == task->id);
 #endif
@@ -268,6 +277,14 @@ boundTaskExiting (Task *task)
 
     endInCall(task);
 
+    // Set task->stopped, but only if this is the last call (#4850).
+    // Remember that we might have a worker Task that makes a foreign
+    // call and then a callback, so it can transform into a bound
+    // Task for the duration of the callback.
+    if (task->incall == NULL) {
+        task->stopped = rtsTrue;
+    }
+
     debugTrace(DEBUG_sched, "task exiting");
 }
 
@@ -284,7 +301,7 @@ discardTasksExcept (Task *keep)
     Task *task, *next;
 
     // Wipe the task list, except the current Task.
-    ACQUIRE_LOCK(&sched_mutex);
+    ACQUIRE_LOCK(&all_tasks_mutex);
     for (task = all_tasks; task != NULL; task=next) {
         next = task->all_link;
         if (task != keep) {
@@ -294,32 +311,37 @@ discardTasksExcept (Task *keep)
     }
     all_tasks = keep;
     keep->all_link = NULL;
-    RELEASE_LOCK(&sched_mutex);
+    RELEASE_LOCK(&all_tasks_mutex);
 }
 
 void
 taskTimeStamp (Task *task USED_IF_THREADS)
 {
 #if defined(THREADED_RTS)
-    Ticks currentElapsedTime, currentUserTime, elapsedGCTime;
+    Ticks currentElapsedTime, currentUserTime;
 
     currentUserTime = getThreadCPUTime();
     currentElapsedTime = getProcessElapsedTime();
 
-    // XXX this is wrong; we want elapsed GC time since the
-    // Task started.
-    elapsedGCTime = stat_getElapsedGCTime();
-    
-    task->mut_time = 
+    task->mut_time =
        currentUserTime - task->muttimestart - task->gc_time;
     task->mut_etime = 
-       currentElapsedTime - task->elapsedtimestart - elapsedGCTime;
+        currentElapsedTime - task->elapsedtimestart - task->gc_etime;
 
+    if (task->gc_time   < 0) { task->gc_time   = 0; }
+    if (task->gc_etime  < 0) { task->gc_etime  = 0; }
     if (task->mut_time  < 0) { task->mut_time  = 0; }
     if (task->mut_etime < 0) { task->mut_etime = 0; }
 #endif
 }
 
+void
+taskDoneGC (Task *task, Ticks cpu_time, Ticks elapsed_time)
+{
+    task->gc_time  += cpu_time;
+    task->gc_etime += elapsed_time;
+}
+
 #if defined(THREADED_RTS)
 
 void
@@ -337,6 +359,19 @@ workerTaskStop (Task *task)
 
 #endif
 
+#ifdef DEBUG
+
+static void *taskId(Task *task)
+{
+#ifdef THREADED_RTS
+    return (void *)task->id;
+#else
+    return (void *)task;
+#endif
+}
+
+#endif
+
 #if defined(THREADED_RTS)
 
 static void OSThreadProcAttr
@@ -398,19 +433,19 @@ startWorkerTask (Capability *cap)
   RELEASE_LOCK(&task->lock);
 }
 
+void
+interruptWorkerTask (Task *task)
+{
+  ASSERT(osThreadId() != task->id);    // seppuku not allowed
+  ASSERT(task->incall->suspended_tso); // use this only for FFI calls
+  interruptOSThread(task->id);
+  debugTrace(DEBUG_sched, "interrupted worker task %p", taskId(task));
+}
+
 #endif /* THREADED_RTS */
 
 #ifdef DEBUG
 
-static void *taskId(Task *task)
-{
-#ifdef THREADED_RTS
-    return (void *)task->id;
-#else
-    return (void *)task;
-#endif
-}
-
 void printAllTasks(void);
 
 void