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