[project @ 2000-03-08 17:48:24 by simonmar]
[ghc-hetmet.git] / ghc / rts / RtsStartup.c
1 /* -----------------------------------------------------------------------------
2  * $Id: RtsStartup.c,v 1.31 2000/03/08 17:48:24 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     initModules();
137
138 #if defined(PROFILING) || defined(DEBUG)
139     initProfiling2();
140 #endif
141
142     /* start the ticker */
143     install_vtalrm_handler();
144     initialize_virtual_timer(TICK_MILLISECS);
145
146     /* start our haskell execution tasks */
147 #ifdef SMP
148     startTasks();
149 #endif
150
151     /* Initialise the stats department */
152     initStats();
153
154 #if !defined(mingw32_TARGET_OS) && !defined(PAR)
155     /* Initialise the user signal handler set */
156     initUserSignals();
157     /* Set up handler to run on SIGINT, etc. */
158     init_default_handlers();
159 #endif
160  
161     /* When the RTS and Prelude live in separate DLLs,
162        we need to patch up the char- and int-like tables
163        that the RTS keep after both DLLs have been loaded,
164        filling in the tables with references to where the
165        static info tables have been loaded inside the running
166        process.
167     */
168 #ifdef ENABLE_WIN32_DLL_SUPPORT
169     for(i=0;i<=255;i++)
170        (CHARLIKE_closure[i]).header.info = (const StgInfoTable*)&Czh_static_info;
171
172     for(i=0;i<=32;i++)
173        (INTLIKE_closure[i]).header.info = (const StgInfoTable*)&Izh_static_info;
174        
175 #endif
176     /* Record initialization times */
177     end_init();
178 }
179
180 /* -----------------------------------------------------------------------------
181    Per-module initialisation
182
183    This process traverses all the compiled modules in the program
184    starting with "Main", and performing per-module initialisation for
185    each one.
186
187    So far, two things happen at initialisation time:
188
189       - we register stable names for each foreign-exported function
190         in that module.  This prevents foreign-exported entities, and
191         things they depend on, from being garbage collected.
192
193       - we supply a unique integer to each statically declared cost
194         centre and cost centre stack in the program.
195
196    The code generator inserts a small function "__init_<moddule>" in each
197    module and calls the registration functions in each of the modules
198    it imports.  So, if we call "__init_Main", each reachable module in the
199    program will be registered.
200
201    The init* functions are compiled in the same way as STG code,
202    i.e. without normal C call/return conventions.  Hence we must use
203    StgRun to call this stuff.
204    -------------------------------------------------------------------------- */
205
206 /* The init functions use an explicit stack... 
207  */
208 #define INIT_STACK_SIZE  (BLOCK_SIZE * 4)
209 F_ *init_stack;
210
211 static void
212 initModules ( void )
213 {
214   /* this storage will be reclaimed by the garbage collector,
215    * as a large block.
216    */
217   init_stack = (F_ *)allocate(INIT_STACK_SIZE / sizeof(W_));
218
219   StgRun((StgFunPtr)stg_init, NULL/* no reg table */);
220 }
221
222 /* -----------------------------------------------------------------------------
223  * Shutting down the RTS - two ways of doing this, one which
224  * calls exit(), one that doesn't.
225  *
226  * (shutdownHaskellAndExit() is called by System.exitWith).
227  * -----------------------------------------------------------------------------
228  */
229 void
230 shutdownHaskellAndExit(int n)
231 {
232   OnExitHook();
233   shutdownHaskell();
234   stg_exit(n);
235 }
236
237 void
238 shutdownHaskell(void)
239 {
240   if (!rts_has_started_up)
241      return;
242
243   /* start timing the shutdown */
244   stat_startExit();
245
246 #if !defined(GRAN)
247   /* Finalize any remaining weak pointers */
248   finalizeWeakPointersNow();
249 #endif
250
251 #if defined(GRAN)
252   /* end_gr_simulation prints global stats if requested -- HWL */
253   if (!RtsFlags.GranFlags.GranSimStats.Suppressed)
254     end_gr_simulation();
255 #endif
256
257   /* stop all running tasks */
258   exitScheduler();
259
260   /* stop the ticker */
261   initialize_virtual_timer(0);
262   
263   /* reset the standard file descriptors to blocking mode */
264   resetNonBlockingFd(0);
265   resetNonBlockingFd(1);
266   resetNonBlockingFd(2);
267
268   /* stop timing the shutdown, we're about to print stats */
269   stat_endExit();
270
271   /* clean up things from the storage manager's point of view.
272    * also outputs the stats (+RTS -s) info.
273    */
274   exitStorage();
275
276 #if defined(PROFILING) || defined(DEBUG)
277   endProfiling();
278 #endif
279
280 #if defined(PROFILING) 
281   report_ccs_profiling();
282 #endif
283
284 #if defined(TICKY_TICKY)
285   if (RtsFlags.TickyFlags.showTickyStats) PrintTickyInfo();
286 #endif
287
288   rts_has_started_up=0;
289
290 #if defined(PAR)
291   shutdownParallelSystem(0);
292 #endif
293
294 }
295
296 /* 
297  * called from STG-land to exit the program
298  */
299
300 void  
301 stg_exit(I_ n)
302 {
303 #if 0 /* def PAR */
304   par_exit(n);
305 #else
306   exit(n);
307 #endif
308 }
309