merge upstream HEAD
[ghc-hetmet.git] / rts / RtsStartup.c
1 /* -----------------------------------------------------------------------------
2  *
3  * (c) The GHC Team, 1998-2002
4  *
5  * Main function for a standalone Haskell program.
6  *
7  * ---------------------------------------------------------------------------*/
8
9 // PAPI uses caddr_t, which is not POSIX
10 #ifndef USE_PAPI
11 #include "PosixSource.h"
12 #endif
13
14 #include "Rts.h"
15 #include "RtsAPI.h"
16 #include "HsFFI.h"
17
18 #include "sm/Storage.h"
19 #include "RtsFlags.h"
20 #include "RtsUtils.h"
21 #include "Prelude.h"
22 #include "Schedule.h"   /* initScheduler */
23 #include "Stats.h"      /* initStats */
24 #include "STM.h"        /* initSTM */
25 #include "RtsSignals.h"
26 #include "Weak.h"
27 #include "Ticky.h"
28 #include "StgRun.h"
29 #include "Prelude.h"            /* fixupRTStoPreludeRefs */
30 #include "ThreadLabels.h"
31 #include "sm/BlockAlloc.h"
32 #include "Trace.h"
33 #include "Stable.h"
34 #include "Hash.h"
35 #include "Profiling.h"
36 #include "Timer.h"
37 #include "Globals.h"
38 void exitLinker( void );        // there is no Linker.h file to include
39
40 #if defined(RTS_GTK_FRONTPANEL)
41 #include "FrontPanel.h"
42 #endif
43
44 #if defined(PROFILING)
45 # include "ProfHeap.h"
46 # include "RetainerProfile.h"
47 #endif
48
49 #if defined(mingw32_HOST_OS) && !defined(THREADED_RTS)
50 #include "win32/AsyncIO.h"
51 #endif
52
53 #if !defined(mingw32_HOST_OS)
54 #include "posix/TTY.h"
55 #include "posix/FileLock.h"
56 #endif
57
58 #ifdef HAVE_UNISTD_H
59 #include <unistd.h>
60 #endif
61 #ifdef HAVE_LOCALE_H
62 #include <locale.h>
63 #endif
64
65 #if USE_PAPI
66 #include "Papi.h"
67 #endif
68
69 // Count of how many outstanding hs_init()s there have been.
70 static int hs_init_count = 0;
71
72 /* -----------------------------------------------------------------------------
73    Initialise floating point unit on x86 (currently disabled; See Note
74    [x86 Floating point precision] in compiler/nativeGen/X86/Instr.hs)
75    -------------------------------------------------------------------------- */
76
77 #define X86_INIT_FPU 0
78
79 #if X86_INIT_FPU
80 static void
81 x86_init_fpu ( void )
82 {
83   __volatile unsigned short int fpu_cw;
84
85   // Grab the control word
86   __asm __volatile ("fnstcw %0" : "=m" (fpu_cw));
87
88 #if 0
89   printf("fpu_cw: %x\n", fpu_cw);
90 #endif
91
92   // Set bits 8-9 to 10 (64-bit precision).
93   fpu_cw = (fpu_cw & 0xfcff) | 0x0200;
94
95   // Store the new control word back
96   __asm __volatile ("fldcw %0" : : "m" (fpu_cw));
97 }
98 #endif
99
100 /* -----------------------------------------------------------------------------
101    Starting up the RTS
102    -------------------------------------------------------------------------- */
103
104 void
105 hs_init(int *argc, char **argv[])
106 {
107     hs_init_count++;
108     if (hs_init_count > 1) {
109         // second and subsequent inits are ignored
110         return;
111     }
112
113     setlocale(LC_CTYPE,"");
114
115     /* Initialise the stats department, phase 0 */
116     initStats0();
117
118     /* Next we do is grab the start time...just in case we're
119      * collecting timing statistics.
120      */
121     stat_startInit();
122
123     /* Set the RTS flags to default values. */
124
125     initRtsFlagsDefaults();
126
127     /* Call the user hook to reset defaults, if present */
128     defaultsHook();
129
130     /* Parse the flags, separating the RTS flags from the programs args */
131     if (argc != NULL && argv != NULL) {
132         setFullProgArgv(*argc,*argv);
133         setupRtsFlags(argc, *argv);
134     }
135
136     /* Initialise the stats department, phase 1 */
137     initStats1();
138
139 #ifdef USE_PAPI
140     papi_init();
141 #endif
142
143     /* initTracing must be after setupRtsFlags() */
144 #ifdef TRACING
145     initTracing();
146 #endif
147     /* Dtrace events are always enabled
148      */
149     dtraceEventStartup();
150
151     /* initialise scheduler data structures (needs to be done before
152      * initStorage()).
153      */
154     initScheduler();
155
156     /* initialize the storage manager */
157     initStorage();
158
159     /* initialise the stable pointer table */
160     initStablePtrTable();
161
162     /* Add some GC roots for things in the base package that the RTS
163      * knows about.  We don't know whether these turn out to be CAFs
164      * or refer to CAFs, but we have to assume that they might.
165      */
166     getStablePtr((StgPtr)runIO_closure);
167     getStablePtr((StgPtr)runNonIO_closure);
168
169     getStablePtr((StgPtr)runFinalizerBatch_closure);
170
171     getStablePtr((StgPtr)stackOverflow_closure);
172     getStablePtr((StgPtr)heapOverflow_closure);
173     getStablePtr((StgPtr)unpackCString_closure);
174     getStablePtr((StgPtr)blockedIndefinitelyOnMVar_closure);
175     getStablePtr((StgPtr)nonTermination_closure);
176     getStablePtr((StgPtr)blockedIndefinitelyOnSTM_closure);
177     getStablePtr((StgPtr)nestedAtomically_closure);
178
179     getStablePtr((StgPtr)runSparks_closure);
180     getStablePtr((StgPtr)ensureIOManagerIsRunning_closure);
181 #ifndef mingw32_HOST_OS
182     getStablePtr((StgPtr)runHandlers_closure);
183 #endif
184
185     /* initialise the shared Typeable store */
186     initGlobalStore();
187
188     /* initialise file locking, if necessary */
189 #if !defined(mingw32_HOST_OS)    
190     initFileLocking();
191 #endif
192
193 #if defined(DEBUG)
194     /* initialise thread label table (tso->char*) */
195     initThreadLabelTable();
196 #endif
197
198     initProfiling1();
199
200     /* start the virtual timer 'subsystem'. */
201     initTimer();
202     startTimer();
203
204 #if defined(RTS_USER_SIGNALS)
205     if (RtsFlags.MiscFlags.install_signal_handlers) {
206         /* Initialise the user signal handler set */
207         initUserSignals();
208         /* Set up handler to run on SIGINT, etc. */
209         initDefaultHandlers();
210     }
211 #endif
212  
213 #if defined(mingw32_HOST_OS) && !defined(THREADED_RTS)
214     startupAsyncIO();
215 #endif
216
217 #ifdef RTS_GTK_FRONTPANEL
218     if (RtsFlags.GcFlags.frontpanel) {
219         initFrontPanel();
220     }
221 #endif
222
223 #if X86_INIT_FPU
224     x86_init_fpu();
225 #endif
226
227     startupHpc();
228
229     // This must be done after module initialisation.
230     // ToDo: make this work in the presence of multiple hs_add_root()s.
231     initProfiling2();
232
233     // ditto.
234 #if defined(THREADED_RTS)
235     ioManagerStart();
236 #endif
237
238     /* Record initialization times */
239     stat_endInit();
240 }
241
242 // Compatibility interface
243 void
244 startupHaskell(int argc, char *argv[], void (*init_root)(void) STG_UNUSED)
245 {
246     hs_init(&argc, &argv);
247 }
248
249
250 /* -----------------------------------------------------------------------------
251    hs_add_root: backwards compatibility.  (see #3252)
252    -------------------------------------------------------------------------- */
253
254 void
255 hs_add_root(void (*init_root)(void) STG_UNUSED)
256 {
257     /* nothing */
258 }
259
260 /* ----------------------------------------------------------------------------
261  * Shutting down the RTS
262  *
263  * The wait_foreign parameter means:
264  *       True  ==> wait for any threads doing foreign calls now.
265  *       False ==> threads doing foreign calls may return in the
266  *                 future, but will immediately block on a mutex.
267  *                 (capability->lock).
268  * 
269  * If this RTS is a DLL that we're about to unload, then you want
270  * safe=True, otherwise the thread might return to code that has been
271  * unloaded.  If this is a standalone program that is about to exit,
272  * then you can get away with safe=False, which is better because we
273  * won't hang on exit if there is a blocked foreign call outstanding.
274  *
275  ------------------------------------------------------------------------- */
276
277 static void
278 hs_exit_(rtsBool wait_foreign)
279 {
280     if (hs_init_count <= 0) {
281         errorBelch("warning: too many hs_exit()s");
282         return;
283     }
284     hs_init_count--;
285     if (hs_init_count > 0) {
286         // ignore until it's the last one
287         return;
288     }
289
290     /* start timing the shutdown */
291     stat_startExit();
292     
293     OnExitHook();
294
295     // sanity check
296 #if defined(DEBUG)
297     checkFPUStack();
298 #endif
299
300     // Free the full argv storage
301     freeFullProgArgv();
302
303 #if defined(THREADED_RTS)
304     ioManagerDie();
305 #endif
306
307     /* stop all running tasks */
308     exitScheduler(wait_foreign);
309
310     /* run C finalizers for all active weak pointers */
311     runAllCFinalizers(weak_ptr_list);
312     
313 #if defined(RTS_USER_SIGNALS)
314     if (RtsFlags.MiscFlags.install_signal_handlers) {
315         freeSignalHandlers();
316     }
317 #endif
318
319     /* stop the ticker */
320     stopTimer();
321     exitTimer(wait_foreign);
322
323     // set the terminal settings back to what they were
324 #if !defined(mingw32_HOST_OS)    
325     resetTerminalSettings();
326 #endif
327
328     // uninstall signal handlers
329     resetDefaultHandlers();
330
331     /* stop timing the shutdown, we're about to print stats */
332     stat_endExit();
333     
334     /* shutdown the hpc support (if needed) */
335     exitHpc();
336
337     // clean up things from the storage manager's point of view.
338     // also outputs the stats (+RTS -s) info.
339     exitStorage();
340     
341     /* free the tasks */
342     freeScheduler();
343
344     /* free shared Typeable store */
345     exitGlobalStore();
346
347     /* free linker data */
348     exitLinker();
349
350     /* free file locking tables, if necessary */
351 #if !defined(mingw32_HOST_OS)    
352     freeFileLocking();
353 #endif
354
355     /* free the stable pointer table */
356     exitStablePtrTable();
357
358 #if defined(DEBUG)
359     /* free the thread label table */
360     freeThreadLabelTable();
361 #endif
362
363 #ifdef RTS_GTK_FRONTPANEL
364     if (RtsFlags.GcFlags.frontpanel) {
365         stopFrontPanel();
366     }
367 #endif
368
369 #if defined(PROFILING) 
370     reportCCSProfiling();
371 #endif
372
373     endProfiling();
374     freeProfiling();
375
376 #ifdef PROFILING
377     // Originally, this was in report_ccs_profiling().  Now, retainer
378     // profiling might tack some extra stuff on to the end of this file
379     // during endProfiling().
380     if (prof_file != NULL) fclose(prof_file);
381 #endif
382
383 #ifdef TRACING
384     endTracing();
385     freeTracing();
386 #endif
387
388 #if defined(TICKY_TICKY)
389     if (RtsFlags.TickyFlags.showTickyStats) PrintTickyInfo();
390 #endif
391
392 #if defined(mingw32_HOST_OS) && !defined(THREADED_RTS)
393     shutdownAsyncIO(wait_foreign);
394 #endif
395
396     /* free hash table storage */
397     exitHashTable();
398
399     // Finally, free all our storage.  However, we only free the heap
400     // memory if we have waited for foreign calls to complete;
401     // otherwise a foreign call in progress may still be referencing
402     // heap memory (e.g. by being passed a ByteArray#).
403     freeStorage(wait_foreign);
404
405 }
406
407 // The real hs_exit():
408 void
409 hs_exit(void)
410 {
411     hs_exit_(rtsTrue);
412     // be safe; this might be a DLL
413 }
414
415 // Compatibility interfaces
416 void
417 shutdownHaskell(void)
418 {
419     hs_exit();
420 }
421
422 void
423 shutdownHaskellAndExit(int n)
424 {
425     // we're about to exit(), no need to wait for foreign calls to return.
426     hs_exit_(rtsFalse);
427
428     if (hs_init_count == 0) {
429         stg_exit(n);
430     }
431 }
432
433 #ifndef mingw32_HOST_OS
434 void
435 shutdownHaskellAndSignal(int sig)
436 {
437     hs_exit_(rtsFalse);
438     kill(getpid(),sig);
439 }
440 #endif
441
442 /* 
443  * called from STG-land to exit the program
444  */
445
446 void (*exitFn)(int) = 0;
447
448 void  
449 stg_exit(int n)
450
451   if (exitFn)
452     (*exitFn)(n);
453   exit(n);
454 }