/* -----------------------------------------------------------------------------
- * $Id: RtsStartup.c,v 1.11 1999/05/04 10:19:19 sof Exp $
+ * $Id: RtsStartup.c,v 1.31 2000/03/08 17:48:24 simonmar Exp $
*
* (c) The GHC Team, 1998-1999
*
#include "StablePriv.h" /* initStablePtrTable */
#include "Schedule.h" /* initScheduler */
#include "Stats.h" /* initStats */
+#include "Signals.h"
+#include "Itimer.h"
#include "Weak.h"
#include "Ticky.h"
+#include "StgRun.h"
+#include "StgStartup.h"
-#if defined(PROFILING)
+#if defined(PROFILING) || defined(DEBUG)
# include "ProfRts.h"
-#elif defined(DEBUG)
-# include "DebugProf.h"
+# include "ProfHeap.h"
#endif
-#ifdef PAR
+#if defined(GRAN)
+#include "GranSimRts.h"
+#include "ParallelRts.h"
+#endif
+
+#if defined(PAR)
#include "ParInit.h"
#include "Parallel.h"
#include "LLC.h"
*/
struct RTS_FLAGS RtsFlags;
-extern void startupHaskell(int argc, char *argv[])
+static int rts_has_started_up = 0;
+#if defined(PAR)
+static ullong startTime = 0;
+#endif
+
+static void initModules ( void );
+
+void
+startupHaskell(int argc, char *argv[])
{
- static int rts_has_started_up = 0;
+#ifdef ENABLE_WIN32_DLL_SUPPORT
int i;
+#endif
/* To avoid repeated initialisations of the RTS */
if (rts_has_started_up)
else
rts_has_started_up=1;
-#if defined(PAR)
- int nPEs = 0; /* Number of PEs */
-#endif
-
/* The very first thing we do is grab the start time...just in case we're
* collecting timing statistics.
*/
#ifdef PAR
/*
- *The parallel system needs to be initialised and synchronised before
- *the program is run.
+ * The parallel system needs to be initialised and synchronised before
+ * the program is run.
*/
+ fprintf(stderr, "startupHaskell: argv[0]=%s\n", argv[0]);
if (*argv[0] == '-') { /* Look to see whether we're the Main Thread */
IAmMainThread = rtsTrue;
argv++; argc--; /* Strip off flag argument */
-/* fprintf(stderr, "I am Main Thread\n"); */
+ // IF_PAR_DEBUG(verbose,
+ fprintf(stderr, "[%x] I am Main Thread\n", mytid);
}
/*
* Grab the number of PEs out of the argument vector, and
argv[1] = argv[0];
argv++; argc--;
initEachPEHook(); /* HWL: hook to be execed on each PE */
- SynchroniseSystem();
#endif
/* Set the RTS flags to default values. */
prog_argv = argv;
#if defined(PAR)
- /* Initialise the parallel system -- before initHeap! */
- initParallelSystem();
- /* And start GranSim profiling if required: omitted for now
- *if (Rtsflags.ParFlags.granSimStats)
- *init_gr_profiling(rts_argc, rts_argv, prog_argc, prog_argv);
- */
+ /* NB: this really must be done after processing the RTS flags */
+ fprintf(stderr, "Synchronising system (%d PEs)\n", nPEs);
+ SynchroniseSystem(); // calls initParallelSystem etc
#endif /* PAR */
+ /* initialise scheduler data structures (needs to be done before
+ * initStorage()).
+ */
+ initScheduler();
+
+#if defined(GRAN)
+ /* And start GranSim profiling if required: */
+ if (RtsFlags.GranFlags.GranSimStats.Full)
+ init_gr_simulation(rts_argc, rts_argv, prog_argc, prog_argv);
+#elif defined(PAR)
+ /* And start GUM profiling if required: */
+ if (RtsFlags.ParFlags.ParStats.Full)
+ init_gr_simulation(rts_argc, rts_argv, prog_argc, prog_argv);
+#endif /* PAR || GRAN */
+
/* initialize the storage manager */
initStorage();
initStablePtrTable();
#if defined(PROFILING) || defined(DEBUG)
- initProfiling();
+ initProfiling1();
#endif
- /* Initialise the scheduler */
- initScheduler();
+ /* run the per-module initialisation code */
+ initModules();
+
+#if defined(PROFILING) || defined(DEBUG)
+ initProfiling2();
+#endif
+
+ /* start the ticker */
+ install_vtalrm_handler();
+ initialize_virtual_timer(TICK_MILLISECS);
+
+ /* start our haskell execution tasks */
+#ifdef SMP
+ startTasks();
+#endif
/* Initialise the stats department */
initStats();
-#if 0
+#if !defined(mingw32_TARGET_OS) && !defined(PAR)
+ /* Initialise the user signal handler set */
initUserSignals();
+ /* Set up handler to run on SIGINT, etc. */
+ init_default_handlers();
#endif
/* When the RTS and Prelude live in separate DLLs,
filling in the tables with references to where the
static info tables have been loaded inside the running
process.
-
- Ditto for Bool closure tbl.
*/
#ifdef ENABLE_WIN32_DLL_SUPPORT
for(i=0;i<=255;i++)
end_init();
}
+/* -----------------------------------------------------------------------------
+ Per-module initialisation
+
+ This process traverses all the compiled modules in the program
+ starting with "Main", and performing per-module initialisation for
+ each one.
+
+ So far, two things happen at initialisation time:
+
+ - we register stable names for each foreign-exported function
+ in that module. This prevents foreign-exported entities, and
+ things they depend on, from being garbage collected.
+
+ - we supply a unique integer to each statically declared cost
+ centre and cost centre stack in the program.
+
+ The code generator inserts a small function "__init_<moddule>" in each
+ module and calls the registration functions in each of the modules
+ it imports. So, if we call "__init_Main", each reachable module in the
+ program will be registered.
+
+ The init* functions are compiled in the same way as STG code,
+ i.e. without normal C call/return conventions. Hence we must use
+ StgRun to call this stuff.
+ -------------------------------------------------------------------------- */
+
+/* The init functions use an explicit stack...
+ */
+#define INIT_STACK_SIZE (BLOCK_SIZE * 4)
+F_ *init_stack;
+
+static void
+initModules ( void )
+{
+ /* this storage will be reclaimed by the garbage collector,
+ * as a large block.
+ */
+ init_stack = (F_ *)allocate(INIT_STACK_SIZE / sizeof(W_));
+
+ StgRun((StgFunPtr)stg_init, NULL/* no reg table */);
+}
+
+/* -----------------------------------------------------------------------------
+ * Shutting down the RTS - two ways of doing this, one which
+ * calls exit(), one that doesn't.
+ *
+ * (shutdownHaskellAndExit() is called by System.exitWith).
+ * -----------------------------------------------------------------------------
+ */
+void
+shutdownHaskellAndExit(int n)
+{
+ OnExitHook();
+ shutdownHaskell();
+ stg_exit(n);
+}
+
void
shutdownHaskell(void)
{
+ if (!rts_has_started_up)
+ return;
+
+ /* start timing the shutdown */
+ stat_startExit();
+
+#if !defined(GRAN)
/* Finalize any remaining weak pointers */
finalizeWeakPointersNow();
+#endif
#if defined(GRAN)
- #error FixMe.
- if (!RTSflags.GranFlags.granSimStats_suppressed)
+ /* end_gr_simulation prints global stats if requested -- HWL */
+ if (!RtsFlags.GranFlags.GranSimStats.Suppressed)
end_gr_simulation();
#endif
- /* clean up things from the storage manager's point of view */
+ /* stop all running tasks */
+ exitScheduler();
+
+ /* stop the ticker */
+ initialize_virtual_timer(0);
+
+ /* reset the standard file descriptors to blocking mode */
+ resetNonBlockingFd(0);
+ resetNonBlockingFd(1);
+ resetNonBlockingFd(2);
+
+ /* stop timing the shutdown, we're about to print stats */
+ stat_endExit();
+
+ /* clean up things from the storage manager's point of view.
+ * also outputs the stats (+RTS -s) info.
+ */
exitStorage();
#if defined(PROFILING) || defined(DEBUG)
#endif
#if defined(PROFILING)
- report_ccs_profiling( );
+ report_ccs_profiling();
#endif
#if defined(TICKY_TICKY)
if (RtsFlags.TickyFlags.showTickyStats) PrintTickyInfo();
#endif
- /*
- This fflush is important, because: if "main" just returns,
- then we will end up in pre-supplied exit code that will close
- streams and flush buffers. In particular we have seen: it
- will close fd 0 (stdin), then flush fd 1 (stdout), then <who
- cares>...
-
- But if you're playing with sockets, that "close fd 0" might
- suggest to the daemon that all is over, only to be presented
- with more stuff on "fd 1" at the flush.
-
- The fflush avoids this sad possibility.
- */
- fflush(stdout);
-}
+ rts_has_started_up=0;
+
+#if defined(PAR)
+ shutdownParallelSystem(0);
+#endif
+}
/*
- * called from STG-land to exit the program cleanly
+ * called from STG-land to exit the program
*/
void
stg_exit(I_ n)
{
-#ifdef PAR
+#if 0 /* def PAR */
par_exit(n);
#else
- OnExitHook();
exit(n);
#endif
}
+