Wrap gcc on Windows, to provide the -B flags
[ghc-hetmet.git] / rts / Task.c
index 7214725..9a8ebd6 100644 (file)
@@ -8,13 +8,13 @@
  * 
  * -------------------------------------------------------------------------*/
 
+#include "PosixSource.h"
 #include "Rts.h"
+
 #include "RtsUtils.h"
-#include "OSThreads.h"
 #include "Task.h"
 #include "Capability.h"
 #include "Stats.h"
-#include "RtsFlags.h"
 #include "Schedule.h"
 #include "Hash.h"
 #include "Trace.h"
@@ -30,6 +30,7 @@ static Task *task_free_list = NULL; // singly-linked
 static nat taskCount;
 static nat tasksRunning;
 static nat workerCount;
+static int tasksInitialized = 0;
 
 /* -----------------------------------------------------------------------------
  * Remembering the current thread's Task
@@ -50,40 +51,50 @@ Task *my_task;
 void
 initTaskManager (void)
 {
-    static int initialized = 0;
-
-    if (!initialized) {
+    if (!tasksInitialized) {
        taskCount = 0;
        workerCount = 0;
        tasksRunning = 0;
-       initialized = 1;
+       tasksInitialized = 1;
 #if defined(THREADED_RTS)
        newThreadLocalKey(&currentTaskKey);
 #endif
     }
 }
 
-
-void
-stopTaskManager (void)
+nat
+freeTaskManager (void)
 {
     Task *task, *next;
 
-    debugTrace(DEBUG_sched, 
-              "stopping task manager, %d tasks still running",
-              tasksRunning);
+    ASSERT_LOCK_HELD(&sched_mutex);
 
-    ACQUIRE_LOCK(&sched_mutex);
-    for (task = task_free_list; task != NULL; task = next) {
-        next = task->next;
-        stgFree(task);
+    debugTrace(DEBUG_sched, "freeing task manager, %d tasks still running",
+               tasksRunning);
+
+    for (task = all_tasks; task != NULL; task = next) {
+        next = task->all_link;
+        if (task->stopped) {
+            // We only free resources if the Task is not in use.  A
+            // Task may still be in use if we have a Haskell thread in
+            // a foreign call while we are attempting to shut down the
+            // RTS (see conc059).
 #if defined(THREADED_RTS)
-        closeCondition(&task->cond);
-        closeMutex(&task->lock);
+            closeCondition(&task->cond);
+            closeMutex(&task->lock);
 #endif
+            stgFree(task);
+        }
     }
+    all_tasks = NULL;
     task_free_list = NULL;
-    RELEASE_LOCK(&sched_mutex);
+#if defined(THREADED_RTS)
+    freeThreadLocalKey(&currentTaskKey);
+#endif
+
+    tasksInitialized = 0;
+
+    return tasksRunning;
 }
 
 
@@ -95,7 +106,8 @@ newTask (void)
 #endif
     Task *task;
 
-    task = stgMallocBytes(sizeof(Task), "newTask");
+#define ROUND_TO_CACHE_LINE(x) ((((x)+63) / 64) * 64)
+    task = stgMallocBytes(ROUND_TO_CACHE_LINE(sizeof(Task)), "newTask");
     
     task->cap  = NULL;
     task->stopped = rtsFalse;
@@ -129,7 +141,6 @@ newTask (void)
     all_tasks = task;
 
     taskCount++;
-    workerCount++;
 
     return task;
 }
@@ -139,7 +150,17 @@ newBoundTask (void)
 {
     Task *task;
 
-    ASSERT_LOCK_HELD(&sched_mutex);
+    if (!tasksInitialized) {
+        errorBelch("newBoundTask: RTS is not initialised; call hs_init() first");
+        stg_exit(EXIT_FAILURE);
+    }
+
+    // ToDo: get rid of this lock in the common case.  We could store
+    // a free Task in thread-local storage, for example.  That would
+    // leave just one lock on the path into the RTS: cap->lock when
+    // acquiring the Capability.
+    ACQUIRE_LOCK(&sched_mutex);
+
     if (task_free_list == NULL) {
        task = newTask();
     } else {
@@ -158,6 +179,8 @@ newBoundTask (void)
 
     taskEnter(task);
 
+    RELEASE_LOCK(&sched_mutex);
+
     debugTrace(DEBUG_sched, "new task (taskCount: %d)", taskCount);
     return task;
 }
@@ -165,6 +188,7 @@ newBoundTask (void)
 void
 boundTaskExiting (Task *task)
 {
+    task->tso = NULL;
     task->stopped = rtsTrue;
     task->cap = NULL;
 
@@ -198,7 +222,11 @@ discardTask (Task *task)
     if (!task->stopped) {
        debugTrace(DEBUG_sched, "discarding task %ld", (long)TASK_ID(task));
        task->cap = NULL;
-       task->tso = NULL;
+        if (task->tso == NULL) {
+            workerCount--;
+        } else {
+            task->tso = NULL;
+        }
        task->stopped = rtsTrue;
        tasksRunning--;
        task->next = task_free_list;
@@ -229,28 +257,30 @@ taskTimeStamp (Task *task USED_IF_THREADS)
 #endif
 }
 
+#if defined(THREADED_RTS)
+
 void
 workerTaskStop (Task *task)
 {
-#if defined(THREADED_RTS)
     OSThreadId id;
     id = osThreadId();
     ASSERT(task->id == id);
     ASSERT(myTask() == task);
-#endif
 
+    task->cap = NULL;
     taskTimeStamp(task);
     task->stopped = rtsTrue;
     tasksRunning--;
-}
+    workerCount--;
 
-void
-resetTaskManagerAfterFork (void)
-{
-    // TODO!
-    taskCount = 0;
+    ACQUIRE_LOCK(&sched_mutex);
+    task->next = task_free_list;
+    task_free_list = task;
+    RELEASE_LOCK(&sched_mutex);
 }
 
+#endif
+
 #if defined(THREADED_RTS)
 
 void