remove empty dir
[ghc-hetmet.git] / ghc / rts / RtsStartup.c
index 8e64ecb..147de7b 100644 (file)
@@ -1,7 +1,6 @@
 /* -----------------------------------------------------------------------------
- * $Id: RtsStartup.c,v 1.54 2001/10/31 10:34:29 simonmar Exp $
  *
- * (c) The GHC Team, 1998-2000
+ * (c) The GHC Team, 1998-2002
  *
  * Main function for a standalone Haskell program.
  *
 #include "RtsAPI.h"
 #include "RtsUtils.h"
 #include "RtsFlags.h"  
+#include "OSThreads.h"
 #include "Storage.h"    /* initStorage, exitStorage */
-#include "StablePriv.h" /* initStablePtrTable */
 #include "Schedule.h"   /* initScheduler */
 #include "Stats.h"      /* initStats */
+#include "STM.h"        /* initSTM */
 #include "Signals.h"
-#include "Itimer.h"
+#include "RtsSignals.h"
+#include "Timer.h"      /* startTimer, stopTimer */
 #include "Weak.h"
 #include "Ticky.h"
 #include "StgRun.h"
-#include "StgStartup.h"
 #include "Prelude.h"           /* fixupRTStoPreludeRefs */
 #include "HsFFI.h"
 #include "Linker.h"
+#include "ThreadLabels.h"
+#include "BlockAlloc.h"
 
 #if defined(RTS_GTK_FRONTPANEL)
 #include "FrontPanel.h"
@@ -33,6 +35,7 @@
 #if defined(PROFILING) || defined(DEBUG)
 # include "Profiling.h"
 # include "ProfHeap.h"
+# include "RetainerProfile.h"
 #endif
 
 #if defined(GRAN)
 # include "LLC.h"
 #endif
 
-/*
- * Flag Structure
- */
-struct RTS_FLAGS RtsFlags;
+#if defined(mingw32_HOST_OS)
+#include "win32/AsyncIO.h"
+#endif
 
-static int rts_has_started_up = 0;
-#if defined(PAR)
-ullong startTime = 0;
+#include <stdlib.h>
+
+#ifdef HAVE_TERMIOS_H
+#include <termios.h>
+#endif
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
 #endif
 
-EXTFUN(__stginit_Prelude);
-static void initModules ( void (*)(void) );
+// Count of how many outstanding hs_init()s there have been.
+static int hs_init_count = 0;
 
-void
-setProgArgv(int argc, char *argv[])
+// Here we save the terminal settings on the standard file
+// descriptors, if we need to change them (eg. to support NoBuffering
+// input).
+static void *saved_termios[3] = {NULL,NULL,NULL};
+
+void*
+__hscore_get_saved_termios(int fd)
 {
-   /* 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;
+  return (0 <= fd && fd < (int)(sizeof(saved_termios) / sizeof(*saved_termios))) ?
+    saved_termios[fd] : NULL;
 }
 
 void
-getProgArgv(int *argc, char **argv[])
+__hscore_set_saved_termios(int fd, void* ts)
 {
-   *argc = prog_argc;
-   *argv = prog_argv;
+  if (0 <= fd && fd < (int)(sizeof(saved_termios) / sizeof(*saved_termios))) {
+    saved_termios[fd] = ts;
+  }
 }
 
+/* -----------------------------------------------------------------------------
+   Initialise floating point unit on x86 (currently disabled. why?)
+   (see comment in ghc/compiler/nativeGen/MachInstrs.lhs).
+   -------------------------------------------------------------------------- */
+
+#define X86_INIT_FPU 0
+
+#if X86_INIT_FPU
+static void
+x86_init_fpu ( void )
+{
+  __volatile unsigned short int fpu_cw;
+
+  // Grab the control word
+  __asm __volatile ("fnstcw %0" : "=m" (fpu_cw));
+
+#if 0
+  printf("fpu_cw: %x\n", fpu_cw);
+#endif
+
+  // Set bits 8-9 to 10 (64-bit precision).
+  fpu_cw = (fpu_cw & 0xfcff) | 0x0200;
+
+  // Store the new control word back
+  __asm __volatile ("fldcw %0" : : "m" (fpu_cw));
+}
+#endif
+
+/* -----------------------------------------------------------------------------
+   Starting up the RTS
+   -------------------------------------------------------------------------- */
 
 void
-startupHaskell(int argc, char *argv[], void (*init_root)(void))
+hs_init(int *argc, char **argv[])
 {
-    /* To avoid repeated initialisations of the RTS */
-   if (rts_has_started_up)
-     return;
-   else
-     rts_has_started_up=1;
+    hs_init_count++;
+    if (hs_init_count > 1) {
+       // second and subsequent inits are ignored
+       return;
+    }
 
     /* The very first thing we do is grab the start time...just in case we're
      * collecting timing statistics.
@@ -118,17 +156,21 @@ startupHaskell(int argc, char *argv[], void (*init_root)(void))
     defaultsHook();
 
     /* Parse the flags, separating the RTS flags from the programs args */
-    setupRtsFlags(&argc, argv, &rts_argc, rts_argv);
-    prog_argc = argc;
-    prog_argv = argv;
+    if (argc != NULL && argv != NULL) {
+       setupRtsFlags(argc, *argv, &rts_argc, rts_argv);
+       setProgArgv(*argc,*argv);
+    }
 
 #if defined(PAR)
     /* NB: this really must be done after processing the RTS flags */
     IF_PAR_DEBUG(verbose,
-                 fprintf(stderr, "==== Synchronising system (%d PEs)\n", nPEs));
+                 debugBelch("==== Synchronising system (%d PEs)\n", nPEs));
     synchroniseSystem();             // calls initParallelSystem etc
 #endif /* PAR */
 
+    /* Perform initialisation of adjustor thunk layer. */
+    initAdjustor();
+
     /* initialise scheduler data structures (needs to be done before
      * initStorage()).
      */
@@ -150,46 +192,56 @@ startupHaskell(int argc, char *argv[], void (*init_root)(void))
     /* initialise the stable pointer table */
     initStablePtrTable();
 
-#if defined(PROFILING) || defined(DEBUG)
-    initProfiling1();
+#if defined(DEBUG)
+    /* initialise thread label table (tso->char*) */
+    initThreadLabelTable();
 #endif
 
-    /* run the per-module initialisation code */
-    initModules(init_root);
-
 #if defined(PROFILING) || defined(DEBUG)
-    initProfiling2();
+    initProfiling1();
 #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'. */
+    startTimer(TICK_MILLISECS);
 
     /* Initialise the stats department */
     initStats();
 
-#if !defined(mingw32_TARGET_OS) && !defined(PAR)
+#if defined(RTS_USER_SIGNALS)
     /* Initialise the user signal handler set */
     initUserSignals();
     /* Set up handler to run on SIGINT, etc. */
     initDefaultHandlers();
 #endif
  
+#if defined(mingw32_HOST_OS)
+    startupAsyncIO();
+#endif
+
 #ifdef RTS_GTK_FRONTPANEL
     if (RtsFlags.GcFlags.frontpanel) {
        initFrontPanel();
     }
 #endif
 
+#if X86_INIT_FPU
+    x86_init_fpu();
+#endif
+
     /* Record initialization times */
     stat_endInit();
 }
 
