X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;ds=sidebyside;f=ghc%2Frts%2FSchedule.h;h=c4560ed1003454ec911ce6367d3bd4eb64fa7680;hb=e15f2200821e56b081ebbf012c78aa83dcc47869;hp=7722802cbddcd302699d9777751f727576db3632;hpb=d9d8ab1594dd83d25708dc0d20dfd8e068f1c2e3;p=ghc-hetmet.git diff --git a/ghc/rts/Schedule.h b/ghc/rts/Schedule.h index 7722802..c4560ed 100644 --- a/ghc/rts/Schedule.h +++ b/ghc/rts/Schedule.h @@ -1,5 +1,4 @@ /* ----------------------------------------------------------------------------- - * $Id: Schedule.h,v 1.35 2002/07/25 18:37:00 sof Exp $ * * (c) The GHC Team 1998-1999 * @@ -33,7 +32,8 @@ void awakenBlockedQueue(StgBlockingQueueElement *q, StgClosure *node); #elif defined(PAR) void awakenBlockedQueue(StgBlockingQueueElement *q, StgClosure *node); #else -void awakenBlockedQueue(StgTSO *tso); +void awakenBlockedQueue (StgTSO *tso); +void awakenBlockedQueueNoLock (StgTSO *tso); #endif /* unblockOne() @@ -46,8 +46,10 @@ void awakenBlockedQueue(StgTSO *tso); */ #if defined(GRAN) || defined(PAR) StgBlockingQueueElement *unblockOne(StgBlockingQueueElement *bqe, StgClosure *node); +StgBlockingQueueElement *unblockOneLocked(StgBlockingQueueElement *bqe, StgClosure *node); #else StgTSO *unblockOne(StgTSO *tso); +StgTSO *unblockOneLocked(StgTSO *tso); #endif /* raiseAsync() @@ -60,9 +62,15 @@ StgTSO *unblockOne(StgTSO *tso); void raiseAsync(StgTSO *tso, StgClosure *exception); void raiseAsyncWithLock(StgTSO *tso, StgClosure *exception); -/* awaitEvent() +/* raiseExceptionHelper */ +StgWord raiseExceptionHelper (StgTSO *tso, StgClosure *exception); + +/* findRetryFrameHelper */ +StgWord findRetryFrameHelper (StgTSO *tso); + +/* awaitEvent(rtsBool wait) * - * Raises an exception asynchronously in the specified thread. + * Checks for blocked threads that need to be woken. * * Called from STG : NO * Locks assumed : sched_mutex @@ -76,7 +84,25 @@ void awaitEvent(rtsBool wait); /* In Select.c */ * Called from STG : NO * Locks assumed : sched_mutex */ -rtsBool wakeUpSleepingThreads(nat); /* In Select.c */ +rtsBool wakeUpSleepingThreads(lnat); /* In Select.c */ + +/* wakeBlockedWorkerThread() + * + * If a worker thread is currently blocked in awaitEvent(), interrupt it. + * + * Called from STG : NO + * Locks assumed : sched_mutex + */ +void wakeBlockedWorkerThread(void); /* In Select.c */ + +/* resetWorkerWakeupPipeAfterFork() + * + * Notify Select.c that a fork() has occured + * + * Called from STG : NO + * Locks assumed : don't care, but must be called right after fork() + */ +void resetWorkerWakeupPipeAfterFork(void); /* In Select.c */ /* GetRoots(evac_fn f) * @@ -106,11 +132,20 @@ void initThread(StgTSO *tso, nat stack_size); /* Context switch flag. * Locks required : sched_mutex */ -extern nat context_switch; -extern rtsBool interrupted; +extern int RTS_VAR(context_switch); +extern rtsBool RTS_VAR(interrupted); + +/* + * flag that tracks whether we have done any execution in this time slice. + */ +#define ACTIVITY_YES 0 /* there has been activity in the current slice */ +#define ACTIVITY_MAYBE_NO 1 /* no activity in the current slice */ +#define ACTIVITY_INACTIVE 2 /* a complete slice has passed with no activity */ +#define ACTIVITY_DONE_GC 3 /* like 2, but we've done a GC too */ +extern nat recent_activity; /* In Select.c */ -extern nat timestamp; +extern lnat RTS_VAR(timestamp); /* Thread queues. * Locks required : sched_mutex @@ -120,25 +155,33 @@ extern nat timestamp; #if defined(GRAN) // run_queue_hds defined in GranSim.h #else -extern StgTSO *run_queue_hd, *run_queue_tl; -extern StgTSO *blocked_queue_hd, *blocked_queue_tl; -extern StgTSO *sleeping_queue; +extern StgTSO *RTS_VAR(run_queue_hd), *RTS_VAR(run_queue_tl); +extern StgTSO *RTS_VAR(blocked_queue_hd), *RTS_VAR(blocked_queue_tl); +extern StgTSO *RTS_VAR(blackhole_queue); +extern StgTSO *RTS_VAR(sleeping_queue); #endif /* Linked list of all threads. */ -extern StgTSO *all_threads; +extern StgTSO *RTS_VAR(all_threads); + +/* Set to rtsTrue if there are threads on the blackhole_queue, and + * it is possible that one or more of them may be available to run. + * This flag is set to rtsFalse after we've checked the queue, and + * set to rtsTrue just before we run some Haskell code. It is used + * to decide whether we should yield the Capability or not. + */ +extern rtsBool blackholes_need_checking; #if defined(RTS_SUPPORTS_THREADS) /* Schedule.c has detailed info on what these do */ -extern Mutex sched_mutex; -extern Condition thread_ready_cond; -extern Condition returning_worker_cond; -extern nat rts_n_waiting_workers; -extern nat rts_n_waiting_tasks; +extern Mutex RTS_VAR(sched_mutex); +extern Condition RTS_VAR(returning_worker_cond); +extern nat RTS_VAR(rts_n_waiting_workers); +extern nat RTS_VAR(rts_n_waiting_tasks); #endif -StgInt forkProcess(StgTSO *tso); +StgBool isThreadBound(StgTSO *tso); -extern SchedulerStatus rts_mainEvalIO(HaskellObj p, /*out*/HaskellObj *ret); +extern SchedulerStatus rts_mainLazyIO(HaskellObj p, /*out*/HaskellObj *ret); /* Called by shutdown_handler(). */ @@ -153,11 +196,13 @@ void resurrectThreads( StgTSO * ); * * These are the threads which clients have requested that we run. * - * In a 'threaded' build, we might have several concurrent clients all - * waiting for results, and each one will wait on a condition variable - * until the result is available. + * In a 'threaded' build, each of these corresponds to one bound thread. + * The pointer to the StgMainThread is passed as a parameter to schedule; + * this invocation of schedule will always pass this main thread's + * bound_thread_cond to waitForkWorkCapability; OS-thread-switching + * takes place using passCapability. * - * In non-SMP, clients are strictly nested: the first client calls + * In non-threaded builds, clients are strictly nested: the first client calls * into the RTS, which might call out again to C with a _ccall_GC, and * eventually re-enter the RTS. * @@ -173,8 +218,9 @@ typedef struct StgMainThread_ { SchedulerStatus stat; StgClosure ** ret; #if defined(RTS_SUPPORTS_THREADS) - Condition wakeup; + Condition bound_thread_cond; #endif + struct StgMainThread_ *prev; struct StgMainThread_ *link; } StgMainThread; @@ -197,6 +243,8 @@ void print_bq (StgClosure *node); void print_bqe (StgBlockingQueueElement *bqe); #endif +void labelThread(StgPtr tso, char *label); + /* ----------------------------------------------------------------------------- * Some convenient macros... */ @@ -227,17 +275,17 @@ void print_bqe (StgBlockingQueueElement *bqe); /* Pop the first thread off the runnable queue. */ -#define POP_RUN_QUEUE() \ - ({ StgTSO *t = run_queue_hd; \ - if (t != END_TSO_QUEUE) { \ - run_queue_hd = t->link; \ - t->link = END_TSO_QUEUE; \ +#define POP_RUN_QUEUE(pt) \ + do { StgTSO *__tmp_t = run_queue_hd; \ + if (__tmp_t != END_TSO_QUEUE) { \ + run_queue_hd = __tmp_t->link; \ + __tmp_t->link = END_TSO_QUEUE; \ if (run_queue_hd == END_TSO_QUEUE) { \ run_queue_tl = END_TSO_QUEUE; \ } \ } \ - t; \ - }) + pt = __tmp_t; \ + } while(0) /* Add a thread to the end of the blocked queue. */ @@ -250,19 +298,6 @@ void print_bqe (StgBlockingQueueElement *bqe); } \ blocked_queue_tl = tso; -/* Signal that a runnable thread has become available, in - * case there are any waiting tasks to execute it. - */ -#if defined(RTS_SUPPORTS_THREADS) -#define THREAD_RUNNABLE() \ - if ( !noCapabilities() ) { \ - signalCondition(&thread_ready_cond); \ - } \ - context_switch = 1; -#else -#define THREAD_RUNNABLE() /* nothing */ -#endif - /* Check whether various thread queues are empty */ #define EMPTY_QUEUE(q) (q == END_TSO_QUEUE) @@ -275,4 +310,19 @@ void print_bqe (StgBlockingQueueElement *bqe); EMPTY_BLOCKED_QUEUE() && \ EMPTY_SLEEPING_QUEUE()) +#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. + */ +void +startSchedulerTaskIfNecessary(void); +#endif + +#ifdef DEBUG +extern void sched_belch(char *s, ...) + GNU_ATTRIBUTE(format (printf, 1, 2)); +#endif + #endif /* __SCHEDULE_H__ */