[project @ 2000-04-20 13:20:31 by simonmar]
[ghc-hetmet.git] / ghc / rts / RtsStartup.c
1 /* -----------------------------------------------------------------------------
2  * $Id: RtsStartup.c,v 1.42 2000/04/20 13:20:31 simonmar Exp $
3  *
4  * (c) The GHC Team, 1998-2000
5  *
6  * Main function for a standalone Haskell program.
7  *
8  * ---------------------------------------------------------------------------*/
9
10 #include "Rts.h"
11 #include "RtsAPI.h"
12 #include "RtsUtils.h"
13 #include "RtsFlags.h"  
14 #include "Storage.h"    /* initStorage, exitStorage */
15 #include "StablePriv.h" /* initStablePtrTable */
16 #include "Schedule.h"   /* initScheduler */
17 #include "Stats.h"      /* initStats */
18 #include "Signals.h"
19 #include "Itimer.h"
20 #include "Weak.h"
21 #include "Ticky.h"
22 #include "StgRun.h"
23 #include "StgStartup.h"
24 #include "Prelude.h"            /* fixupRTStoPreludeRefs */
25
26 #if defined(PROFILING) || defined(DEBUG)
27 # include "Profiling.h"
28 # include "ProfHeap.h"
29 #endif
30
31 #if defined(GRAN)
32 #include "GranSimRts.h"
33 #include "ParallelRts.h"
34 #endif
35
36 #if defined(PAR)
37 #include "ParInit.h"
38 #include "Parallel.h"
39 #include "LLC.h"
40 #endif
41
42 /*
43  * Flag Structure
44  */
45 struct RTS_FLAGS RtsFlags;
46
47 static int rts_has_started_up = 0;
48 #if defined(PAR)
49 static ullong startTime = 0;
50 #endif
51
52 EXTFUN(__init_Prelude);
53 static void initModules ( void * );
54
55 void
56 setProgArgv(int argc, char *argv[])
57 {
58    /* Usually this is done by startupHaskell, so we don't need to call this. 
59       However, sometimes Hugs wants to change the arguments which Haskell
60       getArgs >>= ... will be fed.  So you can do that by calling here
61       _after_ calling startupHaskell.
62    */
63    prog_argc = argc;
64    prog_argv = argv;
65 }
66
67 void
68 getProgArgv(int *argc, char **argv[])
69 {
70    *argc = prog_argc;
71    *argv = prog_argv;
72 }
73
74
75 void
76 startupHaskell(int argc, char *argv[], void *init_root)
77 {
78     /* To avoid repeated initialisations of the RTS */
79    if (rts_has_started_up)
80      return;
81    else
82      rts_has_started_up=1;
83
84     /* The very first thing we do is grab the start time...just in case we're
85      * collecting timing statistics.
86      */
87     start_time();
88
89 #ifdef PAR
90 /*
91  * The parallel system needs to be initialised and synchronised before
92  * the program is run.  
93  */
94     fprintf(stderr, "startupHaskell: argv[0]=%s\n", argv[0]);
95     if (*argv[0] == '-') {     /* Look to see whether we're the Main Thread */
96         IAmMainThread = rtsTrue;
97         argv++; argc--;                 /* Strip off flag argument */
98         // IF_PAR_DEBUG(verbose,
99                      fprintf(stderr, "[%x] I am Main Thread\n", mytid);
100     }
101     /* 
102      * Grab the number of PEs out of the argument vector, and
103      * eliminate it from further argument processing.
104      */
105     nPEs = atoi(argv[1]);
106     argv[1] = argv[0];
107     argv++; argc--;
108     initEachPEHook();                  /* HWL: hook to be execed on each PE */
109 #endif
110
111     /* Set the RTS flags to default values. */
112     initRtsFlagsDefaults();
113
114     /* Call the user hook to reset defaults, if present */
115     defaultsHook();
116
117     /* Parse the flags, separating the RTS flags from the programs args */
118     setupRtsFlags(&argc, argv, &rts_argc, rts_argv);
119     prog_argc = argc;
120     prog_argv = argv;
121
122 #if defined(PAR)
123     /* NB: this really must be done after processing the RTS flags */
124     fprintf(stderr, "Synchronising system (%d PEs)\n", nPEs);
125     SynchroniseSystem();             // calls initParallelSystem etc
126 #endif  /* PAR */
127
128     /* initialise scheduler data structures (needs to be done before
129      * initStorage()).
130      */
131     initScheduler();
132
133 #if defined(GRAN)
134     /* And start GranSim profiling if required: */
135     if (RtsFlags.GranFlags.GranSimStats.Full)
136       init_gr_simulation(rts_argc, rts_argv, prog_argc, prog_argv);
137 #elif defined(PAR)
138     /* And start GUM profiling if required: */
139     if (RtsFlags.ParFlags.ParStats.Full)
140       init_gr_simulation(rts_argc, rts_argv, prog_argc, prog_argv);
141 #endif  /* PAR || GRAN */
142
143     /* initialize the storage manager */
144     initStorage();
145
146     /* initialise the stable pointer table */
147     initStablePtrTable();
148
149 #if defined(PROFILING) || defined(DEBUG)
150     initProfiling1();
151 #endif
152
153     /* run the per-module initialisation code */
154 #if !defined(INTERPRETER)
155     initModules(init_root);
156 #endif
157
158 #if defined(PROFILING) || defined(DEBUG)
159     initProfiling2();
160 #endif
161
162     /* start the ticker */
163     install_vtalrm_handler();
164     initialize_virtual_timer(TICK_MILLISECS);
165
166     /* start our haskell execution tasks */
167 #ifdef SMP
168     startTasks();
169 #endif
170
171     /* Initialise the stats department */
172     initStats();
173
174 #if !defined(mingw32_TARGET_OS) && !defined(PAR)
175     /* Initialise the user signal handler set */
176     initUserSignals();
177     /* Set up handler to run on SIGINT, etc. */
178     init_default_handlers();
179 #endif
180  
181 #if !defined(INTERPRETER)
182     /* Initialise pointers from the RTS to the prelude.  
183        Only for compiled code -- the interpreter
184        will call this itself later, so don't do so now.
185     */
186     fixupRTStoPreludeRefs(NULL);
187 #endif
188
189     /* Record initialization times */
190     end_init();
191 }
192
193 /* -----------------------------------------------------------------------------
194    Per-module initialisation
195
196    This process traverses all the compiled modules in the program
197    starting with "Main", and performing per-module initialisation for
198    each one.
199
200    So far, two things happen at initialisation time:
201
202       - we register stable names for each foreign-exported function
203         in that module.  This prevents foreign-exported entities, and
204         things they depend on, from being garbage collected.
205
206       - we supply a unique integer to each statically declared cost
207         centre and cost centre stack in the program.
208
209    The code generator inserts a small function "__init_<module>" in each
210    module and calls the registration functions in each of the modules
211    it imports.  So, if we call "__init_PrelMain", each reachable module in the
212    program will be registered (because PrelMain.mainIO calls Main.main).
213
214    The init* functions are compiled in the same way as STG code,
215    i.e. without normal C call/return conventions.  Hence we must use
216    StgRun to call this stuff.
217    -------------------------------------------------------------------------- */
218
219 /* The init functions use an explicit stack... 
220  */
221 #define INIT_STACK_SIZE  (BLOCK_SIZE * 4)
222 F_ *init_stack = NULL;
223 nat init_sp = 0;
224
225 #ifndef INTERPRETER
226 static void
227 initModules ( void *init_root )
228 {
229 #ifdef SMP
230     Capability cap;
231 #else
232 #define cap MainRegTable
233 #endif
234
235     init_sp = 0;
236     init_stack = (F_ *)allocate(INIT_STACK_SIZE / sizeof(W_));
237     init_stack[init_sp++] = (F_)stg_init_ret;
238     init_stack[init_sp++] = (F_)__init_Prelude;
239     if (init_root != NULL) {
240         init_stack[init_sp++] = (F_)init_root;
241     }
242     
243     cap.rSp = (P_)(init_stack + init_sp);
244     StgRun((StgFunPtr)stg_init, &cap);
245 }
246 #endif /* !INTERPRETER */
247
248 /* -----------------------------------------------------------------------------
249  * Shutting down the RTS - two ways of doing this, one which
250  * calls exit(), one that doesn't.
251  *
252  * (shutdownHaskellAndExit() is called by System.exitWith).
253  * -----------------------------------------------------------------------------
254  */
255 void
256 shutdownHaskellAndExit(int n)
257 {
258   OnExitHook();
259   shutdownHaskell();
260   stg_exit(n);
261 }
262
263 void
264 shutdownHaskell(void)
265 {
266   if (!rts_has_started_up)
267      return;
268
269   /* start timing the shutdown */
270   stat_startExit();
271
272 #if !defined(GRAN)
273   /* Finalize any remaining weak pointers */
274   finalizeWeakPointersNow();
275 #endif
276
277 #if defined(GRAN)
278   /* end_gr_simulation prints global stats if requested -- HWL */
279   if (!RtsFlags.GranFlags.GranSimStats.Suppressed)
280     end_gr_simulation();
281 #endif
282
283   /* stop all running tasks */
284   exitScheduler();
285
286   /* stop the ticker */
287   initialize_virtual_timer(0);
288   
289   /* reset the standard file descriptors to blocking mode */
290   resetNonBlockingFd(0);
291   resetNonBlockingFd(1);
292   resetNonBlockingFd(2);
293
294 #if defined(PAR)
295   shutdownParallelSystem(0);
296 #endif
297
298   /* stop timing the shutdown, we're about to print stats */
299   stat_endExit();
300
301   /* clean up things from the storage manager's point of view.
302    * also outputs the stats (+RTS -s) info.
303    */
304   exitStorage();
305
306 #if defined(PROFILING) || defined(DEBUG)
307   endProfiling();
308 #endif
309
310 #if defined(PROFILING) 
311   report_ccs_profiling();
312 #endif
313
314 #if defined(TICKY_TICKY)
315   if (RtsFlags.TickyFlags.showTickyStats) PrintTickyInfo();
316 #endif
317
318   rts_has_started_up=0;
319
320 }
321
322 /* 
323  * called from STG-land to exit the program
324  */
325
326 void  
327 stg_exit(I_ n)
328 {
329 #if 0 /* def PAR */
330   par_exit(n);
331 #else
332   exit(n);
333 #endif
334 }
335