X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Frts%2FSchedule.h;h=63dfeb7dd51f89c82788f7f639acb426efbf8366;hb=5638488ba28ec84fbf64bf2742a040e3fa30bed4;hp=e7b51ba8675a040889784cc742f4bbc0007d5d83;hpb=9ac55e08e159d7a4647ab01e7872e69dd762f275;p=ghc-hetmet.git diff --git a/ghc/rts/Schedule.h b/ghc/rts/Schedule.h index e7b51ba..63dfeb7 100644 --- a/ghc/rts/Schedule.h +++ b/ghc/rts/Schedule.h @@ -1,44 +1,32 @@ /* ----------------------------------------------------------------------------- - * $Id: Schedule.h,v 1.21 2000/12/04 12:31:21 simonmar Exp $ * - * (c) The GHC Team 1998-1999 + * (c) The GHC Team 1998-2005 * * Prototypes for functions in Schedule.c * (RTS internal scheduler interface) * * -------------------------------------------------------------------------*/ -//@menu -//* Scheduler Functions:: -//* Scheduler Vars and Data Types:: -//* Some convenient macros:: -//* Index:: -//@end menu +#ifndef SCHEDULE_H +#define SCHEDULE_H -//@node Scheduler Functions, Scheduler Vars and Data Types -//@subsection Scheduler Functions +#include "OSThreads.h" +#include "Capability.h" -//@cindex initScheduler -//@cindex exitScheduler -//@cindex startTasks -/* initScheduler(), exitScheduler(), startTasks() - * +/* initScheduler(), exitScheduler() * Called from STG : no * Locks assumed : none */ -void initScheduler( void ); -void exitScheduler( void ); -#ifdef SMP -void startTasks( void ); -#endif +void initScheduler (void); +void exitScheduler (void); +// Place a new thread on the run queue of the specified Capability +void scheduleThread (Capability *cap, StgTSO *tso); -//@cindex awakenBlockedQueue /* awakenBlockedQueue() * * Takes a pointer to the beginning of a blocked TSO queue, and * wakes up the entire queue. - * * Called from STG : yes * Locks assumed : none */ @@ -47,25 +35,17 @@ void awakenBlockedQueue(StgBlockingQueueElement *q, StgClosure *node); #elif defined(PAR) void awakenBlockedQueue(StgBlockingQueueElement *q, StgClosure *node); #else -void awakenBlockedQueue(StgTSO *tso); +void awakenBlockedQueue (Capability *cap, StgTSO *tso); #endif -//@cindex unblockOne /* unblockOne() * - * Takes a pointer to the beginning of a blocked TSO queue, and - * removes the first thread, placing it on the runnable queue. - * - * Called from STG : yes - * Locks assumed : none + * Put the specified thread on the run queue of the given Capability. + * Called from STG : yes + * Locks assumed : we own the Capability. */ -#if defined(GRAN) || defined(PAR) -StgBlockingQueueElement *unblockOne(StgBlockingQueueElement *bqe, StgClosure *node); -#else -StgTSO *unblockOne(StgTSO *tso); -#endif +StgTSO * unblockOne(Capability *cap, StgTSO *tso); -//@cindex raiseAsync /* raiseAsync() * * Raises an exception asynchronously in the specified thread. @@ -73,29 +53,39 @@ StgTSO *unblockOne(StgTSO *tso); * Called from STG : yes * Locks assumed : none */ -void raiseAsync(StgTSO *tso, StgClosure *exception); +void raiseAsync(Capability *cap, StgTSO *tso, StgClosure *exception); -//@cindex awaitEvent -/* awaitEvent() - * - * Raises an exception asynchronously in the specified thread. +/* suspendComputation() * - * Called from STG : NO - * Locks assumed : sched_mutex + * A variant of raiseAsync(), this strips the stack of the specified + * thread down to the stop_here point, leaving a current closure on + * top of the stack at [stop_here - 1]. */ -void awaitEvent(rtsBool wait); /* In Select.c */ +void suspendComputation(Capability *cap, StgTSO *tso, StgPtr stop_here); -/* wakeUpSleepingThreads(nat ticks) +/* raiseExceptionHelper */ +StgWord raiseExceptionHelper (StgRegTable *reg, StgTSO *tso, StgClosure *exception); + +/* findRetryFrameHelper */ +StgWord findRetryFrameHelper (StgTSO *tso); + +/* GetRoots(evac_fn f) * - * Wakes up any sleeping threads whose timers have expired. + * Call f() for each root known to the scheduler. * * Called from STG : NO - * Locks assumed : sched_mutex + * Locks assumed : ???? */ -rtsBool wakeUpSleepingThreads(nat); /* In Select.c */ +void GetRoots(evac_fn); + +/* workerStart() + * + * Entry point for a new worker task. + * Called from STG : NO + * Locks assumed : none + */ +void workerStart(Task *task); -// ToDo: check whether all fcts below are used in the SMP version, too -//@cindex awaken_blocked_queue #if defined(GRAN) void awaken_blocked_queue(StgBlockingQueueElement *q, StgClosure *node); void unlink_from_bq(StgTSO* tso, StgClosure* node); @@ -111,34 +101,37 @@ void awaken_blocked_queue(StgTSO *q); void initThread(StgTSO *tso, nat stack_size); #endif -//@node Scheduler Vars and Data Types, Some convenient macros, Scheduler Functions -//@subsection Scheduler Vars and Data Types - -//@cindex context_switch /* Context switch flag. - * Locks required : sched_mutex + * Locks required : none (conflicts are harmless) */ -extern nat context_switch; -extern rtsBool interrupted; - -/* In Select.c */ -extern nat timestamp; -extern nat ticks_since_timestamp; +extern int RTS_VAR(context_switch); -//@cindex Capability -/* Capability type +/* The state of the scheduler. This is used to control the sequence + * of events during shutdown, and when the runtime is interrupted + * using ^C. */ -typedef StgRegTable Capability; +#define SCHED_RUNNING 0 /* running as normal */ +#define SCHED_INTERRUPTING 1 /* ^C detected, before threads are deleted */ +#define SCHED_INTERRUPTED 2 /* ^C detected, after threads deleted */ +#define SCHED_SHUTTING_DOWN 3 /* final shutdown */ -/* Free capability list. - * Locks required: sched_mutex. +extern rtsBool RTS_VAR(sched_state); + +/* + * flag that tracks whether we have done any execution in this time slice. */ -#ifdef SMP -extern Capability *free_capabilities; -extern nat n_free_capabilities; -#else -extern Capability MainRegTable; -#endif +#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 */ + +/* Recent activity flag. + * Locks required : Transition from MAYBE_NO to INACTIVE + * happens in the timer signal, so it is atomic. Trnasition from + * INACTIVE to DONE_GC happens under sched_mutex. No lock required + * to set it to ACTIVITY_YES. + */ +extern nat recent_activity; /* Thread queues. * Locks required : sched_mutex @@ -148,152 +141,165 @@ extern Capability MainRegTable; #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(blackhole_queue); +#if !defined(THREADED_RTS) +extern StgTSO *RTS_VAR(blocked_queue_hd), *RTS_VAR(blocked_queue_tl); +extern StgTSO *RTS_VAR(sleeping_queue); #endif -/* Linked list of all threads. */ -extern StgTSO *all_threads; - -#ifdef SMP -//@cindex sched_mutex -//@cindex thread_ready_cond -//@cindex gc_pending_cond -extern pthread_mutex_t sched_mutex; -extern pthread_cond_t thread_ready_cond; -extern pthread_cond_t gc_pending_cond; #endif -//@cindex task_info -#ifdef SMP -typedef struct { - pthread_t id; - double elapsedtimestart; - double mut_time; - double mut_etime; - double gc_time; - double gc_etime; -} task_info; - -extern task_info *task_ids; +/* Linked list of all threads. + * Locks required : sched_mutex + */ +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. + * Locks required : none (see scheduleCheckBlackHoles()). + */ +extern rtsBool blackholes_need_checking; + +#if defined(THREADED_RTS) +extern Mutex RTS_VAR(sched_mutex); #endif -/* Needed by Hugs. - */ -void interruptStgRts ( void ); +StgBool isThreadBound(StgTSO *tso); + +SchedulerStatus rts_mainLazyIO(HaskellObj p, /*out*/HaskellObj *ret); -void raiseAsync(StgTSO *tso, StgClosure *exception); -nat run_queue_len(void); +/* Called by shutdown_handler(). */ +void interruptStgRts (void); -void resurrectThreads( StgTSO * ); +nat run_queue_len (void); -//@node Some convenient macros, Index, Scheduler Vars and Data Types -//@subsection Some convenient macros +void resurrectThreads (StgTSO *); + +void printAllThreads(void); /* debugging only */ #ifdef DEBUG -void printThreadBlockage(StgTSO *tso); -void printThreadStatus(StgTSO *tso); -void printAllThreads(void); -#endif void print_bq (StgClosure *node); +#endif +#if defined(PAR) +void print_bqe (StgBlockingQueueElement *bqe); +#endif + +void labelThread(StgPtr tso, char *label); /* ----------------------------------------------------------------------------- - * Some convenient macros... + * Some convenient macros/inline functions... */ -/* this is the NIL ptr for a TSO queue (e.g. runnable queue) */ -#define END_TSO_QUEUE ((StgTSO *)(void*)&stg_END_TSO_QUEUE_closure) -/* this is the NIL ptr for a list CAFs */ -#define END_ECAF_LIST ((StgCAF *)(void*)&stg_END_TSO_QUEUE_closure) +#if !IN_STG_CODE + +/* END_TSO_QUEUE and friends now defined in includes/StgMiscClosures.h */ -//@cindex APPEND_TO_RUN_QUEUE /* Add a thread to the end of the run queue. * NOTE: tso->link should be END_TSO_QUEUE before calling this macro. + * ASSUMES: cap->running_task is the current task. */ -#define APPEND_TO_RUN_QUEUE(tso) \ - ASSERT(tso->link == END_TSO_QUEUE); \ - if (run_queue_hd == END_TSO_QUEUE) { \ - run_queue_hd = tso; \ - } else { \ - run_queue_tl->link = tso; \ - } \ - run_queue_tl = tso; - -//@cindex PUSH_ON_RUN_QUEUE +STATIC_INLINE void +appendToRunQueue (Capability *cap, StgTSO *tso) +{ + ASSERT(tso->link == END_TSO_QUEUE); + if (cap->run_queue_hd == END_TSO_QUEUE) { + cap->run_queue_hd = tso; + } else { + cap->run_queue_tl->link = tso; + } + cap->run_queue_tl = tso; +} + /* Push a thread on the beginning of the run queue. Used for * newly awakened threads, so they get run as soon as possible. + * ASSUMES: cap->running_task is the current task. */ -#define PUSH_ON_RUN_QUEUE(tso) \ - tso->link = run_queue_hd; \ - run_queue_hd = tso; \ - if (run_queue_tl == END_TSO_QUEUE) { \ - run_queue_tl = tso; \ +STATIC_INLINE void +pushOnRunQueue (Capability *cap, StgTSO *tso) +{ + tso->link = cap->run_queue_hd; + cap->run_queue_hd = tso; + if (cap->run_queue_tl == END_TSO_QUEUE) { + cap->run_queue_tl = tso; } +} -//@cindex POP_RUN_QUEUE /* 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; \ - if (run_queue_hd == END_TSO_QUEUE) { \ - run_queue_tl = END_TSO_QUEUE; \ - } \ - } \ - t; \ - }) - -//@cindex APPEND_TO_BLOCKED_QUEUE +STATIC_INLINE StgTSO * +popRunQueue (Capability *cap) +{ + StgTSO *t = cap->run_queue_hd; + ASSERT(t != END_TSO_QUEUE); + cap->run_queue_hd = t->link; + t->link = END_TSO_QUEUE; + if (cap->run_queue_hd == END_TSO_QUEUE) { + cap->run_queue_tl = END_TSO_QUEUE; + } + return t; +} + /* Add a thread to the end of the blocked queue. */ -#define APPEND_TO_BLOCKED_QUEUE(tso) \ - ASSERT(tso->link == END_TSO_QUEUE); \ - if (blocked_queue_hd == END_TSO_QUEUE) { \ - blocked_queue_hd = tso; \ - } else { \ - blocked_queue_tl->link = tso; \ - } \ +#if !defined(THREADED_RTS) +STATIC_INLINE void +appendToBlockedQueue(StgTSO *tso) +{ + ASSERT(tso->link == END_TSO_QUEUE); + if (blocked_queue_hd == END_TSO_QUEUE) { + blocked_queue_hd = tso; + } else { + blocked_queue_tl->link = tso; + } blocked_queue_tl = tso; +} +#endif -//@cindex THREAD_RUNNABLE -/* Signal that a runnable thread has become available, in - * case there are any waiting tasks to execute it. +/* Check whether various thread queues are empty */ -#ifdef SMP -#define THREAD_RUNNABLE() \ - if (free_capabilities != NULL) { \ - pthread_cond_signal(&thread_ready_cond); \ - } \ - context_switch = 1; -#else -#define THREAD_RUNNABLE() /* nothing */ +STATIC_INLINE rtsBool +emptyQueue (StgTSO *q) +{ + return (q == END_TSO_QUEUE); +} + +STATIC_INLINE rtsBool +emptyRunQueue(Capability *cap) +{ + return emptyQueue(cap->run_queue_hd); +} + +#if !defined(THREADED_RTS) +#define EMPTY_BLOCKED_QUEUE() (emptyQueue(blocked_queue_hd)) +#define EMPTY_SLEEPING_QUEUE() (emptyQueue(sleeping_queue)) +#endif + +STATIC_INLINE rtsBool +emptyThreadQueues(Capability *cap) +{ + return emptyRunQueue(cap) +#if !defined(THREADED_RTS) + && EMPTY_BLOCKED_QUEUE() && EMPTY_SLEEPING_QUEUE() #endif + ; +} + +#ifdef DEBUG +void sched_belch(char *s, ...) + GNU_ATTRIBUTE(format (printf, 1, 2)); +#endif + +#endif /* !IN_STG_CODE */ + +STATIC_INLINE void +dirtyTSO (StgTSO *tso) +{ + tso->flags |= TSO_DIRTY; +} + +#endif /* SCHEDULE_H */ -//@node Index, , Some convenient macros -//@subsection Index - -//@index -//* APPEND_TO_BLOCKED_QUEUE:: @cindex\s-+APPEND_TO_BLOCKED_QUEUE -//* APPEND_TO_RUN_QUEUE:: @cindex\s-+APPEND_TO_RUN_QUEUE -//* Capability:: @cindex\s-+Capability -//* POP_RUN_QUEUE :: @cindex\s-+POP_RUN_QUEUE -//* PUSH_ON_RUN_QUEUE:: @cindex\s-+PUSH_ON_RUN_QUEUE -//* THREAD_RUNNABLE:: @cindex\s-+THREAD_RUNNABLE -//* awaitEvent:: @cindex\s-+awaitEvent -//* awakenBlockedQueue:: @cindex\s-+awakenBlockedQueue -//* awaken_blocked_queue:: @cindex\s-+awaken_blocked_queue -//* context_switch:: @cindex\s-+context_switch -//* exitScheduler:: @cindex\s-+exitScheduler -//* gc_pending_cond:: @cindex\s-+gc_pending_cond -//* initScheduler:: @cindex\s-+initScheduler -//* raiseAsync:: @cindex\s-+raiseAsync -//* sched_mutex:: @cindex\s-+sched_mutex -//* startTasks:: @cindex\s-+startTasks -//* task_info:: @cindex\s-+task_info -//* thread_ready_cond:: @cindex\s-+thread_ready_cond -//* unblockOne:: @cindex\s-+unblockOne -//@end index