#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;
static Task * allocTask (void);
static Task * newTask (rtsBool);
+#if defined(THREADED_RTS)
+static Mutex all_tasks_mutex;
+#endif
+
/* -----------------------------------------------------------------------------
* Remembering the current thread's Task
* -------------------------------------------------------------------------- */
if (!tasksInitialized) {
taskCount = 0;
tasksInitialized = 1;
-#if defined(THREADED_RTS) && !defined(MYTASK_USE_TLV)
+#if defined(THREADED_RTS)
+#if !defined(MYTASK_USE_TLV)
newThreadLocalKey(¤tTaskKey);
#endif
+ initMutex(&all_tasks_mutex);
+#endif
}
}
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;
tasksRunning);
all_tasks = NULL;
+
+ RELEASE_LOCK(&all_tasks_mutex);
+
#if defined(THREADED_RTS) && !defined(MYTASK_USE_TLV)
+ closeMutex(&all_tasks_mutex);
freeThreadLocalKey(¤tTaskKey);
#endif
task->cap = NULL;
task->worker = worker;
task->stopped = rtsFalse;
- task->stat = NoStatus;
- task->ret = NULL;
+ task->running_finalizers = rtsFalse;
task->n_spare_incalls = 0;
task->spare_incalls = NULL;
task->incall = NULL;
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;
}
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;
void
boundTaskExiting (Task *task)
{
- task->stopped = rtsTrue;
-
#if defined(THREADED_RTS)
ASSERT(osThreadId() == task->id);
#endif
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");
}
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) {
}
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
#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
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