[project @ 2002-12-26 17:52:34 by wolfgang]
[ghc-hetmet.git] / ghc / rts / RtsStartup.c
index 07605fc..1f72bd1 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: RtsStartup.c,v 1.33 2000/03/14 09:55:05 simonmar Exp $
+ * $Id: RtsStartup.c,v 1.67 2002/12/11 15:36:48 simonmar Exp $
  *
  * (c) The GHC Team, 1998-2000
  *
@@ -7,6 +7,7 @@
  *
  * ---------------------------------------------------------------------------*/
 
+#include "PosixSource.h"
 #include "Rts.h"
 #include "RtsAPI.h"
 #include "RtsUtils.h"
 #include "Ticky.h"
 #include "StgRun.h"
 #include "StgStartup.h"
-#include "Prelude.h"           /* fixupPreludeRefs */
+#include "Prelude.h"           /* fixupRTStoPreludeRefs */
+#include "HsFFI.h"
+#include "Linker.h"
+#include "ThreadLabels.h"
+
+#if defined(RTS_GTK_FRONTPANEL)
+#include "FrontPanel.h"
+#endif
 
 #if defined(PROFILING) || defined(DEBUG)
-# include "ProfRts.h"
+# include "Profiling.h"
 # include "ProfHeap.h"
+# include "RetainerProfile.h"
 #endif
 
 #if defined(GRAN)
-#include "GranSimRts.h"
-#include "ParallelRts.h"
+# include "GranSimRts.h"
+#endif
+
+#if defined(GRAN) || defined(PAR)
+# include "ParallelRts.h"
 #endif
 
 #if defined(PAR)
-#include "ParInit.h"
-#include "Parallel.h"
-#include "LLC.h"
+# include "Parallel.h"
+# include "LLC.h"
 #endif
 
+#include <stdlib.h>
+
 /*
  * Flag Structure
  */
@@ -46,45 +59,65 @@ struct RTS_FLAGS RtsFlags;
 
 static int rts_has_started_up = 0;
 #if defined(PAR)
-static ullong startTime = 0;
+ullong startTime = 0;
 #endif
 
-static void initModules ( void );
+EXTFUN(__stginit_Prelude);
+static void initModules ( void (*)(void) );
 
 void