+// Compatibility interface
+void
+startupHaskell(int argc, char *argv[], void (*init_root)(void))
+{
+    hs_init(&argc, &argv);
+    if(init_root)
+        hs_add_root(init_root);
+}
+
+
 /* -----------------------------------------------------------------------------
    Per-module initialisation
 
@@ -208,8 +260,7 @@ startupHaskell(int argc, char *argv[], void (*init_root)(void))
 
    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).
+   imports.
 
    The init* functions are compiled in the same way as STG code,
    i.e. without normal C call/return conventions.  Hence we must use
@@ -218,117 +269,168 @@ startupHaskell(int argc, char *argv[], void (*init_root)(void))
 
 /* The init functions use an explicit stack... 
  */
-#define INIT_STACK_SIZE  (BLOCK_SIZE * 4)
-F_ *init_stack = NULL;
-nat init_sp = 0;
+#define INIT_STACK_BLOCKS  4
+static F_ *init_stack = NULL;
 
-static void
-initModules ( void (*init_root)(void) )
+void
+hs_add_root(void (*init_root)(void))
 {
-#ifdef SMP
-    Capability cap;
-#else
-#define cap MainRegTable
-#endif
+    bdescr *bd;
+    nat init_sp;
+    Capability *cap = &MainCapability;
 
-    init_sp = 0;
-    init_stack = (F_ *)allocate(INIT_STACK_SIZE / sizeof(W_));
-    init_stack[init_sp++] = (F_)stg_init_ret;
-    init_stack[init_sp++] = (F_)__stginit_Prelude;
+    if (hs_init_count <= 0) {
+       barf("hs_add_root() must be called after hs_init()");
+    }
+
+    /* The initialisation stack grows downward, with sp pointing 
+       to the last occupied word */
+    init_sp = INIT_STACK_BLOCKS*BLOCK_SIZE_W;
+    bd = allocGroup_lock(INIT_STACK_BLOCKS);
+    init_stack = (F_ *)bd->start;
+    init_stack[--init_sp] = (F_)stg_init_finish;
     if (init_root != NULL) {
-       init_stack[init_sp++] = (F_)init_root;
+       init_stack[--init_sp] = (F_)init_root;
     }
     
-    cap.rSp = (P_)(init_stack + init_sp);
-    StgRun((StgFunPtr)stg_init, &cap);
-}
+    cap->r.rSp = (P_)(init_stack + init_sp);
+    StgRun((StgFunPtr)stg_init, &cap->r);
 
