[project @ 2003-02-22 04:51:50 by sof]
[ghc-hetmet.git] / ghc / rts / RtsStartup.c
1 /* -----------------------------------------------------------------------------
2  * $Id: RtsStartup.c,v 1.72 2003/02/22 04:51:53 sof Exp $
3  *
4  * (c) The GHC Team, 1998-2002
5  *
6  * Main function for a standalone Haskell program.
7  *
8  * ---------------------------------------------------------------------------*/
9
10 #include "PosixSource.h"
11 #include "Rts.h"
12 #include "RtsAPI.h"
13 #include "RtsUtils.h"
14 #include "RtsFlags.h"  
15 #include "Storage.h"    /* initStorage, exitStorage */
16 #include "StablePriv.h" /* initStablePtrTable */
17 #include "Schedule.h"   /* initScheduler */
18 #include "Stats.h"      /* initStats */
19 #include "Signals.h"
20 #include "Timer.h"      /* startTimer, stopTimer */
21 #include "Weak.h"
22 #include "Ticky.h"
23 #include "StgRun.h"
24 #include "StgStartup.h"
25 #include "Prelude.h"            /* fixupRTStoPreludeRefs */
26 #include "HsFFI.h"
27 #include "Linker.h"
28 #include "ThreadLabels.h"
29
30 #if defined(RTS_GTK_FRONTPANEL)
31 #include "FrontPanel.h"
32 #endif
33
34 #if defined(PROFILING) || defined(DEBUG)
35 # include "Profiling.h"
36 # include "ProfHeap.h"
37 # include "RetainerProfile.h"
38 #endif
39
40 #if defined(GRAN)
41 # include "GranSimRts.h"
42 #endif
43
44 #if defined(GRAN) || defined(PAR)
45 # include "ParallelRts.h"
46 #endif
47
48 #if defined(PAR)
49 # include "Parallel.h"
50 # include "LLC.h"
51 #endif
52
53 #if defined(mingw32_TARGET_OS)
54 #include "win32/AsyncIO.h"
55 #endif
56
57 #include <stdlib.h>
58
59 // Flag Structure
60 struct RTS_FLAGS RtsFlags;
61
62 // Count of how many outstanding hs_init()s there have been.
63 static int hs_init_count = 0;
64
65 /* -----------------------------------------------------------------------------
66    Starting up the RTS
67    -------------------------------------------------------------------------- */
68
69 void
70 hs_init(int *argc, char **argv[])
71 {
72     hs_init_count++;
73     if (hs_init_count > 1) {
74         // second and subsequent inits are ignored
75         return;
76     }
77
78     /* The very first thing we do is grab the start time...just in case we're
79      * collecting timing statistics.
80      */
81     stat_startInit();
82
83 #ifdef PAR
84     /*
85      * The parallel system needs to be initialised and synchronised before
86      * the program is run.  
87      */ 
88     startupParallelSystem(argv);
89      
90     if (*argv[0] == '-') { /* Strip off mainPE flag argument */
91       argv++; 
92       argc--;                   
93     }
94
95     argv[1] = argv[0];   /* ignore the nPEs argument */
96     argv++; argc--;
97 #endif
98
99     /* Set the RTS flags to default values. */
100     initRtsFlagsDefaults();
101
102     /* Call the user hook to reset defaults, if present */
103     defaultsHook();
104
105     /* Parse the flags, separating the RTS flags from the programs args */
106     if (argc != NULL && argv != NULL) {
107         setupRtsFlags(argc, *argv, &rts_argc, rts_argv);
108         prog_argc = *argc;
109         prog_argv = *argv;
110     }
111
112 #if defined(PAR)
113     /* NB: this really must be done after processing the RTS flags */
114     IF_PAR_DEBUG(verbose,
115                  fprintf(stderr, "==== Synchronising system (%d PEs)\n", nPEs));
116     synchroniseSystem();             // calls initParallelSystem etc
117 #endif  /* PAR */
118
119     /* initialise scheduler data structures (needs to be done before
120      * initStorage()).
121      */
122     initScheduler();
123
124 #if defined(GRAN)
125     /* And start GranSim profiling if required: */
126     if (RtsFlags.GranFlags.GranSimStats.Full)
127       init_gr_simulation(rts_argc, rts_argv, prog_argc, prog_argv);
128 #elif defined(PAR)
129     /* And start GUM profiling if required: */
130     if (RtsFlags.ParFlags.ParStats.Full)
131       init_gr_simulation(rts_argc, rts_argv, prog_argc, prog_argv);
132 #endif  /* PAR || GRAN */
133
134     /* initialize the storage manager */
135     initStorage();
136
137     /* initialise the stable pointer table */
138     initStablePtrTable();
139
140     /* initialise thread label table (tso->char*) */
141     initThreadLabelTable();
142
143 #if defined(PROFILING) || defined(DEBUG)
144     initProfiling1();
145 #endif
146
147     /* start the virtual timer 'subsystem'. */
148     startTimer(TICK_MILLISECS);
149
150     /* Initialise the stats department */
151     initStats();
152
153 #if !defined(mingw32_TARGET_OS) && !defined(PAR)
154     /* Initialise the user signal handler set */
155     initUserSignals();
156     /* Set up handler to run on SIGINT, etc. */
157     initDefaultHandlers();
158 #endif
159  
160 #if defined(mingw32_TARGET_OS)
161     startupAsyncIO();
162 #endif
163
164 #ifdef RTS_GTK_FRONTPANEL
165     if (RtsFlags.GcFlags.frontpanel) {
166         initFrontPanel();
167     }
168 #endif
169
170     /* Record initialization times */
171     stat_endInit();
172 }
173
174 // Compatibility interface
175 void
176 startupHaskell(int argc, char *argv[], void (*init_root)(void))
177 {
178     hs_init(&argc, &argv);
179     hs_add_root(init_root);
180 }
181
182
183 /* -----------------------------------------------------------------------------
184    Getting/Setting the program's arguments.
185
186    These are used by System.Environment.
187    -------------------------------------------------------------------------- */
188
189 void
190 getProgArgv(int *argc, char **argv[])
191 {
192     *argc = prog_argc;
193     *argv = prog_argv;
194 }
195
196 void
197 setProgArgv(int argc, char *argv[])
198 {
199    /* Usually this is done by startupHaskell, so we don't need to call this. 
200       However, sometimes Hugs wants to change the arguments which Haskell
201       getArgs >>= ... will be fed.  So you can do that by calling here
202       _after_ calling startupHaskell.
203    */
204    prog_argc = argc;
205    prog_argv = argv;
206 }
207
208 /* -----------------------------------------------------------------------------
209    Per-module initialisation
210
211    This process traverses all the compiled modules in the program
212    starting with "Main", and performing per-module initialisation for
213    each one.
214
215    So far, two things happen at initialisation time:
216
217       - we register stable names for each foreign-exported function
218         in that module.  This prevents foreign-exported entities, and
219         things they depend on, from being garbage collected.
220
221       - we supply a unique integer to each statically declared cost
222         centre and cost centre stack in the program.
223
224    The code generator inserts a small function "__stginit_<module>" in each
225    module and calls the registration functions in each of the modules it
226    imports.
227
228    The init* functions are compiled in the same way as STG code,
229    i.e. without normal C call/return conventions.  Hence we must use
230    StgRun to call this stuff.
231    -------------------------------------------------------------------------- */
232
233 /* The init functions use an explicit stack... 
234  */
235 #define INIT_STACK_BLOCKS  4
236 static F_ *init_stack = NULL;
237
238 void
239 hs_add_root(void (*init_root)(void))
240 {
241     bdescr *bd;
242 #ifdef SMP
243     Capability cap;
244 #else
245 #define cap MainCapability
246 #endif
247     nat init_sp;
248
249     if (hs_init_count <= 0) {
250         barf("hs_add_root() must be called after hs_init()");
251     }
252
253     init_sp = 0;
254     bd = allocGroup(INIT_STACK_BLOCKS);
255     init_stack = (F_ *)bd->start;
256     init_stack[init_sp++] = (F_)stg_init_ret;
257     if (init_root != NULL) {
258         init_stack[init_sp++] = (F_)init_root;
259     }
260     
261     cap.r.rSp = (P_)(init_stack + init_sp);
262     StgRun((StgFunPtr)stg_init, &cap.r);
263
264     freeGroup(bd);
265
266 #if defined(PROFILING) || defined(DEBUG)
267     // This must be done after module initialisation.
268     // ToDo: make this work in the presence of multiple hs_add_root()s.
269     initProfiling2();
270 #endif
271 }
272
273 /* -----------------------------------------------------------------------------
274    Shutting down the RTS
275    -------------------------------------------------------------------------- */
276
277 void
278 hs_exit(void)
279 {
280     if (hs_init_count <= 0) {
281         barf("too many hs_exit()s");
282     }
283     hs_init_count--;
284     if (hs_init_count > 0) {
285         // ignore until it's the last one
286         return;
287     }
288
289     /* start timing the shutdown */
290     stat_startExit();
291     
292     /* stop all running tasks */
293     exitScheduler();
294     
295 #if !defined(GRAN)
296     /* Finalize any remaining weak pointers */
297     finalizeWeakPointersNow();
298 #endif
299     
300 #if defined(GRAN)
301     /* end_gr_simulation prints global stats if requested -- HWL */
302     if (!RtsFlags.GranFlags.GranSimStats.Suppressed)
303         end_gr_simulation();
304 #endif
305     
306     /* stop the ticker */
307     stopTimer();
308     
309     /* reset the standard file descriptors to blocking mode */
310     resetNonBlockingFd(0);
311     resetNonBlockingFd(1);
312     resetNonBlockingFd(2);
313
314 #if defined(PAR)
315     /* controlled exit; good thread! */
316     shutdownParallelSystem(0);
317     
318     /* global statistics in parallel system */
319     PAR_TICKY_PAR_END();
320 #endif
321
322     /* stop timing the shutdown, we're about to print stats */
323     stat_endExit();
324     
325     /* clean up things from the storage manager's point of view.
326      * also outputs the stats (+RTS -s) info.
327      */
328     exitStorage();
329     
330 #ifdef RTS_GTK_FRONTPANEL
331     if (RtsFlags.GcFlags.frontpanel) {
332         stopFrontPanel();
333     }
334 #endif
335
336 #if defined(PROFILING) 
337     reportCCSProfiling();
338 #endif
339
340 #if defined(PROFILING) || defined(DEBUG)
341     endProfiling();
342 #endif
343
344 #ifdef PROFILING
345     // Originally, this was in report_ccs_profiling().  Now, retainer
346     // profiling might tack some extra stuff on to the end of this file
347     // during endProfiling().
348     fclose(prof_file);
349 #endif
350     
351 #if defined(TICKY_TICKY)
352     if (RtsFlags.TickyFlags.showTickyStats) PrintTickyInfo();
353 #endif
354
355 #if defined(mingw32_TARGET_OS)
356     shutdownAsyncIO();
357 #endif
358 }
359
360 // Compatibility interfaces
361 void
362 shutdownHaskell(void)
363 {
364     hs_exit();
365 }
366
367 void
368 shutdownHaskellAndExit(int n)
369 {
370     if (hs_init_count == 1) {
371         OnExitHook();
372         hs_exit();
373 #if defined(PAR)
374         /* really exit (stg_exit() would call shutdownParallelSystem() again) */
375         exit(n);
376 #else
377         stg_exit(n);
378 #endif
379     }
380 }
381
382 /* 
383  * called from STG-land to exit the program
384  */
385
386 #ifdef PAR
387 static int exit_started=rtsFalse;
388 #endif
389
390 void  
391 stg_exit(int n)
392
393 #ifdef PAR
394   /* HACK: avoid a loop when exiting due to a stupid error */
395   if (exit_started) 
396     return;
397   exit_started=rtsTrue;
398
399   IF_PAR_DEBUG(verbose, fprintf(stderr,"==-- stg_exit %d on [%x]...", n, mytid));
400   shutdownParallelSystem(n);
401 #endif
402   exit(n);
403 }
404