Turn the "too many hs_exit()s" fatal error into a warning
[ghc-hetmet.git] / ghc / rts / RtsStartup.c
index def63a5..147de7b 100644 (file)
@@ -1,5 +1,4 @@
 /* -----------------------------------------------------------------------------
- * $Id: RtsStartup.c,v 1.68 2003/01/28 16:30:06 simonmar Exp $
  *
  * (c) The GHC Team, 1998-2002
  *
 #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"
 # include "LLC.h"
 #endif
 
+#if defined(mingw32_HOST_OS)
+#include "win32/AsyncIO.h"
+#endif
+
 #include <stdlib.h>
 
-// Flag Structure
-struct RTS_FLAGS RtsFlags;
+#ifdef HAVE_TERMIOS_H
+#include <termios.h>
+#endif
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
 
 // Count of how many outstanding hs_init()s there have been.
 static int hs_init_count = 0;
 
+// 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)
+{
+  return (0 <= fd && fd < (int)(sizeof(saved_termios) / sizeof(*saved_termios))) ?
+    saved_termios[fd] : NULL;
+}
+
+void
+__hscore_set_saved_termios(int fd, void* ts)
+{
+  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
    -------------------------------------------------------------------------- */
@@ -101,17 +158,19 @@ hs_init(int *argc, char **argv[])
     /* Parse the flags, separating the RTS flags from the programs args */
     if (argc != NULL && argv != NULL) {
        setupRtsFlags(argc, *argv, &rts_argc, rts_argv);
-       prog_argc = *argc;
-       prog_argv = *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()).
      */
@@ -133,36 +192,42 @@ hs_init(int *argc, char **argv[])
     /* initialise the stable pointer table */
     initStablePtrTable();
 
+#if defined(DEBUG)
     /* initialise thread label table (tso->char*) */
     initThreadLabelTable();
-
-#if defined(PROFILING) || defined(DEBUG)
-    initProfiling1();
 #endif
 
 #if defined(PROFILING) || defined(DEBUG)
-    initProfiling2();
+    initProfiling1();
 #endif
 
     /* start the virtual timer 'subsystem'. */
-    startVirtTimer(TICK_MILLISECS);
+    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();
 }
@@ -172,24 +237,12 @@ void
 startupHaskell(int argc, char *argv[], void (*init_root)(void))
 {
     hs_init(&argc, &argv);
-    hs_add_root(init_root);
+    if(init_root)
+        hs_add_root(init_root);
 }
 
 
 /* -----------------------------------------------------------------------------
-   Getting the program's arguments.
-
-   This is used by System.Environment.getArgs.
-   -------------------------------------------------------------------------- */
-
-void
-getProgArgv(int *argc, char **argv[])
-{
-    *argc = prog_argc;
-    *argv = prog_argv;
-}
-
-/* -----------------------------------------------------------------------------
    Per-module initialisation
 
    This process traverses all the compiled modules in the program
@@ -223,29 +276,33 @@ void
 hs_add_root(void (*init_root)(void))
 {
     bdescr *bd;
-#ifdef SMP
-    Capability cap;
-#else
-#define cap MainCapability
-#endif
     nat init_sp;
+    Capability *cap = &MainCapability;
 
     if (hs_init_count <= 0) {
        barf("hs_add_root() must be called after hs_init()");
     }
 
-    init_sp = 0;
-    bd = allocGroup(INIT_STACK_BLOCKS);
+    /* 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_ret;
+    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.r.rSp = (P_)(init_stack + init_sp);
-    StgRun((StgFunPtr)stg_init, &cap.r);
+    cap->r.rSp = (P_)(init_stack + init_sp);
+    StgRun((StgFunPtr)stg_init, &cap->r);
 
-    freeGroup(bd);
+    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
 }
 
 /* -----------------------------------------------------------------------------
@@ -256,7 +313,8 @@ void
 hs_exit(void)
 {
     if (hs_init_count <= 0) {
-       barf("too many hs_exit()s");
+       errorBelch("warning: too many hs_exit()s");
+       return;
     }
     hs_init_count--;
     if (hs_init_count > 0) {
@@ -270,11 +328,6 @@ hs_exit(void)
     /* stop all running tasks */
     exitScheduler();
     
-#if !defined(GRAN)
-    /* Finalize any remaining weak pointers */
-    finalizeWeakPointersNow();
-#endif
-    
 #if defined(GRAN)
     /* end_gr_simulation prints global stats if requested -- HWL */
     if (!RtsFlags.GranFlags.GranSimStats.Suppressed)
@@ -282,13 +335,34 @@ hs_exit(void)
 #endif
     
     /* stop the ticker */
-    stopVirtTimer();
+    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
+
 #if defined(PAR)
     /* controlled exit; good thread! */
     shutdownParallelSystem(0);
@@ -300,9 +374,8 @@ hs_exit(void)
     /* 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.
-     */
+    // clean up things from the storage manager's point of view.
+    // also outputs the stats (+RTS -s) info.
     exitStorage();
     
 #ifdef RTS_GTK_FRONTPANEL
@@ -325,10 +398,17 @@ hs_exit(void)
     // during endProfiling().
     fclose(prof_file);
 #endif
-    
+
 #if defined(TICKY_TICKY)
     if (RtsFlags.TickyFlags.showTickyStats) PrintTickyInfo();
 #endif
+
+#if defined(mingw32_HOST_OS)
+    shutdownAsyncIO();
+#endif
+
+    // Finally, free all our storage.
+    freeStorage();
 }
 
 // Compatibility interfaces
@@ -370,9 +450,8 @@ stg_exit(int 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);
 }
-