[project @ 2002-06-26 08:18:38 by stolz]
[ghc-hetmet.git] / ghc / rts / RtsStartup.c
1 /* -----------------------------------------------------------------------------
2  * $Id: RtsStartup.c,v 1.64 2002/06/26 08:18:41 stolz Exp $
3  *
4  * (c) The GHC Team, 1998-2000
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 "Itimer.h"
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 /*
54  * Flag Structure
55  */
56 struct RTS_FLAGS RtsFlags;
57
58 static int rts_has_started_up = 0;
59 #if defined(PAR)
60 ullong startTime = 0;
61 #endif
62
63 EXTFUN(__stginit_Prelude);
64 static void initModules ( void (*)(void) );
65
66 void
67 setProgArgv(int argc, char *argv[])
68 {
69    /* Usually this is done by startupHaskell, so we don't need to call this. 
70       However, sometimes Hugs wants to change the arguments which Haskell
71       getArgs >>= ... will be fed.  So you can do that by calling here
72       _after_ calling startupHaskell.
73    */
74    prog_argc = argc;
75    prog_argv = argv;
76 }
77
78 void
79 getProgArgv(int *argc, char **argv[])
80 {
81    *argc = prog_argc;
82    *argv = prog_argv;
83 }
84
85
86 void
87 startupHaskell(int argc, char *argv[], void (*init_root)(void))
88 {
89    /* To avoid repeated initialisations of the RTS */
90   if (rts_has_started_up) {
91     /* RTS is up and running, so only run the per-module initialisation code */
92     if (init_root) {
93       initModules(init_root);
94     }
95     return;
96   } else {
97     rts_has_started_up=1;
98   }
99
100     /* The very first thing we do is grab the start time...just in case we're
101      * collecting timing statistics.
102      */
103     stat_startInit();
104
105 #ifdef PAR
106     /*
107      * The parallel system needs to be initialised and synchronised before
108      * the program is run.  
109      */ 
110     startupParallelSystem(argv);
111      
112     if (*argv[0] == '-') { /* Strip off mainPE flag argument */
113       argv++; 
114       argc--;                   
115     }
116
117     argv[1] = argv[0];   /* ignore the nPEs argument */
118     argv++; argc--;
119 #endif
120
121     /* Set the RTS flags to default values. */
122     initRtsFlagsDefaults();
123
124     /* Call the user hook to reset defaults, if present */
125     defaultsHook();
126
127     /* Parse the flags, separating the RTS flags from the programs args */
128     setupRtsFlags(&argc, argv, &rts_argc, rts_argv);
129     prog_argc = argc;
130     prog_argv = argv;
131
132 #if defined(PAR)
133     /* NB: this really must be done after processing the RTS flags */
134     IF_PAR_DEBUG(verbose,
135                  fprintf(stderr, "==== Synchronising system (%d PEs)\n", nPEs));
136     synchroniseSystem();             // calls initParallelSystem etc
137 #endif  /* PAR */
138
139     /* initialise scheduler data structures (needs to be done before
140      * initStorage()).
141      */
142     initScheduler();
143
144 #if defined(GRAN)
145     /* And start GranSim profiling if required: */
146     if (RtsFlags.GranFlags.GranSimStats.Full)
147       init_gr_simulation(rts_argc, rts_argv, prog_argc, prog_argv);
148 #elif defined(PAR)
149     /* And start GUM profiling if required: */
150     if (RtsFlags.ParFlags.ParStats.Full)
151       init_gr_simulation(rts_argc, rts_argv, prog_argc, prog_argv);
152 #endif  /* PAR || GRAN */
153
154     /* initialize the storage manager */
155     initStorage();
156
157     /* initialise the stable pointer table */
158     initStablePtrTable();
159
160     /* initialise thread label table (tso->char*) */
161     initThreadLabelTable();
162
163 #if defined(PROFILING) || defined(DEBUG)
164     initProfiling1();
165 #endif
166
167     /* run the per-module initialisation code */
168     initModules(init_root);
169
170 #if defined(PROFILING) || defined(DEBUG)
171     initProfiling2();
172 #endif
173
174     /* start the virtual timer 'subsystem'. */
175     startVirtTimer(TICK_MILLISECS);
176
177     /* Initialise the stats department */
178     initStats();
179
180 #if !defined(mingw32_TARGET_OS) && !defined(PAR)
181     /* Initialise the user signal handler set */
182     initUserSignals();
183     /* Set up handler to run on SIGINT, etc. */
184     initDefaultHandlers();
185 #endif
186  
187 #ifdef RTS_GTK_FRONTPANEL
188     if (RtsFlags.GcFlags.frontpanel) {
189         initFrontPanel();
190     }
191 #endif
192
193     /* Record initialization times */
194     stat_endInit();
195 }
196
197 /* -----------------------------------------------------------------------------
198    Per-module initialisation
199
200    This process traverses all the compiled modules in the program
201    starting with "Main", and performing per-module initialisation for
202    each one.
203
204    So far, two things happen at initialisation time:
205
206       - we register stable names for each foreign-exported function
207         in that module.  This prevents foreign-exported entities, and
208         things they depend on, from being garbage collected.
209
210       - we supply a unique integer to each statically declared cost
211         centre and cost centre stack in the program.
212
213    The code generator inserts a small function "__stginit_<module>" in each
214    module and calls the registration functions in each of the modules it
215    imports.  So, if we call "__stginit_PrelMain", each reachable module in the
216    program will be registered (because PrelMain.mainIO calls Main.main).
217
218    The init* functions are compiled in the same way as STG code,
219    i.e. without normal C call/return conventions.  Hence we must use
220    StgRun to call this stuff.
221    -------------------------------------------------------------------------- */
222
223 /* The init functions use an explicit stack... 
224  */
225 #define INIT_STACK_BLOCKS  4
226 F_ *init_stack = NULL;
227 nat init_sp = 0;
228
229 static void
230 initModules ( void (*init_root)(void) )
231 {
232     bdescr *bd;
233 #ifdef SMP
234     Capability cap;
235 #else
236 #define cap MainCapability
237 #endif
238
239     init_sp = 0;
240     bd = allocGroup(INIT_STACK_BLOCKS);
241     init_stack = (F_ *)bd->start;
242     init_stack[init_sp++] = (F_)stg_init_ret;
243     init_stack[init_sp++] = (F_)__stginit_Prelude;
244     if (init_root != NULL) {
245         init_stack[init_sp++] = (F_)init_root;
246     }
247     
248     cap.r.rSp = (P_)(init_stack + init_sp);
249     StgRun((StgFunPtr)stg_init, &cap.r);
250
251     freeGroup(bd);
252 }
253
254 /* -----------------------------------------------------------------------------
255  * Shutting down the RTS - two ways of doing this, one which
256  * calls exit(), one that doesn't.
257  *
258  * (shutdownHaskellAndExit() is called by System.exitWith).
259  * -----------------------------------------------------------------------------
260  */
261 void
262 shutdownHaskellAndExit(int n)
263 {
264   OnExitHook();
265   shutdownHaskell();
266 #if defined(PAR)
267   /* really exit (stg_exit() would call shutdownParallelSystem() again) */
268   exit(n);
269 #else
270   stg_exit(n);
271 #endif
272 }
273
274 void
275 shutdownHaskell(void)
276 {
277   if (!rts_has_started_up)
278      return;
279   rts_has_started_up=0;
280   
281   /* start timing the shutdown */
282   stat_startExit();
283
284   /* stop all running tasks */
285   exitScheduler();
286
287 #if !defined(GRAN)
288   /* Finalize any remaining weak pointers */
289   finalizeWeakPointersNow();
290 #endif
291
292 #if defined(GRAN)
293   /* end_gr_simulation prints global stats if requested -- HWL */
294   if (!RtsFlags.GranFlags.GranSimStats.Suppressed)
295     end_gr_simulation();
296 #endif
297
298   /* stop the ticker */
299   stopVirtTimer();
300   
301   /* reset the standard file descriptors to blocking mode */
302   resetNonBlockingFd(0);
303   resetNonBlockingFd(1);
304   resetNonBlockingFd(2);
305
306 #if defined(PAR)
307   /* controlled exit; good thread! */
308   shutdownParallelSystem(0);
309
310   /* global statistics in parallel system */
311   PAR_TICKY_PAR_END();
312 #endif
313
314   /* stop timing the shutdown, we're about to print stats */
315   stat_endExit();
316
317   /* clean up things from the storage manager's point of view.
318    * also outputs the stats (+RTS -s) info.
319    */
320   exitStorage();
321
322 #ifdef RTS_GTK_FRONTPANEL
323     if (RtsFlags.GcFlags.frontpanel) {
324         stopFrontPanel();
325     }
326 #endif
327
328 #if defined(PROFILING) 
329   reportCCSProfiling();
330 #endif
331
332 #if defined(PROFILING) || defined(DEBUG)
333   endProfiling();
334 #endif
335
336 #ifdef PROFILING
337   // Originally, this was in report_ccs_profiling().  Now, retainer
338   // profiling might tack some extra stuff on to the end of this file
339   // during endProfiling().
340   fclose(prof_file);
341 #endif
342
343 #if defined(TICKY_TICKY)
344   if (RtsFlags.TickyFlags.showTickyStats) PrintTickyInfo();
345 #endif
346 }
347
348 /* 
349  * called from STG-land to exit the program
350  */
351
352 #ifdef PAR
353 static int exit_started=rtsFalse;
354 #endif
355
356 void  
357 stg_exit(I_ n)
358
359 #ifdef PAR
360   /* HACK: avoid a loop when exiting due to a stupid error */
361   if (exit_started) 
362     return;
363   exit_started=rtsTrue;
364
365   IF_PAR_DEBUG(verbose, fprintf(stderr,"==-- stg_exit %d on [%x]...", n, mytid));
366   shutdownParallelSystem(n);
367 #endif
368   exit(n);
369 }
370