-startupHaskell(int argc, char *argv[])
+setProgArgv(int argc, char *argv[])
 {
-    /* To avoid repeated initialisations of the RTS */
-   if (rts_has_started_up)
-     return;
-   else
-     rts_has_started_up=1;
+   /* Usually this is done by startupHaskell, so we don't need to call this. 
+      However, sometimes Hugs wants to change the arguments which Haskell
+      getArgs >>= ... will be fed.  So you can do that by calling here
+      _after_ calling startupHaskell.
+   */
+   prog_argc = argc;
+   prog_argv = argv;
+}
+
+void
+getProgArgv(int *argc, char **argv[])
+{
+   *argc = prog_argc;
+   *argv = prog_argv;
+}
+
+
+void
+startupHaskell(int argc, char *argv[], void (*init_root)(void))
+{
+   /* To avoid repeated initialisations of the RTS */
+  if (rts_has_started_up) {
+    /* RTS is up and running, so only run the per-module initialisation code */
+    if (init_root) {
+      initModules(init_root);
+    }
+    return;
+  } else {
+    rts_has_started_up=1;
+  }
 
     /* The very first thing we do is grab the start time...just in case we're
      * collecting timing statistics.
      */
-    start_time();
+    stat_startInit();
 
 #ifdef PAR
-/*
- * 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 */
-       // IF_PAR_DEBUG(verbose,
-                    fprintf(stderr, "[%x] I am Main Thread\n", mytid);
+    /*
+     * The parallel system needs to be initialised and synchronised before
+     * the program is run.  
+     */ 
+    startupParallelSystem(argv);
+     
+    if (*argv[0] == '-') { /* Strip off mainPE flag argument */
+      argv++; 
+      argc--;                  
     }
-    /* 
-     * Grab the number of PEs out of the argument vector, and
-     * eliminate it from further argument processing.
-     */
-    nPEs = atoi(argv[1]);
-    argv[1] = argv[0];
+
+    argv[1] = argv[0];   /* ignore the nPEs argument */
     argv++; argc--;
-    initEachPEHook();                  /* HWL: hook to be execed on each PE */
 #endif
 
     /* Set the RTS flags to default values. */
@@ -100,8 +133,9 @@ startupHaskell(int argc, char *argv[])
 
 #if defined(PAR)
     /* NB: this really must be done after processing the RTS flags */
-    fprintf(stderr, "Synchronising system (%d PEs)\n", nPEs);
-    SynchroniseSystem();             // calls initParallelSystem etc
+    IF_PAR_DEBUG(verbose,
+                 fprintf(stderr, "==== Synchronising system (%d PEs)\n", nPEs));
+    synchroniseSystem();             // calls initParallelSystem etc
 #endif /* PAR */
 
     /* initialise scheduler data structures (needs to be done before
@@ -125,27 +159,22 @@ startupHaskell(int argc, char *argv[])
     /* initialise the stable pointer table */
     initStablePtrTable();
 
+    /* initialise thread label table (tso->char*) */
+    initThreadLabelTable();
+
 #if defined(PROFILING) || defined(DEBUG)
     initProfiling1();
 #endif
 
     /* run the per-module initialisation code */
-#if !defined(INTERPRETER)
-    initModules();
-#endif
+    initModules(init_root);
 
 #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
+    /* start the virtual timer 'subsystem'. */
+    startVirtTimer(TICK_MILLISECS);
 
     /* Initialise the stats department */
     initStats();
@@ -154,14 +183,17 @@ startupHaskell(int argc, char *argv[])
     /* Initialise the user signal handler set */
     initUserSignals();
     /* Set up handler to run on SIGINT, etc. */
-    init_default_handlers();
+    initDefaultHandlers();
 #endif
  
-    /* Initialise pointers from the RTS to the prelude */
-    fixupPreludeRefs();
+#ifdef RTS_GTK_FRONTPANEL
+    if (RtsFlags.GcFlags.frontpanel) {
+       initFrontPanel();
+    }
+#endif
 
     /* Record initialization times */
-    end_init();
+    stat_endInit();
 }
 
 /* -----------------------------------------------------------------------------
@@ -180,36 +212,47 @@ startupHaskell(int argc, char *argv[])
       - 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 code generator inserts a small function "__stginit_<module>" in each
+   module and calls the registration functions in each of the modules it
+   imports.  So, if we call "__stginit_PrelMain", each reachable module in the
+   program will be registered (because PrelMain.mainIO calls Main.main).
 
    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.
    -------------------------------------------------------------------------- */
 
-#ifndef INTERPRETER
-
 /* The init functions use an explicit stack... 
  */
-#define INIT_STACK_SIZE  (BLOCK_SIZE * 4)
-F_ *init_stack;
+#define INIT_STACK_BLOCKS  4
+F_ *init_stack = NULL;
 
 static void
-initModules ( void )
+initModules ( void (*init_root)(void) )
 {
-  /* this storage will be reclaimed by the garbage collector,
-   * as a large block.
-   */
-  init_stack = (F_ *)allocate(INIT_STACK_SIZE / sizeof(W_));
+    bdescr *bd;
+#ifdef SMP
+    Capability cap;
+#else
+#define cap MainCapability
+#endif
+    nat init_sp;
+
+    init_sp = 0;
+    bd = allocGroup(INIT_STACK_BLOCKS);
+    init_stack = (F_ *)bd->start;
+    init_stack[init_sp++] = (F_)stg_init_ret;
+//    init_stack[init_sp++] = (F_)__stginit_Prelude;
+    if (init_root != NULL) {
+       init_stack[init_sp++] = (F_)init_root;
+    }
+    
+    cap.r.rSp = (P_)(init_stack + init_sp);
+    StgRun((StgFunPtr)stg_init, &cap.r);
 
-  StgRun((StgFunPtr)stg_init, NULL/* no reg table */);
+    freeGroup(bd);
 }
 