-/* -----------------------------------------------------------------------------
- * 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();
-#if defined(PAR)
-  /* really exit (stg_exit() would call shutdownParallelSystem() again) */
-  exit(n);
-#else
-  stg_exit(n);
+    freeGroup_lock(bd);
+
+#if defined(PROFILING) || defined(DEBUG)
+    // This must be done after module initialisation.
+    // ToDo: make this work in the presence of multiple hs_add_root()s.
+    initProfiling2();
 #endif
 }
 
+/* -----------------------------------------------------------------------------
+   Shutting down the RTS
+   -------------------------------------------------------------------------- */
+
 void
-shutdownHaskell(void)
+hs_exit(void)
 {
-  if (!rts_has_started_up)
-     return;
-
-  /* start timing the shutdown */
-  stat_startExit();
-
-#if !defined(GRAN)
-  /* Finalize any remaining weak pointers */
-  finalizeWeakPointersNow();
-#endif
+    if (hs_init_count <= 0) {
+       errorBelch("warning: too many hs_exit()s");
+       return;
+    }
+    hs_init_count--;
+    if (hs_init_count > 0) {
+       // ignore until it's the last one
+       return;
+    }
 
+    /* start timing the shutdown */
+    stat_startExit();
+    
+    /* stop all running tasks */
+    exitScheduler();
+    
 #if defined(GRAN)
-  /* end_gr_simulation prints global stats if requested -- HWL */
-  if (!RtsFlags.GranFlags.GranSimStats.Suppressed)
-    end_gr_simulation();
+    /* end_gr_simulation prints global stats if requested -- HWL */
+    if (!RtsFlags.GranFlags.GranSimStats.Suppressed)
+       end_gr_simulation();
+#endif
+    
+    /* stop the ticker */
+    stopTimer();
+    
+    /* reset the standard file descriptors to blocking mode */
+    resetNonBlockingFd(0);
+    resetNonBlockingFd(1);
+    resetNonBlockingFd(2);
+
+#if HAVE_TERMIOS_H
+    // Reset the terminal settings on the standard file descriptors,
+    // if we changed them.  See System.Posix.Internals.tcSetAttr for
+    // more details, including the reason we termporarily disable
+    // SIGTTOU here.
+    { 
+       int fd;
+       sigset_t sigset, old_sigset;
+       sigemptyset(&sigset);
+       sigaddset(&sigset, SIGTTOU);
+       sigprocmask(SIG_BLOCK, &sigset, &old_sigset);
+       for (fd = 0; fd <= 2; fd++) {
+           struct termios* ts = (struct termios*)__hscore_get_saved_termios(fd);
+           if (ts != NULL) {
+               tcsetattr(fd,TCSANOW,ts);
+           }
+       }
+       sigprocmask(SIG_SETMASK, &old_sigset, NULL);
+    }
 #endif
-
-  /* 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);
 
 #if defined(PAR)
-  /* controlled exit; good thread! */
-  shutdownParallelSystem(0);
-
-  /* global statistics in parallel system */
-  PAR_TICKY_PAR_END();
+    /* 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();
-
-  /* clean up things from the storage manager's point of view.
-   * also outputs the stats (+RTS -s) info.
-   */
-  exitStorage();
-
+    /* 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();
+    
 #ifdef RTS_GTK_FRONTPANEL
     if (RtsFlags.GcFlags.frontpanel) {
        stopFrontPanel();
     }
 #endif
 
+#if defined(PROFILING) 
+    reportCCSProfiling();
+#endif
+
 #if defined(PROFILING) || defined(DEBUG)
-  endProfiling();
+    endProfiling();
 #endif
 
-#if defined(PROFILING) 
-  report_ccs_profiling();
+#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();
+    if (RtsFlags.TickyFlags.showTickyStats) PrintTickyInfo();
+#endif
+
+#if defined(mingw32_HOST_OS)
+    shutdownAsyncIO();
 #endif
 
-  rts_has_started_up=0;
+    // Finally, free all our storage.
+    freeStorage();
+}
+
+// Compatibility interfaces
+void
+shutdownHaskell(void)
+{
+    hs_exit();
+}
+
+void
+shutdownHaskellAndExit(int n)
+{
+    if (hs_init_count == 1) {
+       OnExitHook();
+       hs_exit();
+#if defined(PAR)
+       /* really exit (stg_exit() would call shutdownParallelSystem() again) */
+       exit(n);
+#else
+       stg_exit(n);
+#endif
+    }
 }
 
 /* 
@@ -340,7 +442,7 @@ static int exit_started=rtsFalse;
 #endif
 
 void  
-stg_exit(I_ n)
+stg_exit(int n)
 { 
 #ifdef PAR
   /* HACK: avoid a loop when exiting due to a stupid error */
@@ -348,9 +450,8 @@ stg_exit(I_ n)
     return;
   exit_started=rtsTrue;
 
-  IF_PAR_DEBUG(verbose, fprintf(stderr,"==-- stg_exit %d on [%x]...", n, mytid));
+  IF_PAR_DEBUG(verbose, debugBelch("==-- stg_exit %d on [%x]...", n, mytid));
   shutdownParallelSystem(n);
 #endif
   exit(n);
 }
-