Skip to content
Snippets Groups Projects
Forked from Glasgow Haskell Compiler / GHC
44728 commits behind, 9 commits ahead of the upstream repository.
  • Simon Marlow's avatar
    a52ff761
    Change the way module initialisation is done (#3252, #4417) · a52ff761
    Simon Marlow authored
    Previously the code generator generated small code fragments labelled
    with __stginit_M for each module M, and these performed whatever
    initialisation was necessary for that module and recursively invoked
    the initialisation functions for imported modules.  This appraoch had
    drawbacks:
    
     - FFI users had to call hs_add_root() to ensure the correct
       initialisation routines were called.  This is a non-standard,
       and ugly, API.
    
     - unless we were using -split-objs, the __stginit dependencies would
       entail linking the whole transitive closure of modules imported,
       whether they were actually used or not.  In an extreme case (#4387,
       #4417), a module from GHC might be imported for use in Template
       Haskell or an annotation, and that would force the whole of GHC to
       be needlessly linked into the final executable.
    
    So now instead we do our initialisation with C functions marked with
    __attribute__((constructor)), which are automatically invoked at
    program startup time (or DSO load-time).  The C initialisers are
    emitted into the stub.c file.  This means that every time we compile
    with -prof or -hpc, we now get a stub file, but thanks to #3687 that
    is now invisible to the user.
    
    There are some refactorings in the RTS (particularly for HPC) to
    handle the fact that initialisers now get run earlier than they did
    before.
    
    The __stginit symbols are still generated, and the hs_add_root()
    function still exists (but does nothing), for backwards compatibility.
    a52ff761
    History
    Change the way module initialisation is done (#3252, #4417)
    Simon Marlow authored
    Previously the code generator generated small code fragments labelled
    with __stginit_M for each module M, and these performed whatever
    initialisation was necessary for that module and recursively invoked
    the initialisation functions for imported modules.  This appraoch had
    drawbacks:
    
     - FFI users had to call hs_add_root() to ensure the correct
       initialisation routines were called.  This is a non-standard,
       and ugly, API.
    
     - unless we were using -split-objs, the __stginit dependencies would
       entail linking the whole transitive closure of modules imported,
       whether they were actually used or not.  In an extreme case (#4387,
       #4417), a module from GHC might be imported for use in Template
       Haskell or an annotation, and that would force the whole of GHC to
       be needlessly linked into the final executable.
    
    So now instead we do our initialisation with C functions marked with
    __attribute__((constructor)), which are automatically invoked at
    program startup time (or DSO load-time).  The C initialisers are
    emitted into the stub.c file.  This means that every time we compile
    with -prof or -hpc, we now get a stub file, but thanks to #3687 that
    is now invisible to the user.
    
    There are some refactorings in the RTS (particularly for HPC) to
    handle the fact that initialisers now get run earlier than they did
    before.
    
    The __stginit symbols are still generated, and the hs_add_root()
    function still exists (but does nothing), for backwards compatibility.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
RtsMain.c 3.37 KiB
/* -----------------------------------------------------------------------------
 *
 * (c) The GHC Team 1998-2000
 *
 * Main function for a standalone Haskell program.
 *
 * ---------------------------------------------------------------------------*/

#define COMPILING_RTS_MAIN

#include "PosixSource.h"
#include "Rts.h"
#include "RtsAPI.h"

#include "RtsUtils.h"
#include "RtsMain.h"
#include "Prelude.h"
#include "Task.h"
#if defined(mingw32_HOST_OS)
#include "win32/seh_excn.h"
#endif

#ifdef DEBUG
# include "Printer.h"   /* for printing        */
#endif

#ifdef HAVE_WINDOWS_H
# include <windows.h>
#endif

/* Annoying global vars for passing parameters to real_main() below
 * This is to get around problem with Windows SEH, see hs_main(). */
static int progargc;
static char **progargv;
static StgClosure *progmain_closure;  /* This will be ZCMain_main_closure */

/* Hack: we assume that we're building a batch-mode system unless 
 * INTERPRETER is set
 */
#ifndef INTERPRETER /* Hack */
static void real_main(void)
{
    int exit_status;
    SchedulerStatus status;
    /* all GranSim/GUM init is done in startupHaskell; sets IAmMainThread! */

    startupHaskell(progargc,progargv,NULL);

    /* kick off the computation by creating the main thread with a pointer
       to mainIO_closure representing the computation of the overall program;
       then enter the scheduler with this thread and off we go;
      
       the same for GranSim (we have only one instance of this code)

       in a parallel setup, where we have many instances of this code
       running on different PEs, we should do this only for the main PE
       (IAmMainThread is set in startupHaskell) 
    */

    /* ToDo: want to start with a larger stack size */
    { 
	Capability *cap = rts_lock();
	cap = rts_evalLazyIO(cap,progmain_closure, NULL);
	status = rts_getSchedStatus(cap);
	taskTimeStamp(myTask());
	rts_unlock(cap);
    }

    /* check the status of the entire Haskell computation */
    switch (status) {
    case Killed:
      errorBelch("main thread exited (uncaught exception)");
      exit_status = EXIT_KILLED;
      break;
    case Interrupted:
      errorBelch("interrupted");
      exit_status = EXIT_INTERRUPTED;
      break;
    case HeapExhausted:
      exit_status = EXIT_HEAPOVERFLOW;
      break;
    case Success:
      exit_status = EXIT_SUCCESS;
      break;
    default:
      barf("main thread completed with invalid status");
    }
    shutdownHaskellAndExit(exit_status);
}

/* The rts entry point from a compiled program using a Haskell main function.
 * This gets called from a tiny main function which gets linked into each
 * compiled Haskell program that uses a Haskell main function.
 *
 * We expect the caller to pass ZCMain_main_closure for
 * main_closure. The reason we cannot refer to this symbol directly
 * is because we're inside the rts and we do not know for sure that
 * we'll be using a Haskell main function.
 */
int hs_main(int argc, char *argv[], StgClosure *main_closure)
{
    /* We do this dance with argc and argv as otherwise the SEH exception
       stuff (the BEGIN/END CATCH below) on Windows gets confused */
    progargc = argc;
    progargv = argv;
    progmain_closure = main_closure;

#if defined(mingw32_HOST_OS)
    BEGIN_CATCH
#endif
    real_main();
#if defined(mingw32_HOST_OS)
    END_CATCH
#endif
    return 0; /* not reached, but keeps gcc -Wall happy */
}
# endif /* BATCH_MODE */