Add capability sets to the event system. Contains code from Duncan Coutts.
[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     /* Trace some basic information about the process
152      */
153     traceCapsetDetails(argc, argv);
154
155     /* initialise scheduler data structures (needs to be done before
156      * initStorage()).
157      */
158     initScheduler();
159
160     /* initialize the storage manager */
161     initStorage();
162
163     /* initialise the stable pointer table */
164     initStablePtrTable();
165
166     /* Add some GC roots for things in the base package that the RTS
167      * knows about.  We don't know whether these turn out to be CAFs
168      * or refer to CAFs, but we have to assume that they might.
169      */
170     getStablePtr((StgPtr)runIO_closure);
171     getStablePtr((StgPtr)runNonIO_closure);
172
173     getStablePtr((StgPtr)runFinalizerBatch_closure);
174
175     getStablePtr((StgPtr)stackOverflow_closure);
176     getStablePtr((StgPtr)heapOverflow_closure);
177     getStablePtr((StgPtr)unpackCString_closure);
178     getStablePtr((StgPtr)blockedIndefinitelyOnMVar_closure);
179     getStablePtr((StgPtr)nonTermination_closure);
180     getStablePtr((StgPtr)blockedIndefinitelyOnSTM_closure);
181     getStablePtr((StgPtr)nestedAtomically_closure);
182
183     getStablePtr((StgPtr)runSparks_closure);
184     getStablePtr((StgPtr)ensureIOManagerIsRunning_closure);
185 #ifndef mingw32_HOST_OS
186     getStablePtr((StgPtr)runHandlers_closure);
187 #endif
188
189     /* initialise the shared Typeable store */
190     initGlobalStore();
191
192     /* initialise file locking, if necessary */
193 #if !defined(mingw32_HOST_OS)    
194     initFileLocking();
195 #endif
196
197 #if defined(DEBUG)
198     /* initialise thread label table (tso->char*) */
199     initThreadLabelTable();
200 #endif
201
202     initProfiling1();
203
204     /* start the virtual timer 'subsystem'. */
205     initTimer();
206     startTimer();
207
208 #if defined(RTS_USER_SIGNALS)
209     if (RtsFlags.MiscFlags.install_signal_handlers) {
210         /* Initialise the user signal handler set */
211         initUserSignals();
212         /* Set up handler to run on SIGINT, etc. */
213         initDefaultHandlers();
214     }
215 #endif
216  
217 #if defined(mingw32_HOST_OS) && !defined(THREADED_RTS)
218     startupAsyncIO();
219 #endif
220
221 #ifdef RTS_GTK_FRONTPANEL
222     if (RtsFlags.GcFlags.frontpanel) {
223         initFrontPanel();
224     }
225 #endif
226
227 #if X86_INIT_FPU
228     x86_init_fpu();
229 #endif
230
231     startupHpc();
232
233     // This must be done after module initialisation.
234     // ToDo: make this work in the presence of multiple hs_add_root()s.
235     initProfiling2();
236
237     // ditto.
238 #if defined(THREADED_RTS)
239     ioManagerStart();
240 #endif
241
242     /* Record initialization times */
243     stat_endInit();
244 }
245
246 // Compatibility interface
247 void
248 startupHaskell(int argc, char *argv[], void (*init_root)(void) STG_UNUSED)
249 {
250     hs_init(&argc, &argv);
251 }
252
253
254 /* -----------------------------------------------------------------------------
255    hs_add_root: backwards compatibility.  (see #3252)
256    -------------------------------------------------------------------------- */
257
258 void
259 hs_add_root(void (*init_root)(void) STG_UNUSED)
260 {
261     /* nothing */
262 }
263
264 /* ----------------------------------------------------------------------------
265  * Shutting down the RTS
266  *
267  * The wait_foreign parameter means:
268  *       True  ==> wait for any threads doing foreign calls now.
269  *       False ==> threads doing foreign calls may return in the
270  *                 future, but will immediately block on a mutex.
271  *                 (capability->lock).
272  * 
273  * If this RTS is a DLL that we're about to unload, then you want
274  * safe=True, otherwise the thread might return to code that has been
275  * unloaded.  If this is a standalone program that is about to exit,
276  * then you can get away with safe=False, which is better because we
277  * won't hang on exit if there is a blocked foreign call outstanding.
278  *
279  ------------------------------------------------------------------------- */
280
281 static void
282 hs_exit_(rtsBool wait_foreign)
283 {
284     if (hs_init_count <= 0) {
285         errorBelch("warning: too many hs_exit()s");
286         return;
287     }
288     hs_init_count--;
289     if (hs_init_count > 0) {
290         // ignore until it's the last one
291         return;
292     }
293
294     /* start timing the shutdown */
295     stat_startExit();
296     
297     OnExitHook();
298
299     // sanity check
300 #if defined(DEBUG)
301     checkFPUStack();
302 #endif
303
304     // Free the full argv storage
305     freeFullProgArgv();
306
307 #if defined(THREADED_RTS)
308     ioManagerDie();
309 #endif
310
311     /* stop all running tasks */
312     exitScheduler(wait_foreign);
313
314     /* run C finalizers for all active weak pointers */
315     runAllCFinalizers(weak_ptr_list);
316     
317 #if defined(RTS_USER_SIGNALS)
318     if (RtsFlags.MiscFlags.install_signal_handlers) {
319         freeSignalHandlers();
320     }
321 #endif
322
323     /* stop the ticker */
324     stopTimer();
325     exitTimer(wait_foreign);
326
327     // set the terminal settings back to what they were
328 #if !defined(mingw32_HOST_OS)    
329     resetTerminalSettings();
330 #endif
331
332     // uninstall signal handlers
333     resetDefaultHandlers();
334
335     /* stop timing the shutdown, we're about to print stats */
336     stat_endExit();
337     
338     /* shutdown the hpc support (if needed) */
339     exitHpc();
340
341     // clean up things from the storage manager's point of view.
342     // also outputs the stats (+RTS -s) info.
343     exitStorage();
344     
345     /* free the tasks */
346     freeScheduler();
347
348     /* free shared Typeable store */
349     exitGlobalStore();
350
351     /* free linker data */
352     exitLinker();
353
354     /* free file locking tables, if necessary */
355 #if !defined(mingw32_HOST_OS)    
356     freeFileLocking();
357 #endif
358
359     /* free the stable pointer table */
360     exitStablePtrTable();
361
362 #if defined(DEBUG)
363     /* free the thread label table */
364     freeThreadLabelTable();
365 #endif
366
367 #ifdef RTS_GTK_FRONTPANEL
368     if (RtsFlags.GcFlags.frontpanel) {
369         stopFrontPanel();
370     }
371 #endif
372
373 #if defined(PROFILING) 
374     reportCCSProfiling();
375 #endif
376
377     endProfiling();
378     freeProfiling();
379
380 #ifdef PROFILING
381     // Originally, this was in report_ccs_profiling().  Now, retainer
382     // profiling might tack some extra stuff on to the end of this file
383     // during endProfiling().
384     if (prof_file != NULL) fclose(prof_file);
385 #endif
386
387 #ifdef TRACING
388     endTracing();
389     freeTracing();
390 #endif
391
392 #if defined(TICKY_TICKY)
393     if (RtsFlags.TickyFlags.showTickyStats) PrintTickyInfo();
394 #endif
395
396 #if defined(mingw32_HOST_OS) && !defined(THREADED_RTS)
397     shutdownAsyncIO(wait_foreign);
398 #endif
399
400     /* free hash table storage */
401     exitHashTable();
402
403     // Finally, free all our storage.  However, we only free the heap
404     // memory if we have waited for foreign calls to complete;
405     // otherwise a foreign call in progress may still be referencing
406     // heap memory (e.g. by being passed a ByteArray#).
407     freeStorage(wait_foreign);
408
409 }
410
411 // The real hs_exit():
412 void
413 hs_exit(void)
414 {
415     hs_exit_(rtsTrue);
416     // be safe; this might be a DLL
417 }
418
419 // Compatibility interfaces
420 void
421 shutdownHaskell(void)
422 {
423     hs_exit();
424 }
425
426 void
427 shutdownHaskellAndExit(int n)
428 {
429     // we're about to exit(), no need to wait for foreign calls to return.
430     hs_exit_(rtsFalse);
431
432     if (hs_init_count == 0) {
433         stg_exit(n);
434     }
435 }
436
437 #ifndef mingw32_HOST_OS
438 void
439 shutdownHaskellAndSignal(int sig)
440 {
441     hs_exit_(rtsFalse);
442     kill(getpid(),sig);
443 }
444 #endif
445
446 /* 
447  * called from STG-land to exit the program
448  */
449
450 void (*exitFn)(int) = 0;
451
452 void  
453 stg_exit(int n)
454
455   if (exitFn)
456     (*exitFn)(n);
457   exit(n);
458 }