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