diff --git a/ghc/includes/PrimOps.h b/ghc/includes/PrimOps.h index 6dd2209ec9d10bd4fd432f38310b28a85b85c392..77e74c3d409b94a7325a373c6a2b16f894372ad4 100644 --- a/ghc/includes/PrimOps.h +++ b/ghc/includes/PrimOps.h @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: PrimOps.h,v 1.36 1999/08/25 10:23:51 simonmar Exp $ + * $Id: PrimOps.h,v 1.37 1999/08/25 16:11:43 simonmar Exp $ * * (c) The GHC Team, 1998-1999 * @@ -663,7 +663,9 @@ EF_(putMVarzh_fast); Delay/Wait PrimOps -------------------------------------------------------------------------- */ -/* Hmm, I'll think about these later. */ +EF_(waitReadzh_fast); +EF_(waitWritezh_fast); +EF_(delayzh_fast); /* ----------------------------------------------------------------------------- Primitive I/O, error-handling PrimOps diff --git a/ghc/includes/Rts.h b/ghc/includes/Rts.h index 77f095cc745fe064c4131bbd16c9e94166fe4e6b..1dc23dd37474b0eae52f78bdbab0ff0ce2d05f76 100644 --- a/ghc/includes/Rts.h +++ b/ghc/includes/Rts.h @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: Rts.h,v 1.6 1999/02/05 16:02:27 simonm Exp $ + * $Id: Rts.h,v 1.7 1999/08/25 16:11:44 simonmar Exp $ * * (c) The GHC Team, 1998-1999 * @@ -85,6 +85,4 @@ typedef enum { #define stg_min(a,b) ({typeof(a) _a = (a), _b = (b); _a <= _b ? _a : _b; }) #define stg_max(a,b) ({typeof(a) _a = (a), _b = (b); _a <= _b ? _b : _a; }) -#define UNUSED __attribute__((unused)) - #endif RTS_H diff --git a/ghc/includes/TSO.h b/ghc/includes/TSO.h index dd568bd148b9f3d440eaa5e728ee7e977a74c1d0..2c53ab9b67517cda13caf46cb3e92b1c7511d9ca 100644 --- a/ghc/includes/TSO.h +++ b/ghc/includes/TSO.h @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: TSO.h,v 1.7 1999/05/11 16:47:42 keithw Exp $ + * $Id: TSO.h,v 1.8 1999/08/25 16:11:44 simonmar Exp $ * * (c) The GHC Team, 1998-1999 * @@ -70,6 +70,29 @@ typedef enum { ThreadFinished } StgThreadReturnCode; +/* + * Threads may be blocked for several reasons. A blocked thread will + * have the reason in the why_blocked field of the TSO, and some + * further info (such as the closure the thread is blocked on, or the + * file descriptor if the thread is waiting on I/O) in the block_info + * field. + */ + +typedef enum { + NotBlocked, + BlockedOnMVar, + BlockedOnBlackHole, + BlockedOnRead, + BlockedOnWrite, + BlockedOnDelay +} StgTSOBlockReason; + +typedef union { + StgClosure *closure; + int fd; + unsigned int delay; +} StgTSOBlockInfo; + /* * TSOs live on the heap, and therefore look just like heap objects. * Large TSOs will live in their own "block group" allocated by the @@ -81,7 +104,8 @@ typedef struct StgTSO_ { struct StgTSO_* link; StgMutClosure * mut_link; /* TSO's are mutable of course! */ StgTSOWhatNext whatNext; - StgClosure * blocked_on; + StgTSOBlockReason why_blocked; + StgTSOBlockInfo block_info; StgThreadID id; StgTSOTickyInfo ticky; StgTSOProfInfo prof; diff --git a/ghc/includes/Updates.h b/ghc/includes/Updates.h index 753da3c8d1aed9bf424ba76afff37c41a0f4522c..e142cd0e9ec1c52e1728160352aae73f7de83755 100644 --- a/ghc/includes/Updates.h +++ b/ghc/includes/Updates.h @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: Updates.h,v 1.11 1999/05/13 17:31:08 simonm Exp $ + * $Id: Updates.h,v 1.12 1999/08/25 16:11:44 simonmar Exp $ * * (c) The GHC Team, 1998-1999 * @@ -51,13 +51,13 @@ Awaken any threads waiting on this computation -------------------------------------------------------------------------- */ -extern void awaken_blocked_queue(StgTSO *q); +extern void awakenBlockedQueue(StgTSO *q); #define AWAKEN_BQ(closure) \ if (closure->header.info == &BLACKHOLE_BQ_info) { \ StgTSO *bq = ((StgBlockingQueue *)closure)->blocking_queue;\ if (bq != (StgTSO *)&END_TSO_QUEUE_closure) { \ - STGCALL1(awaken_blocked_queue, bq); \ + STGCALL1(awakenBlockedQueue, bq); \ } \ } diff --git a/ghc/lib/concurrent/Concurrent.lhs b/ghc/lib/concurrent/Concurrent.lhs index de342c6e4328e555dce6def635a7ff0649e326c2..befeaa64ec7da90f5308018f6bab3a1e4174ec7c 100644 --- a/ghc/lib/concurrent/Concurrent.lhs +++ b/ghc/lib/concurrent/Concurrent.lhs @@ -31,7 +31,9 @@ module Concurrent ( , fork -- :: a -> b -> b , yield -- :: IO () - {-threadDelay, threadWaitRead, threadWaitWrite,-} + , threadDelay -- :: Int -> IO () + , threadWaitRead -- :: Int -> IO () + , threadWaitWrite -- :: Int -> IO () -- MVars , MVar -- abstract @@ -54,7 +56,8 @@ import Channel import Semaphore import SampleVar import PrelConc -import PrelHandle ( topHandler ) +import PrelHandle ( topHandler, threadDelay, + threadWaitRead, threadWaitWrite ) import PrelException import PrelIOBase ( IO(..) ) import IO diff --git a/ghc/rts/GC.c b/ghc/rts/GC.c index b32274f235e462f9206ccce8edcd8245ca6d7ddb..7d299beefae0411e46ce37fff996194083940ad4 100644 --- a/ghc/rts/GC.c +++ b/ghc/rts/GC.c @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: GC.c,v 1.60 1999/06/29 13:04:38 panne Exp $ + * $Id: GC.c,v 1.61 1999/08/25 16:11:46 simonmar Exp $ * * (c) The GHC Team 1998-1999 * @@ -1842,8 +1842,9 @@ scavenge(step *step) evac_gen = 0; /* chase the link field for any TSOs on the same queue */ (StgClosure *)tso->link = evacuate((StgClosure *)tso->link); - if (tso->blocked_on) { - tso->blocked_on = evacuate(tso->blocked_on); + if ( tso->why_blocked == BlockedOnMVar + || tso->why_blocked == BlockedOnBlackHole) { + tso->block_info.closure = evacuate(tso->block_info.closure); } /* scavenge this thread's stack */ scavenge_stack(tso->sp, &(tso->stack[tso->stack_size])); @@ -2195,8 +2196,9 @@ scavenge_mutable_list(generation *gen) StgTSO *tso = (StgTSO *)p; (StgClosure *)tso->link = evacuate((StgClosure *)tso->link); - if (tso->blocked_on) { - tso->blocked_on = evacuate(tso->blocked_on); + if ( tso->why_blocked == BlockedOnMVar + || tso->why_blocked == BlockedOnBlackHole) { + tso->block_info.closure = evacuate(tso->block_info.closure); } scavenge_stack(tso->sp, &(tso->stack[tso->stack_size])); @@ -2571,8 +2573,9 @@ scavenge_large(step *step) tso = (StgTSO *)p; /* chase the link field for any TSOs on the same queue */ (StgClosure *)tso->link = evacuate((StgClosure *)tso->link); - if (tso->blocked_on) { - tso->blocked_on = evacuate(tso->blocked_on); + if ( tso->why_blocked == BlockedOnMVar + || tso->why_blocked == BlockedOnBlackHole) { + tso->block_info.closure = evacuate(tso->block_info.closure); } /* scavenge this thread's stack */ scavenge_stack(tso->sp, &(tso->stack[tso->stack_size])); diff --git a/ghc/rts/HeapStackCheck.h b/ghc/rts/HeapStackCheck.h index 3a5e2e4d64c47f3f0968fd971e401ed539e834a9..1f2efeefb9c404d2ac103e45a033bb06f3c82481 100644 --- a/ghc/rts/HeapStackCheck.h +++ b/ghc/rts/HeapStackCheck.h @@ -1,3 +1,12 @@ +/* ----------------------------------------------------------------------------- + * $Id: HeapStackCheck.h,v 1.4 1999/08/25 16:11:48 simonmar Exp $ + * + * (c) The GHC Team, 1998-1999 + * + * Prototypes for functions in HeapStackCheck.hc + * + * ---------------------------------------------------------------------------*/ + EXTFUN(stg_gc_entertop); EXTFUN(stg_gc_enter_1); EXTFUN(stg_gc_enter_2); @@ -38,4 +47,5 @@ EXTFUN(stg_gen_yield); EXTFUN(stg_yield_noregs); EXTFUN(stg_yield_to_Hugs); EXTFUN(stg_gen_block); +EXTFUN(stg_block_noregs); EXTFUN(stg_block_1); diff --git a/ghc/rts/HeapStackCheck.hc b/ghc/rts/HeapStackCheck.hc index e387b0638564bea6474798db427189b45c4db176..8f66e92e30ce8d88771226490e14015f5096e983 100644 --- a/ghc/rts/HeapStackCheck.hc +++ b/ghc/rts/HeapStackCheck.hc @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: HeapStackCheck.hc,v 1.8 1999/05/24 10:58:09 simonmar Exp $ + * $Id: HeapStackCheck.hc,v 1.9 1999/08/25 16:11:48 simonmar Exp $ * * (c) The GHC Team, 1998-1999 * @@ -295,6 +295,10 @@ EXTFUN(stg_gc_seq_1) /*-- No regsiters live (probably a void return) ----------------------------- */ +/* If we change the policy for thread startup to *not* remove the + * return address from the stack, we can get rid of this little + * function/info table... + */ INFO_TABLE_SRT_BITMAP(stg_gc_noregs_ret_info, stg_gc_noregs_ret, 0/*BITMAP*/, 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, RET_SMALL,, EF_, 0, 0); @@ -823,22 +827,11 @@ FN_(stg_gen_yield) FE_ } -INFO_TABLE_SRT_BITMAP(stg_yield_noregs_info, stg_yield_noregs_ret, 0/*BITMAP*/, - 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, - RET_SMALL,, EF_, 0, 0); - -FN_(stg_yield_noregs_ret) -{ - FB_ - JMP_(ENTRY_CODE(Sp[0])); - FE_ -} - FN_(stg_yield_noregs) { FB_ Sp--; - Sp[0] = (W_)&stg_yield_noregs_info; + Sp[0] = (W_)&stg_gc_noregs_ret_info; YIELD_GENERIC; FE_ } @@ -863,6 +856,15 @@ FN_(stg_gen_block) FE_ } +FN_(stg_block_noregs) +{ + FB_ + Sp--; + Sp[0] = (W_)&stg_gc_noregs_ret_info; + BLOCK_GENERIC; + FE_ +} + FN_(stg_block_1) { FB_ diff --git a/ghc/rts/Itimer.c b/ghc/rts/Itimer.c index 5ec8c0d92a4bc1afc1f311dcd84d148156d10d89..bbbb3adebea3a4f66d5431c8ddb5b010f1181cb2 100644 --- a/ghc/rts/Itimer.c +++ b/ghc/rts/Itimer.c @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: Itimer.c,v 1.4 1999/03/03 19:00:07 sof Exp $ + * $Id: Itimer.c,v 1.5 1999/08/25 16:11:48 simonmar Exp $ * * (c) The GHC Team, 1995-1999 * @@ -24,6 +24,7 @@ #include "Rts.h" #include "Itimer.h" +#include "Schedule.h" /* As recommended in the autoconf manual */ # ifdef TIME_WITH_SYS_TIME @@ -41,6 +42,34 @@ # include <windows.h> #endif +lnat total_ticks = 0; +rtsBool do_prof_ticks = rtsFalse; + +static void handle_tick(int unused STG_UNUSED); + +/* ----------------------------------------------------------------------------- + Tick handler + + We use the ticker for two things: supporting threadDelay, and time + profiling. + -------------------------------------------------------------------------- */ + +static void +handle_tick(int unused STG_UNUSED) +{ + total_ticks++; + +#ifdef PROFILING + if (do_prof_ticks = rtsTrue) { + CCS_TICK(CCCS); + } +#endif + + /* For threadDelay etc., see Select.c */ + ticks_since_select++; +} + + /* * Handling timer events under cygwin32 is not done with signal/setitimer. * Instead of the two steps of first registering a signal handler to handle @@ -132,19 +161,19 @@ initialize_virtual_timer(nat ms) #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER)) int -install_vtalrm_handler(void (*handler)(int)) +install_vtalrm_handler(void) { - vtalrm_cback = handler; + vtalrm_cback = handle_tick; return 0; } #else int -install_vtalrm_handler(void (*handler)(int)) +install_vtalrm_handler(void) { struct sigaction action; - action.sa_handler = handler; + action.sa_handler = handle_tick; sigemptyset(&action.sa_mask); action.sa_flags = 0; diff --git a/ghc/rts/Itimer.h b/ghc/rts/Itimer.h index 0876e8445353ad21fbf99a65265c067e93f25c96..fbdf795c8bffed1b22ba270c6688a4d229d8d94b 100644 --- a/ghc/rts/Itimer.h +++ b/ghc/rts/Itimer.h @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: Itimer.h,v 1.3 1999/02/05 16:02:44 simonm Exp $ + * $Id: Itimer.h,v 1.4 1999/08/25 16:11:48 simonmar Exp $ * * (c) The GHC Team 1998-1999 * @@ -7,9 +7,12 @@ * * ---------------------------------------------------------------------------*/ +# define TICK_FREQUENCY 50 /* ticks per second */ +# define TICK_MILLISECS (1000/TICK_FREQUENCY) /* ms per tick */ + +extern rtsBool do_prof_ticks; /* profiling ticks on/off */ + nat initialize_virtual_timer ( nat ms ); -int install_vtalrm_handler ( void (*handler)(int) ); +int install_vtalrm_handler ( void ); void block_vtalrm_signal ( void ); void unblock_vtalrm_signal ( void ); - - diff --git a/ghc/rts/PrimOps.hc b/ghc/rts/PrimOps.hc index 84ecf27840eef35e6f7d4553a3d30cd204a07813..08ca10a6cd9d7cebaf255623c54a80075e20b020 100644 --- a/ghc/rts/PrimOps.hc +++ b/ghc/rts/PrimOps.hc @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: PrimOps.hc,v 1.28 1999/07/14 13:42:28 simonmar Exp $ + * $Id: PrimOps.hc,v 1.29 1999/08/25 16:11:48 simonmar Exp $ * * (c) The GHC Team, 1998-1999 * @@ -842,7 +842,8 @@ FN_(takeMVarzh_fast) mvar->tail->link = CurrentTSO; } CurrentTSO->link = (StgTSO *)&END_TSO_QUEUE_closure; - CurrentTSO->blocked_on = (StgClosure *)mvar; + CurrentTSO->why_blocked = BlockedOnMVar; + CurrentTSO->block_info.closure = (StgClosure *)mvar; mvar->tail = CurrentTSO; BLOCK(R1_PTR, takeMVarzh_fast); @@ -860,7 +861,6 @@ FN_(takeMVarzh_fast) FN_(putMVarzh_fast) { StgMVar *mvar; - StgTSO *tso; FB_ /* args: R1 = MVar, R2 = value */ @@ -874,15 +874,12 @@ FN_(putMVarzh_fast) SET_INFO(mvar,&FULL_MVAR_info); mvar->value = R2.cl; - /* wake up the first thread on the queue, - * it will continue with the takeMVar operation and mark the MVar - * empty again. + /* wake up the first thread on the queue, it will continue with the + * takeMVar operation and mark the MVar empty again. */ - tso = mvar->head; - if (tso != (StgTSO *)&END_TSO_QUEUE_closure) { - PUSH_ON_RUN_QUEUE(tso); - mvar->head = tso->link; - tso->link = (StgTSO *)&END_TSO_QUEUE_closure; + if (mvar->head != (StgTSO *)&END_TSO_QUEUE_closure) { + ASSERT(mvar->head->why_blocked == BlockedOnMVar); + mvar->head = RET_STGCALL1(StgTSO *,unblockOne,mvar->head); if (mvar->head == (StgTSO *)&END_TSO_QUEUE_closure) { mvar->tail = (StgTSO *)&END_TSO_QUEUE_closure; } @@ -924,5 +921,50 @@ FN_(makeStableNamezh_fast) RET_P(sn_obj); } +/* ----------------------------------------------------------------------------- + Thread I/O blocking primitives + -------------------------------------------------------------------------- */ + +FN_(waitReadzh_fast) +{ + FB_ + /* args: R1.i */ + ASSERT(CurrentTSO->why_blocked == NotBlocked); + CurrentTSO->why_blocked = BlockedOnRead; + CurrentTSO->block_info.fd = R1.i; + PUSH_ON_BLOCKED_QUEUE(CurrentTSO); + JMP_(stg_block_noregs); + FE_ +} + +FN_(waitWritezh_fast) +{ + FB_ + /* args: R1.i */ + ASSERT(CurrentTSO->why_blocked == NotBlocked); + CurrentTSO->why_blocked = BlockedOnWrite; + CurrentTSO->block_info.fd = R1.i; + PUSH_ON_BLOCKED_QUEUE(CurrentTSO); + JMP_(stg_block_noregs); + FE_ +} + +FN_(delayzh_fast) +{ + FB_ + /* args: R1.i */ + ASSERT(CurrentTSO->why_blocked == NotBlocked); + CurrentTSO->why_blocked = BlockedOnDelay; + + /* Add on ticks_since_select, since these will be subtracted at + * the next awaitEvent call. + */ + CurrentTSO->block_info.delay = R1.i + ticks_since_select; + + PUSH_ON_BLOCKED_QUEUE(CurrentTSO); + JMP_(stg_block_noregs); + FE_ +} + #endif /* COMPILER */ diff --git a/ghc/rts/ProfRts.h b/ghc/rts/ProfRts.h index 2634f7a623e569695f872e76cbea0482561e0dbc..9c438f2f7b803d27d2bb27bcaf2aa2ff4500a648 100644 --- a/ghc/rts/ProfRts.h +++ b/ghc/rts/ProfRts.h @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: ProfRts.h,v 1.3 1999/02/05 16:02:47 simonm Exp $ + * $Id: ProfRts.h,v 1.4 1999/08/25 16:11:49 simonmar Exp $ * * (c) The GHC Team, 1998-1999 * @@ -23,9 +23,6 @@ void print_ccs (FILE *, CostCentreStack *); void report_ccs_profiling( void ); -# define TICK_FREQUENCY 50 /* ticks per second */ -# define TICK_MILLISECS (1000/TICK_FREQUENCY) /* ms per tick */ - # define DEFAULT_INTERVAL TICK_FREQUENCY extern rtsBool time_profiling; diff --git a/ghc/rts/Profiling.c b/ghc/rts/Profiling.c index 56260b1d194a5771b3892a5c5e37c4ade209f28f..aa11286cf101351119b0a230637c5f8013e9c429 100644 --- a/ghc/rts/Profiling.c +++ b/ghc/rts/Profiling.c @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: Profiling.c,v 1.7 1999/06/29 13:04:40 panne Exp $ + * $Id: Profiling.c,v 1.8 1999/08/25 16:11:49 simonmar Exp $ * * (c) The GHC Team, 1998-1999 * @@ -45,7 +45,7 @@ rtsBool time_profiling = rtsFalse; /* figures for the profiling report. */ -static lnat total_alloc, total_ticks; +static lnat total_alloc, total_prof_ticks; /* Globals for opening the profiling log file */ @@ -183,9 +183,7 @@ initProfiling (void) ccs = next; } - /* profiling is the only client of the VTALRM system at the moment, - * so just install the profiling tick handler. */ - install_vtalrm_handler(handleProfTick); + /* Start ticking */ startProfTimer(); }; @@ -196,7 +194,7 @@ endProfiling ( void ) } void -heapCensus ( bdescr *bd UNUSED ) +heapCensus ( bdescr *bd STG_UNUSED ) { /* nothing yet */ } @@ -512,7 +510,7 @@ report_ccs_profiling( void ) stopProfTimer(); - total_ticks = 0; + total_prof_ticks = 0; total_alloc = 0; count_ticks(CCS_MAIN); @@ -535,8 +533,8 @@ report_ccs_profiling( void ) fprintf(prof_file, "\n\n"); fprintf(prof_file, "\ttotal time = %11.2f secs (%lu ticks @ %d ms)\n", - total_ticks / (StgFloat) TICK_FREQUENCY, - total_ticks, TICK_MILLISECS); + total_prof_ticks / (StgFloat) TICK_FREQUENCY, + total_prof_ticks, TICK_MILLISECS); fprintf(prof_file, "\ttotal alloc = %11s bytes", ullong_format_string((ullong) total_alloc * sizeof(W_), @@ -596,7 +594,7 @@ reportCCS(CostCentreStack *ccs, nat indent) fprintf(prof_file, "%8ld %4.1f %4.1f %8ld %5ld", ccs->scc_count, - total_ticks == 0 ? 0.0 : (ccs->time_ticks / (StgFloat) total_ticks * 100), + total_prof_ticks == 0 ? 0.0 : (ccs->time_ticks / (StgFloat) total_prof_ticks * 100), total_alloc == 0 ? 0.0 : (ccs->mem_alloc / (StgFloat) total_alloc * 100), ccs->sub_scc_count, ccs->sub_cafcc_count); @@ -628,7 +626,7 @@ count_ticks(CostCentreStack *ccs) if (!ccs_to_ignore(ccs)) { total_alloc += ccs->mem_alloc; - total_ticks += ccs->time_ticks; + total_prof_ticks += ccs->time_ticks; } for (i = ccs->indexTable; i != NULL; i = i->next) count_ticks(i->ccs); diff --git a/ghc/rts/Proftimer.c b/ghc/rts/Proftimer.c index b93123a784061bcb0ec8b9aa373c0f7e9a25cfa5..ad5bbd92072c7235f9b955d5c0784e1a71ab4e5f 100644 --- a/ghc/rts/Proftimer.c +++ b/ghc/rts/Proftimer.c @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: Proftimer.c,v 1.4 1999/08/04 17:03:41 panne Exp $ + * $Id: Proftimer.c,v 1.5 1999/08/25 16:11:49 simonmar Exp $ * * (c) The GHC Team, 1998-1999 * @@ -16,8 +16,6 @@ #include "Itimer.h" #include "Proftimer.h" -lnat total_ticks = 0; - nat current_interval = 1; /* Current interval number -- stored in AGE */ @@ -26,21 +24,11 @@ nat interval_ticks = DEFAULT_INTERVAL; /* No of ticks in an interval */ nat previous_ticks = 0; /* ticks in previous intervals */ nat current_ticks = 0; /* ticks in current interval */ -void -initProfTimer(nat ms) -{ - if (initialize_virtual_timer(ms)) { - fflush(stdout); - fprintf(stderr, "Can't initialize virtual timer.\n"); - stg_exit(EXIT_FAILURE); - } -}; - void stopProfTimer(void) { /* Stops time profile */ if (time_profiling) { - initProfTimer(0); + do_prof_ticks = rtsFalse; } }; @@ -48,19 +36,8 @@ void startProfTimer(void) { /* Starts time profile */ if (time_profiling) { - initProfTimer(TICK_MILLISECS); + do_prof_ticks = rtsTrue; } }; -/* For a small collection of signal handler prototypes, see - http://web2.airmail.net/sjbaker1/software/signal_collection.html */ - -void -handleProfTick(int unused) -{ - (void)unused; /* no warnings, please */ - CCS_TICK(CCCS); - total_ticks++; -}; - #endif /* PROFILING */ diff --git a/ghc/rts/Proftimer.h b/ghc/rts/Proftimer.h index 1e1a090e8551cd2ad16dd0b4f35c3cc75bf22f78..38a023ca12bea6fe3e6cf1841a944a809335ab20 100644 --- a/ghc/rts/Proftimer.h +++ b/ghc/rts/Proftimer.h @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: Proftimer.h,v 1.3 1999/08/04 17:03:41 panne Exp $ + * $Id: Proftimer.h,v 1.4 1999/08/25 16:11:50 simonmar Exp $ * * (c) The GHC Team, 1998 * @@ -7,6 +7,8 @@ * * ---------------------------------------------------------------------------*/ +extern lnat total_prof_ticks; + extern void initProfTimer(nat ms); extern void stopProfTimer(void); extern void startProfTimer(void); diff --git a/ghc/rts/RtsFlags.c b/ghc/rts/RtsFlags.c index 3c2af6c2f7f16a2e4be580067c4866b385a8dee3..1615934b1973a54d32e09a1c5db80d4615125f3b 100644 --- a/ghc/rts/RtsFlags.c +++ b/ghc/rts/RtsFlags.c @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: RtsFlags.c,v 1.14 1999/05/20 10:23:42 simonmar Exp $ + * $Id: RtsFlags.c,v 1.15 1999/08/25 16:11:50 simonmar Exp $ * * (c) The AQUA Project, Glasgow University, 1994-1997 * (c) The GHC Team, 1998-1999 @@ -97,23 +97,7 @@ void initRtsFlagsDefaults(void) RtsFlags.ProfFlags.doHeapProfile = rtsFalse; #endif -/* there really shouldn't be a threads limit for concurrent mandatory threads. - For now, unlimitied means less than 64k (there's a storage overhead) -- SOF -*/ -#if defined(CONCURRENT) && !defined(GRAN) RtsFlags.ConcFlags.ctxtSwitchTime = CS_MIN_MILLISECS; /* In milliseconds */ - RtsFlags.ConcFlags.maxThreads = 65536; - RtsFlags.ConcFlags.stkChunkSize = 1024; - RtsFlags.ConcFlags.maxLocalSparks = 65536; -#endif /* CONCURRENT only */ - -#if GRAN - RtsFlags.ConcFlags.ctxtSwitchTime = CS_MIN_MILLISECS; /* In milliseconds */ - RtsFlags.ConcFlags.maxThreads = 32; - RtsFlags.ConcFlags.stkChunkSize = 1024; - RtsFlags.ConcFlags.maxLocalSparks = 500; -#endif /* GRAN */ - #ifdef PAR RtsFlags.ParFlags.parallelStats = rtsFalse; RtsFlags.ParFlags.granSimStats = rtsFalse; @@ -279,16 +263,11 @@ usage_text[] = { " -C<secs> Context-switch interval in seconds", " (0 or no argument means switch as often as possible)", " the default is .01 sec; resolution is .01 sec", -" -e<size> Size of spark pools (default 100)", # ifdef PAR " -q Enable activity profile (output files in ~/<program>*.gr)", " -qb Enable binary activity profile (output file /tmp/<program>.gb)", " -Q<size> Set pack-buffer size (default: 1024)", -# else -" -q[v] Enable quasi-parallel profile (output file <program>.qp)", # endif -" -t<num> Set maximum number of advisory threads per PE (default 32)", -" -o<num> Set stack chunk size (default 1024)", # ifdef PAR " -d Turn on PVM-ish debugging", " -O Disable output for performance measurement", @@ -735,16 +714,6 @@ error = rtsTrue; } break; - case 't': - if (rts_argv[arg][2] != '\0') { - RtsFlags.ConcFlags.maxThreads - = strtol(rts_argv[arg]+2, (char **) NULL, 10); - } else { - fprintf(stderr, "setupRtsFlags: missing size for -t\n"); - error = rtsTrue; - } - break; - /* =========== PARALLEL =========================== */ case 'e': PAR_BUILD_ONLY( diff --git a/ghc/rts/RtsFlags.h b/ghc/rts/RtsFlags.h index a0e6205df61aee3b1668fd313aff23374b776bec..9e7f70c8561c9fa14a19bd6d9ec2a77043838aaa 100644 --- a/ghc/rts/RtsFlags.h +++ b/ghc/rts/RtsFlags.h @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: RtsFlags.h,v 1.14 1999/06/25 09:18:49 simonmar Exp $ + * $Id: RtsFlags.h,v 1.15 1999/08/25 16:11:50 simonmar Exp $ * * (c) The GHC Team, 1998-1999 * @@ -85,6 +85,7 @@ struct COST_CENTRE_FLAGS { #ifdef PROFILING struct PROFILING_FLAGS { unsigned int doHeapProfile; + # define NO_HEAP_PROFILING 0 /* N.B. Used as indexes into arrays */ # define HEAP_BY_CC 1 # define HEAP_BY_MOD 2 @@ -118,7 +119,6 @@ struct PROFILING_FLAGS { struct CONCURRENT_FLAGS { int ctxtSwitchTime; /* in milliseconds */ - int maxThreads; }; #ifdef PAR diff --git a/ghc/rts/RtsStartup.c b/ghc/rts/RtsStartup.c index d87f18862a53548d3f8eafda35aff7b2d17d99d9..f6aaebd080a2855024261eab66611209f7e970a6 100644 --- a/ghc/rts/RtsStartup.c +++ b/ghc/rts/RtsStartup.c @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: RtsStartup.c,v 1.17 1999/07/06 15:33:23 simonmar Exp $ + * $Id: RtsStartup.c,v 1.18 1999/08/25 16:11:50 simonmar Exp $ * * (c) The GHC Team, 1998-1999 * @@ -15,6 +15,8 @@ #include "StablePriv.h" /* initStablePtrTable */ #include "Schedule.h" /* initScheduler */ #include "Stats.h" /* initStats */ +#include "Signals.h" +#include "Itimer.h" #include "Weak.h" #include "Ticky.h" @@ -110,15 +112,18 @@ startupHaskell(int argc, char *argv[]) initProfiling(); #endif + /* start the ticker */ + install_vtalrm_handler(); + initialize_virtual_timer(TICK_MILLISECS); + /* Initialise the scheduler */ initScheduler(); /* Initialise the stats department */ initStats(); -#if 0 + /* Initialise the user signal handler set */ initUserSignals(); -#endif /* When the RTS and Prelude live in separate DLLs, we need to patch up the char- and int-like tables @@ -171,6 +176,9 @@ shutdownHaskell(void) /* clean up things from the storage manager's point of view */ exitStorage(); + /* stop the ticker */ + initialize_virtual_timer(0); + #if defined(PROFILING) || defined(DEBUG) endProfiling(); #endif diff --git a/ghc/rts/RtsUtils.c b/ghc/rts/RtsUtils.c index aab8a38008c14339144dcd9e7404c4b36fce35f4..d3d01cfb1ec5b7d742ed387705de7019258b6547 100644 --- a/ghc/rts/RtsUtils.c +++ b/ghc/rts/RtsUtils.c @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: RtsUtils.c,v 1.8 1999/03/17 13:19:23 simonm Exp $ + * $Id: RtsUtils.c,v 1.9 1999/08/25 16:11:51 simonmar Exp $ * * (c) The GHC Team, 1998-1999 * @@ -27,7 +27,7 @@ void barf(char *s, ...) { va_list ap; va_start(ap,s); - fflush(stdout); + /* don't fflush(stdout); WORKAROUND bug in Linux glibc */ if (prog_argv != NULL && prog_argv[0] != NULL) { fprintf(stderr, "%s: fatal error: ", prog_argv[0]); } else { @@ -43,7 +43,7 @@ void belch(char *s, ...) { va_list ap; va_start(ap,s); - fflush(stdout); + /* don't fflush(stdout); WORKAROUND bug in Linux glibc */ vfprintf(stderr, s, ap); fprintf(stderr, "\n"); } @@ -56,7 +56,7 @@ stgMallocBytes (int n, char *msg) char *space; if ((space = (char *) malloc((size_t) n)) == NULL) { - fflush(stdout); + /* don't fflush(stdout); WORKAROUND bug in Linux glibc */ MallocFailHook((W_) n, msg); /*msg*/ stg_exit(EXIT_FAILURE); } @@ -69,7 +69,7 @@ stgReallocBytes (void *p, int n, char *msg) char *space; if ((space = (char *) realloc(p, (size_t) n)) == NULL) { - fflush(stdout); + /* don't fflush(stdout); WORKAROUND bug in Linux glibc */ MallocFailHook((W_) n, msg); /*msg*/ exit(EXIT_FAILURE); } @@ -91,20 +91,11 @@ stgReallocWords (void *p, int n, char *msg) void _stgAssert (char *filename, nat linenum) { - fflush(stdout); + /* don't fflush(stdout); WORKAROUND bug in Linux glibc */ fprintf(stderr, "ASSERTION FAILED: file %s, line %u\n", filename, linenum); abort(); } -StgStablePtr errorHandler = -1; /* -1 indicates no handler installed */ - -void -raiseError( StgStablePtr handler STG_UNUSED ) -{ - shutdownHaskell(); - stg_exit(EXIT_FAILURE); -} - /* ----------------------------------------------------------------------------- Stack overflow @@ -114,25 +105,25 @@ raiseError( StgStablePtr handler STG_UNUSED ) void stackOverflow(void) { - StackOverflowHook(RtsFlags.GcFlags.maxStkSize * sizeof(W_)); + StackOverflowHook(RtsFlags.GcFlags.maxStkSize * sizeof(W_)); #if defined(TICKY_TICKY) - if (RtsFlags.TickyFlags.showTickyStats) PrintTickyInfo(); + if (RtsFlags.TickyFlags.showTickyStats) PrintTickyInfo(); #endif } void heapOverflow(void) { - fflush(stdout); - OutOfHeapHook(0/*unknown request size*/, - RtsFlags.GcFlags.maxHeapSize * BLOCK_SIZE); - + /* don't fflush(stdout); WORKAROUND bug in Linux glibc */ + OutOfHeapHook(0/*unknown request size*/, + RtsFlags.GcFlags.maxHeapSize * BLOCK_SIZE); + #if defined(TICKY_TICKY) - if (RtsFlags.TickyFlags.showTickyStats) PrintTickyInfo(); + if (RtsFlags.TickyFlags.showTickyStats) PrintTickyInfo(); #endif - stg_exit(EXIT_FAILURE); + stg_exit(EXIT_FAILURE); } /* ----------------------------------------------------------------------------- diff --git a/ghc/rts/Schedule.c b/ghc/rts/Schedule.c index 70df69675272937e55978bb45bbd2af920c2efbd..8450d972998813e2ee31c99abffb52b4af3ae40e 100644 --- a/ghc/rts/Schedule.c +++ b/ghc/rts/Schedule.c @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: Schedule.c,v 1.23 1999/08/25 10:23:53 simonmar Exp $ + * $Id: Schedule.c,v 1.24 1999/08/25 16:11:51 simonmar Exp $ * * (c) The GHC Team, 1998-1999 * @@ -127,7 +127,7 @@ initThread(StgTSO *tso, nat stack_size) SET_INFO(tso,&TSO_info); tso->whatNext = ThreadEnterGHC; tso->id = next_thread_id++; - tso->blocked_on = NULL; + tso->why_blocked = NotBlocked; tso->splim = (P_)&(tso->stack) + RESERVED_STACK_WORDS; tso->stack_size = stack_size; @@ -260,7 +260,7 @@ SchedulerStatus schedule(StgTSO *main, StgClosure **ret_val) /* If we have more threads on the run queue, set up a context * switch at some point in the future. */ - if (run_queue_hd != END_TSO_QUEUE) { + if (run_queue_hd != END_TSO_QUEUE || blocked_queue_hd != END_TSO_QUEUE) { context_switch = 1; } else { context_switch = 0; @@ -392,7 +392,10 @@ SchedulerStatus schedule(StgTSO *main, StgClosure **ret_val) break; case ThreadBlocked: - IF_DEBUG(scheduler,belch("Thread %ld stopped, blocking\n", t->id)); + IF_DEBUG(scheduler, + fprintf(stderr, "Thread %d stopped, ", t->id); + printThreadBlockage(t); + fprintf(stderr, "\n")); threadPaused(t); /* assume the thread has put itself on some blocked queue * somewhere. @@ -438,6 +441,14 @@ SchedulerStatus schedule(StgTSO *main, StgClosure **ret_val) } next_thread: + /* Checked whether any waiting threads need to be woken up. + * If the run queue is empty, we can wait indefinitely for + * something to happen. + */ + if (blocked_queue_hd != END_TSO_QUEUE) { + awaitEvent(run_queue_hd == END_TSO_QUEUE); + } + t = run_queue_hd; if (t != END_TSO_QUEUE) { run_queue_hd = t->link; @@ -448,12 +459,42 @@ SchedulerStatus schedule(StgTSO *main, StgClosure **ret_val) } } - if (blocked_queue_hd != END_TSO_QUEUE) { - return AllBlocked; - } else { - return Deadlock; + /* If we got to here, then we ran out of threads to run, but the + * main thread hasn't finished yet. It must be blocked on an MVar + * or a black hole somewhere, so we return deadlock. + */ + return Deadlock; +} + +/* ----------------------------------------------------------------------------- + Debugging: why is a thread blocked + -------------------------------------------------------------------------- */ + +#ifdef DEBUG +void printThreadBlockage(StgTSO *tso) +{ + switch (tso->why_blocked) { + case BlockedOnRead: + fprintf(stderr,"blocked on read from fd %d", tso->block_info.fd); + break; + case BlockedOnWrite: + fprintf(stderr,"blocked on write to fd %d", tso->block_info.fd); + break; + case BlockedOnDelay: + fprintf(stderr,"blocked on delay of %d ms", tso->block_info.delay); + break; + case BlockedOnMVar: + fprintf(stderr,"blocked on an MVar"); + break; + case BlockedOnBlackHole: + fprintf(stderr,"blocked on a black hole"); + break; + case NotBlocked: + fprintf(stderr,"not blocked"); + break; } } +#endif /* ----------------------------------------------------------------------------- Where are the roots that we know about? @@ -588,7 +629,7 @@ threadStackOverflow(StgTSO *tso) tso->whatNext = ThreadKilled; tso->sp = (P_)&(tso->stack[tso->stack_size]); tso->su = (StgUpdateFrame *)tso->sp; - tso->blocked_on = NULL; + tso->why_blocked = NotBlocked; dest->mut_link = NULL; IF_DEBUG(sanity,checkTSO(tso)); @@ -602,21 +643,26 @@ threadStackOverflow(StgTSO *tso) } /* ----------------------------------------------------------------------------- - Wake up a queue that was blocked on some resource (usually a - computation in progress). + Wake up a queue that was blocked on some resource. -------------------------------------------------------------------------- */ -void awaken_blocked_queue(StgTSO *q) +StgTSO *unblockOne(StgTSO *tso) { - StgTSO *tso; + StgTSO *next; + + ASSERT(get_itbl(tso)->type == TSO); + ASSERT(tso->why_blocked != NotBlocked); + tso->why_blocked = NotBlocked; + next = tso->link; + PUSH_ON_RUN_QUEUE(tso); + IF_DEBUG(scheduler,belch("Waking up thread %ld", tso->id)); + return next; +} - while (q != END_TSO_QUEUE) { - ASSERT(get_itbl(q)->type == TSO); - tso = q; - q = tso->link; - PUSH_ON_RUN_QUEUE(tso); - tso->blocked_on = NULL; - IF_DEBUG(scheduler,belch("Waking up thread %ld", tso->id)); +void awakenBlockedQueue(StgTSO *tso) +{ + while (tso != END_TSO_QUEUE) { + tso = unblockOne(tso); } } @@ -644,16 +690,16 @@ unblockThread(StgTSO *tso) { StgTSO *t, **last; - if (tso->blocked_on == NULL) { - return; /* not blocked */ - } + switch (tso->why_blocked) { - switch (get_itbl(tso->blocked_on)->type) { + case NotBlocked: + return; /* not blocked */ - case MVAR: + case BlockedOnMVar: + ASSERT(get_itbl(tso->block_info.closure)->type == MVAR); { StgTSO *last_tso = END_TSO_QUEUE; - StgMVar *mvar = (StgMVar *)(tso->blocked_on); + StgMVar *mvar = (StgMVar *)(tso->block_info.closure); last = &mvar->head; for (t = mvar->head; t != END_TSO_QUEUE; @@ -669,9 +715,10 @@ unblockThread(StgTSO *tso) barf("unblockThread (MVAR): TSO not found"); } - case BLACKHOLE_BQ: + case BlockedOnBlackHole: + ASSERT(get_itbl(tso->block_info.closure)->type == BLACKHOLE_BQ); { - StgBlockingQueue *bq = (StgBlockingQueue *)(tso->blocked_on); + StgBlockingQueue *bq = (StgBlockingQueue *)(tso->block_info.closure); last = &bq->blocking_queue; for (t = bq->blocking_queue; t != END_TSO_QUEUE; @@ -684,13 +731,20 @@ unblockThread(StgTSO *tso) barf("unblockThread (BLACKHOLE): TSO not found"); } + case BlockedOnRead: + case BlockedOnWrite: + case BlockedOnDelay: + /* ToDo */ + barf("unblockThread {read,write,delay}"); + default: barf("unblockThread"); } done: tso->link = END_TSO_QUEUE; - tso->blocked_on = NULL; + tso->why_blocked = NotBlocked; + tso->block_info.closure = NULL; PUSH_ON_RUN_QUEUE(tso); } diff --git a/ghc/rts/Schedule.h b/ghc/rts/Schedule.h index 6bdde63fa0efc2474603023ff38dbab79a990920..4a2cac0f44ecb5d3248382cf65d4b00d7594de2d 100644 --- a/ghc/rts/Schedule.h +++ b/ghc/rts/Schedule.h @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: Schedule.h,v 1.5 1999/03/16 13:20:17 simonm Exp $ + * $Id: Schedule.h,v 1.6 1999/08/25 16:11:51 simonmar Exp $ * * (c) The GHC Team 1998-1999 * @@ -18,16 +18,24 @@ void initScheduler(void); * Miscellany */ -void awaken_blocked_queue(StgTSO *tso); +void awakenBlockedQueue(StgTSO *tso); +StgTSO *unblockOne(StgTSO *tso); void initThread(StgTSO *tso, nat stack_size); void interruptStgRts(void); void raiseAsync(StgTSO *tso, StgClosure *exception); extern nat context_switch; +void awaitEvent(rtsBool wait); /* In Select.c */ +extern nat ticks_since_select; /* ditto */ + extern StgTSO *run_queue_hd, *run_queue_tl; extern StgTSO *blocked_queue_hd, *blocked_queue_tl; +#ifdef DEBUG +extern void printThreadBlockage(StgTSO *tso); +#endif + #ifdef COMPILING_RTS_MAIN extern DLLIMPORT StgTSO *MainTSO; /* temporary hack */ #else @@ -43,4 +51,12 @@ extern StgTSO *MainTSO; /* temporary hack */ } \ run_queue_tl = tso; +#define PUSH_ON_BLOCKED_QUEUE(tso) \ + if (blocked_queue_hd == END_TSO_QUEUE) { \ + blocked_queue_hd = tso; \ + } else { \ + blocked_queue_tl->link = tso; \ + } \ + blocked_queue_tl = tso; + #define END_CAF_LIST stgCast(StgCAF*,(void*)&END_TSO_QUEUE_closure) diff --git a/ghc/rts/StgMiscClosures.hc b/ghc/rts/StgMiscClosures.hc index 10d8cd0d6774eaf06456cdc278819360c66d5172..671177fef96e826a29ed56a363cb8294ada081ee 100644 --- a/ghc/rts/StgMiscClosures.hc +++ b/ghc/rts/StgMiscClosures.hc @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: StgMiscClosures.hc,v 1.26 1999/07/06 16:40:27 sewardj Exp $ + * $Id: StgMiscClosures.hc,v 1.27 1999/08/25 16:11:51 simonmar Exp $ * * (c) The GHC Team, 1998-1999 * @@ -22,7 +22,7 @@ /* ToDo: make the printing of panics more Win32-friendly, i.e., * pop up some lovely message boxes (as well). */ -#define DUMP_ERRMSG(msg) STGCALL1(fflush,stdout); STGCALL2(fprintf,stderr,msg) +#define DUMP_ERRMSG(msg) STGCALL2(fprintf,stderr,msg) /* ----------------------------------------------------------------------------- Entry code for an indirection. @@ -190,7 +190,8 @@ STGFUN(BLACKHOLE_entry) /* Put ourselves on the blocking queue for this black hole */ CurrentTSO->link = (StgTSO *)&END_TSO_QUEUE_closure; ((StgBlockingQueue *)R1.p)->blocking_queue = CurrentTSO; - CurrentTSO->blocked_on = R1.cl; + CurrentTSO->why_blocked = BlockedOnBlackHole; + CurrentTSO->block_info.closure = R1.cl; recordMutable((StgMutClosure *)R1.cl); /* stg_gen_block is too heavyweight, use a specialised one */ @@ -205,7 +206,8 @@ STGFUN(BLACKHOLE_BQ_entry) TICK_ENT_BH(); /* Put ourselves on the blocking queue for this black hole */ - CurrentTSO->blocked_on = R1.cl; + CurrentTSO->why_blocked = BlockedOnBlackHole; + CurrentTSO->block_info.closure = R1.cl; CurrentTSO->link = ((StgBlockingQueue *)R1.p)->blocking_queue; ((StgBlockingQueue *)R1.p)->blocking_queue = CurrentTSO; @@ -219,18 +221,7 @@ INFO_TABLE(CAF_BLACKHOLE_info, CAF_BLACKHOLE_entry,0,2,CAF_BLACKHOLE,,EF_,0,0); STGFUN(CAF_BLACKHOLE_entry) { FB_ - TICK_ENT_BH(); - - /* Change the BLACKHOLE into a BLACKHOLE_BQ */ - ((StgBlockingQueue *)R1.p)->header.info = &BLACKHOLE_BQ_info; - /* Put ourselves on the blocking queue for this black hole */ - CurrentTSO->link = (StgTSO *)&END_TSO_QUEUE_closure; - ((StgBlockingQueue *)R1.p)->blocking_queue = CurrentTSO; - CurrentTSO->blocked_on = R1.cl; - recordMutable((StgMutClosure *)R1.cl); - - /* stg_gen_block is too heavyweight, use a specialised one */ - BLOCK_NP(1); + JMP_(BLACKHOLE_entry); FE_ } @@ -239,10 +230,8 @@ INFO_TABLE(SE_BLACKHOLE_info, SE_BLACKHOLE_entry,0,2,SE_BLACKHOLE,,EF_,0,0); STGFUN(SE_BLACKHOLE_entry) { FB_ - STGCALL1(fflush,stdout); STGCALL3(fprintf,stderr,"SE_BLACKHOLE at %p entered!\n",R1.p); - STGCALL1(raiseError, errorHandler); - stg_exit(EXIT_FAILURE); /* not executed */ + STGCALL1(shutdownHaskellAndExit,EXIT_FAILURE); FE_ } @@ -250,10 +239,8 @@ INFO_TABLE(SE_CAF_BLACKHOLE_info, SE_CAF_BLACKHOLE_entry,0,2,SE_CAF_BLACKHOLE,,E STGFUN(SE_CAF_BLACKHOLE_entry) { FB_ - STGCALL1(fflush,stdout); STGCALL3(fprintf,stderr,"SE_CAF_BLACKHOLE at %p entered!\n",R1.p); - STGCALL1(raiseError, errorHandler); - stg_exit(EXIT_FAILURE); /* not executed */ + STGCALL1(shutdownHaskellAndExit,EXIT_FAILURE); FE_ } #endif @@ -280,8 +267,7 @@ STGFUN(type##_entry) \ { \ FB_ \ DUMP_ERRMSG(#type " object entered!\n"); \ - STGCALL1(raiseError, errorHandler); \ - stg_exit(EXIT_FAILURE); /* not executed */ \ + STGCALL1(shutdownHaskellAndExit, EXIT_FAILURE); \ FE_ \ } @@ -425,8 +411,7 @@ STGFUN(stg_error_entry) \ { \ FB_ \ DUMP_ERRMSG("fatal: stg_error_entry"); \ - STGCALL1(raiseError, errorHandler); \ - exit(EXIT_FAILURE); /* not executed */ \ + STGCALL1(shutdownHaskellAndExit, EXIT_FAILURE); \ FE_ \ }