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