-#endif /* !INTERPRETER */
-
 /* -----------------------------------------------------------------------------
  * Shutting down the RTS - two ways of doing this, one which
  * calls exit(), one that doesn't.
@@ -222,7 +265,12 @@ shutdownHaskellAndExit(int n)
 {
   OnExitHook();
   shutdownHaskell();
+#if defined(PAR)
+  /* really exit (stg_exit() would call shutdownParallelSystem() again) */
+  exit(n);
+#else
   stg_exit(n);
+#endif
 }
 
 void
@@ -230,10 +278,14 @@ shutdownHaskell(void)
 {
   if (!rts_has_started_up)
      return;
-
+  rts_has_started_up=0;
+  
   /* start timing the shutdown */
   stat_startExit();
 
+  /* stop all running tasks */
+  exitScheduler();
+
 #if !defined(GRAN)
   /* Finalize any remaining weak pointers */
   finalizeWeakPointersNow();
@@ -245,17 +297,22 @@ shutdownHaskell(void)
     end_gr_simulation();
 #endif
 
-  /* stop all running tasks */
-  exitScheduler();
-
   /* stop the ticker */
-  initialize_virtual_timer(0);
+  stopVirtTimer();
   
   /* reset the standard file descriptors to blocking mode */
   resetNonBlockingFd(0);
   resetNonBlockingFd(1);
   resetNonBlockingFd(2);
 
+#if defined(PAR)
+  /* controlled exit; good thread! */
+  shutdownParallelSystem(0);
+
+  /* global statistics in parallel system */
+  PAR_TICKY_PAR_END();
+#endif
+
   /* stop timing the shutdown, we're about to print stats */
   stat_endExit();
 
@@ -264,37 +321,52 @@ shutdownHaskell(void)
    */
   exitStorage();
 
-#if defined(PROFILING) || defined(DEBUG)
-  endProfiling();
+#ifdef RTS_GTK_FRONTPANEL
+    if (RtsFlags.GcFlags.frontpanel) {
+       stopFrontPanel();
+    }
 #endif
 
 #if defined(PROFILING) 
-  report_ccs_profiling();
+  reportCCSProfiling();
 #endif
 
-#if defined(TICKY_TICKY)
-  if (RtsFlags.TickyFlags.showTickyStats) PrintTickyInfo();
+#if defined(PROFILING) || defined(DEBUG)
+  endProfiling();
 #endif
 
-  rts_has_started_up=0;
-
-#if defined(PAR)
-  shutdownParallelSystem(0);
+#ifdef PROFILING
+  // Originally, this was in report_ccs_profiling().  Now, retainer
+  // profiling might tack some extra stuff on to the end of this file
+  // during endProfiling().
+  fclose(prof_file);
 #endif
 
+#if defined(TICKY_TICKY)
+  if (RtsFlags.TickyFlags.showTickyStats) PrintTickyInfo();
+#endif
 }
 
 /* 
  * called from STG-land to exit the program
  */
 
+#ifdef PAR
+static int exit_started=rtsFalse;
+#endif
+
 void  
-stg_exit(I_ n)
-{
-#if 0 /* def PAR */
-  par_exit(n);
-#else
-  exit(n);
+stg_exit(int n)
+{ 
+#ifdef PAR
+  /* HACK: avoid a loop when exiting due to a stupid error */
+  if (exit_started) 
+    return;
+  exit_started=rtsTrue;
+
+  IF_PAR_DEBUG(verbose, fprintf(stderr,"==-- stg_exit %d on [%x]...", n, mytid));
+  shutdownParallelSystem(n);
 #endif
+  exit(n);
 }