#endif
/* Signal that a capability is available */
signalCondition(&thread_ready_cond);
+ startSchedulerTaskIfNecessary(); // if there is more work to be done,
+ // we'll need a new thread
}
#endif
#ifdef RTS_SUPPORTS_THREADS
*/
static Condition *passTarget = NULL;
+static rtsBool passingCapability = rtsFalse;
void
waitForWorkCapability(Mutex* pMutex, Capability** pCap, Condition* pThreadCond)
IF_DEBUG(scheduler,
fprintf(stderr,"worker thread (%p): wait for cap (cond: %p)\n",
osThreadId(),pThreadCond));
- while ( noCapabilities() || (pThreadCond && passTarget != pThreadCond)
- || (!pThreadCond && passTarget)) {
+ while ( noCapabilities() || (passingCapability && passTarget != pThreadCond)) {
if(pThreadCond)
{
waitCondition(pThreadCond, pMutex);
osThreadId()));
}
}
- passTarget = NULL;
+ passingCapability = rtsFalse;
grabCapability(pCap);
return;
}
rts_n_free_capabilities = 1;
signalCondition(pTargetThreadCond);
passTarget = pTargetThreadCond;
+ passingCapability = rtsTrue;
IF_DEBUG(scheduler,
fprintf(stderr,"worker thread (%p): passCapability\n",
osThreadId()));
}
+/*
+ * Function: passCapabilityToWorker(Mutex*, Capability*)
+ *
+ * Purpose: Let go of the capability and make sure that a
+ * "plain" worker thread (not a bound thread) gets it next.
+ *
+ * Pre-condition: pMutex is held and cap is held by the current thread
+ * Post-condition: pMutex is held; cap will be grabbed by the "target"
+ * thread when pMutex is released.
+ */
+
+void
+passCapabilityToWorker(Mutex* pMutex, Capability* cap)
+{
+#ifdef SMP
+ #error SMP version not implemented
+#endif
+ rts_n_free_capabilities = 1;
+ signalCondition(&thread_ready_cond);
+ startSchedulerTaskIfNecessary();
+ passTarget = NULL;
+ passingCapability = rtsTrue;
+ IF_DEBUG(scheduler,
+ fprintf(stderr,"worker thread (%p): passCapabilityToWorker\n",
+ osThreadId()));
+}
+
+
#endif /* RTS_SUPPORTS_THREADS */
extern void yieldToReturningWorker(Mutex* pMutex, Capability** pCap, Condition *pThreadCond);
extern void waitForWorkCapability(Mutex* pMutex, Capability** pCap, Condition *pThreadCond);
extern void passCapability(Mutex* pMutex, Capability* cap, Condition *pTargetThreadCond);
+extern void passCapabilityToWorker(Mutex* pMutex, Capability* cap);
static inline rtsBool needToYieldToReturningWorker(void)
{
/* ----------------------------------------------------------------------------
- * $Id: RtsAPI.c,v 1.48 2003/10/01 10:36:49 wolfgang Exp $
+ * $Id: RtsAPI.c,v 1.49 2003/10/01 10:49:07 wolfgang Exp $
*
* (c) The GHC Team, 1998-2001
*
// b) wake the current worker thread from awaitEvent()
// (so that a thread started by rts_eval* will start immediately)
grabReturnCapability(&sched_mutex,&rtsApiCapability);
-
- // In the RTS hasn't been entered yet,
- // start a RTS task.
- // If there is already a task available (waiting for the work capability),
- // this will do nothing.
- startSchedulerTask();
#endif
}
/* ---------------------------------------------------------------------------
- * $Id: Schedule.c,v 1.175 2003/09/26 13:32:14 panne Exp $
+ * $Id: Schedule.c,v 1.176 2003/10/01 10:49:08 wolfgang Exp $
*
* (c) The GHC Team, 1998-2000
*
StgTSO *MainTSO;
*/
-#if defined(PAR) || defined(RTS_SUPPORTS_THREADS)
+#if defined(RTS_SUPPORTS_THREADS)
+static rtsBool startingWorkerThread = rtsFalse;
+
static void taskStart(void);
static void
taskStart(void)
{
- schedule(NULL,NULL);
+ Capability *cap;
+
+ ACQUIRE_LOCK(&sched_mutex);
+ startingWorkerThread = rtsFalse;
+ waitForWorkCapability(&sched_mutex, &cap, NULL);
+ RELEASE_LOCK(&sched_mutex);
+
+ schedule(NULL,cap);
}
-#endif
-#if defined(RTS_SUPPORTS_THREADS)
void
-startSchedulerTask(void)
+startSchedulerTaskIfNecessary(void)
{
- startTask(taskStart);
+ if(run_queue_hd != END_TSO_QUEUE
+ || blocked_queue_hd != END_TSO_QUEUE
+ || sleeping_queue != END_TSO_QUEUE)
+ {
+ if(!startingWorkerThread)
+ { // we don't want to start another worker thread
+ // just because the last one hasn't yet reached the
+ // "waiting for capability" state
+ startingWorkerThread = rtsTrue;
+ startTask(taskStart);
+ }
+ }
}
#endif
// so just exit right away.
prog_belch("interrupted");
releaseCapability(cap);
- startTask(taskStart); // thread-safe-call to shutdownHaskellAndExit
RELEASE_LOCK(&sched_mutex);
shutdownHaskellAndExit(EXIT_SUCCESS);
#else
// no, the current native thread is bound to a different
// Haskell thread, so pass it to any worker thread
PUSH_ON_RUN_QUEUE(t);
- releaseCapability(cap);
+ passCapabilityToWorker(&sched_mutex, cap);
cap = NULL;
continue;
}
waiting to take over.
*/
IF_DEBUG(scheduler, sched_belch("worker thread (%d, osthread %p): leaving RTS", tok, osThreadId()));
- //if (concCall) { // implementing "safe" as opposed to "threadsafe" is more difficult
- startTask(taskStart);
- //}
#endif
/* Other threads _might_ be available for execution; signal this */
m->ret = ret;
m->stat = NoStatus;
#if defined(RTS_SUPPORTS_THREADS)
- initCondition(&m->wakeup);
#if defined(THREADED_RTS)
initCondition(&m->bound_thread_cond);
+#else
+ initCondition(&m->wakeup);
#endif
#endif
m->ret = ret;
m->stat = NoStatus;
#if defined(RTS_SUPPORTS_THREADS)
- initCondition(&m->wakeup);
#if defined(THREADED_RTS)
initCondition(&m->bound_thread_cond);
+#else
+ initCondition(&m->wakeup);
#endif
#endif
stat = m->stat;
#if defined(RTS_SUPPORTS_THREADS)
- closeCondition(&m->wakeup);
#if defined(THREADED_RTS)
closeCondition(&m->bound_thread_cond);
+#else
+ closeCondition(&m->wakeup);
#endif
#endif
if (tso->what_next == ThreadComplete || tso->what_next == ThreadKilled) {
return;
}
- unblockThread(tso);
+#if defined(RTS_SUPPORTS_THREADS)
+ if (tso->why_blocked != BlockedOnCCall
+ && tso->why_blocked != BlockedOnCCall_NoUnblockExc)
+#endif
+ unblockThread(tso);
tso->what_next = ThreadKilled;
}
#endif
/* -----------------------------------------------------------------------------
- * $Id: Schedule.h,v 1.39 2003/09/21 22:20:56 wolfgang Exp $
+ * $Id: Schedule.h,v 1.40 2003/10/01 10:49:09 wolfgang Exp $
*
* (c) The GHC Team 1998-1999
*
SchedulerStatus stat;
StgClosure ** ret;
#if defined(RTS_SUPPORTS_THREADS)
- Condition wakeup;
#if defined(THREADED_RTS)
Condition bound_thread_cond;
+#else
+ Condition wakeup;
#endif
#endif
struct StgMainThread_ *link;
#if defined(RTS_SUPPORTS_THREADS)
/* If no task is waiting for a capability,
+ * and if there is work to be done
+ * or if we need to wait for IO or delay requests,
* spawn a new worker thread.
- *
- * (Used by the RtsAPI)
*/
void
-startSchedulerTask(void);
+startSchedulerTaskIfNecessary(void);
#endif
#endif /* __SCHEDULE_H__ */
/* -----------------------------------------------------------------------------
- * $Id: Select.c,v 1.29 2003/06/26 12:22:59 stolz Exp $
+ * $Id: Select.c,v 1.30 2003/10/01 10:49:09 wolfgang Exp $
*
* (c) The GHC Team 1995-2002
*
workerWakeupPending = rtsTrue;
}
}
+
+/* resetWorkerWakeupPipeAfterFork
+ *
+ * To be called right after a fork().
+ * After the fork(), the worker wakeup pipe will be shared
+ * with the parent process, and that's something we don't want.
+ */
+void
+resetWorkerWakeupPipeAfterFork()
+{
+ if(workerWakeupInited) {
+ close(workerWakeupPipe[0]);
+ close(workerWakeupPipe[1]);
+ }
+ workerWakeupInited = rtsFalse;
+}
#endif
return;
}
+void
+resetTaskManagerAfterFork ()
+{
+ barf("resetTaskManagerAfterFork not implemented for SMP");
+}
+
#else
/************ THREADS version *****************/
{
}
+
+void
+resetTaskManagerAfterFork ()
+{
+ rts_n_waiting_tasks = 0;
+ taskCount = 0;
+}
#endif
extern void startTaskManager ( nat maxTasks, void (*taskStart)(void) );
extern void stopTaskManager ( void );
+void resetTaskManagerAfterFork ();
extern void startTask ( void (*taskStart)(void) );