fix a warning
[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 // #include "PosixSource.h"
11
12 #include "Rts.h"
13 #include "RtsAPI.h"
14 #include "RtsUtils.h"
15 #include "RtsFlags.h"  
16 #include "OSThreads.h"
17 #include "Schedule.h"   /* initScheduler */
18 #include "Stats.h"      /* initStats */
19 #include "STM.h"        /* initSTM */
20 #include "Signals.h"
21 #include "RtsSignals.h"
22 #include "ThrIOManager.h"
23 #include "Timer.h"      /* startTimer, stopTimer */
24 #include "Weak.h"
25 #include "Ticky.h"
26 #include "StgRun.h"
27 #include "Prelude.h"            /* fixupRTStoPreludeRefs */
28 #include "HsFFI.h"
29 #include "Linker.h"
30 #include "ThreadLabels.h"
31 #include "BlockAlloc.h"
32 #include "Trace.h"
33 #include "RtsGlobals.h"
34 #include "Stable.h"
35 #include "Hpc.h"
36 #include "FileLock.h"
37 #include "EventLog.h"
38 #include "Hash.h"
39
40 #if defined(RTS_GTK_FRONTPANEL)
41 #include "FrontPanel.h"
42 #endif
43
44 # include "Profiling.h"
45
46 #if defined(PROFILING)
47 # include "ProfHeap.h"
48 # include "RetainerProfile.h"
49 #endif
50
51 #if defined(mingw32_HOST_OS) && !defined(THREADED_RTS)
52 #include "win32/AsyncIO.h"
53 #endif
54
55 #include <stdlib.h>
56
57 #ifdef HAVE_TERMIOS_H
58 #include <termios.h>
59 #endif
60 #ifdef HAVE_SIGNAL_H
61 #include <signal.h>
62 #endif
63 #ifdef HAVE_UNISTD_H
64 #include <unistd.h>
65 #endif
66
67 #if USE_PAPI
68 #include "Papi.h"
69 #endif
70
71 // Count of how many outstanding hs_init()s there have been.
72 static int hs_init_count = 0;
73
74 // Here we save the terminal settings on the standard file
75 // descriptors, if we need to change them (eg. to support NoBuffering
76 // input).
77 static void *saved_termios[3] = {NULL,NULL,NULL};
78
79 void*
80 __hscore_get_saved_termios(int fd)
81 {
82   return (0 <= fd && fd < (int)(sizeof(saved_termios) / sizeof(*saved_termios))) ?
83     saved_termios[fd] : NULL;
84 }
85
86 void
87 __hscore_set_saved_termios(int fd, void* ts)
88 {
89   if (0 <= fd && fd < (int)(sizeof(saved_termios) / sizeof(*saved_termios))) {
90     saved_termios[fd] = ts;
91   }
92 }
93
94 /* -----------------------------------------------------------------------------
95    Initialise floating point unit on x86 (currently disabled. why?)
96    (see comment in ghc/compiler/nativeGen/MachInstrs.lhs).
97    -------------------------------------------------------------------------- */
98
99 #define X86_INIT_FPU 0
100
101 #if X86_INIT_FPU
102 static void
103 x86_init_fpu ( void )
104 {
105   __volatile unsigned short int fpu_cw;
106
107   // Grab the control word
108   __asm __volatile ("fnstcw %0" : "=m" (fpu_cw));
109
110 #if 0
111   printf("fpu_cw: %x\n", fpu_cw);
112 #endif
113
114   // Set bits 8-9 to 10 (64-bit precision).
115   fpu_cw = (fpu_cw & 0xfcff) | 0x0200;
116
117   // Store the new control word back
118   __asm __volatile ("fldcw %0" : : "m" (fpu_cw));
119 }
120 #endif
121
122 /* -----------------------------------------------------------------------------
123    Starting up the RTS
124    -------------------------------------------------------------------------- */
125
126 void
127 hs_init(int *argc, char **argv[])
128 {
129     hs_init_count++;
130     if (hs_init_count > 1) {
131         // second and subsequent inits are ignored
132         return;
133     }
134
135     /* Initialise the stats department, phase 0 */
136     initStats0();
137
138     /* Next we do is grab the start time...just in case we're
139      * collecting timing statistics.
140      */
141     stat_startInit();
142
143 #if defined(DEBUG)
144     /* Start off by initialising the allocator debugging so we can
145      * use it anywhere */
146     initAllocator();
147 #endif
148
149     /* Set the RTS flags to default values. */
150
151     initRtsFlagsDefaults();
152
153     /* Call the user hook to reset defaults, if present */
154     defaultsHook();
155
156     /* Parse the flags, separating the RTS flags from the programs args */
157     if (argc != NULL && argv != NULL) {
158         setFullProgArgv(*argc,*argv);
159         setupRtsFlags(argc, *argv, &rts_argc, rts_argv);
160         setProgArgv(*argc,*argv);
161     }
162
163     /* Initialise the stats department, phase 1 */
164     initStats1();
165
166 #ifdef USE_PAPI
167     papi_init();
168 #endif
169
170     /* initTracing must be after setupRtsFlags() */
171 #ifdef DEBUG
172     initTracing();
173 #endif
174
175     /* initialise scheduler data structures (needs to be done before
176      * initStorage()).
177      */
178     initScheduler();
179
180     /* initialize the storage manager */
181     initStorage();
182
183     /* initialise the stable pointer table */
184     initStablePtrTable();
185
186     /* Add some GC roots for things in the base package that the RTS
187      * knows about.  We don't know whether these turn out to be CAFs
188      * or refer to CAFs, but we have to assume that they might.
189      */
190     getStablePtr((StgPtr)base_GHCziTopHandler_runIO_closure);
191     getStablePtr((StgPtr)base_GHCziTopHandler_runNonIO_closure);
192     getStablePtr((StgPtr)stackOverflow_closure);
193     getStablePtr((StgPtr)heapOverflow_closure);
194     getStablePtr((StgPtr)runFinalizerBatch_closure);
195     getStablePtr((StgPtr)unpackCString_closure);
196     getStablePtr((StgPtr)blockedOnDeadMVar_closure);
197     getStablePtr((StgPtr)nonTermination_closure);
198     getStablePtr((StgPtr)blockedIndefinitely_closure);
199
200     /* initialise the shared Typeable store */
201     initGlobalStore();
202
203     /* initialise file locking, if necessary */
204 #if !defined(mingw32_HOST_OS)    
205     initFileLocking();
206 #endif
207
208 #if defined(DEBUG)
209     /* initialise thread label table (tso->char*) */
210     initThreadLabelTable();
211 #endif
212
213     initProfiling1();
214
215 #ifdef EVENTLOG
216     if (RtsFlags.EventLogFlags.doEventLogging) {
217         initEventLogging();
218     }
219 #endif
220
221     /* start the virtual timer 'subsystem'. */
222     initTimer();
223     startTimer();
224
225 #if defined(RTS_USER_SIGNALS)
226     if (RtsFlags.MiscFlags.install_signal_handlers) {
227         /* Initialise the user signal handler set */
228         initUserSignals();
229         /* Set up handler to run on SIGINT, etc. */
230         initDefaultHandlers();
231     }
232 #endif
233  
234 #if defined(mingw32_HOST_OS) && !defined(THREADED_RTS)
235     startupAsyncIO();
236 #endif
237
238 #ifdef RTS_GTK_FRONTPANEL
239     if (RtsFlags.GcFlags.frontpanel) {
240         initFrontPanel();
241     }
242 #endif
243
244 #if X86_INIT_FPU
245     x86_init_fpu();
246 #endif
247
248     /* Record initialization times */
249     stat_endInit();
250 }
251
252 // Compatibility interface
253 void
254 startupHaskell(int argc, char *argv[], void (*init_root)(void))
255 {
256     hs_init(&argc, &argv);
257     if(init_root)
258         hs_add_root(init_root);
259 }
260
261
262 /* -----------------------------------------------------------------------------
263    Per-module initialisation
264
265    This process traverses all the compiled modules in the program
266    starting with "Main", and performing per-module initialisation for
267    each one.
268
269    So far, two things happen at initialisation time:
270
271       - we register stable names for each foreign-exported function
272         in that module.  This prevents foreign-exported entities, and
273         things they depend on, from being garbage collected.
274
275       - we supply a unique integer to each statically declared cost
276         centre and cost centre stack in the program.
277
278    The code generator inserts a small function "__stginit_<module>" in each
279    module and calls the registration functions in each of the modules it
280    imports.
281
282    The init* functions are compiled in the same way as STG code,
283    i.e. without normal C call/return conventions.  Hence we must use
284    StgRun to call this stuff.
285    -------------------------------------------------------------------------- */
286
287 /* The init functions use an explicit stack... 
288  */
289 #define INIT_STACK_BLOCKS  4
290 static F_ *init_stack = NULL;
291
292 void
293 hs_add_root(void (*init_root)(void))
294 {
295     bdescr *bd;
296     nat init_sp;
297     Capability *cap;
298
299     cap = rts_lock();
300
301     if (hs_init_count <= 0) {
302         barf("hs_add_root() must be called after hs_init()");
303     }
304
305     /* The initialisation stack grows downward, with sp pointing 
306        to the last occupied word */
307     init_sp = INIT_STACK_BLOCKS*BLOCK_SIZE_W;
308     bd = allocGroup_lock(INIT_STACK_BLOCKS);
309     init_stack = (F_ *)bd->start;
310     init_stack[--init_sp] = (F_)stg_init_finish;
311     if (init_root != NULL) {
312         init_stack[--init_sp] = (F_)init_root;
313     }
314     
315     cap->r.rSp = (P_)(init_stack + init_sp);
316     StgRun((StgFunPtr)stg_init, &cap->r);
317
318     freeGroup_lock(bd);
319
320     startupHpc();
321
322     // This must be done after module initialisation.
323     // ToDo: make this work in the presence of multiple hs_add_root()s.
324     initProfiling2();
325
326     rts_unlock(cap);
327
328     // ditto.
329 #if defined(THREADED_RTS)
330     ioManagerStart();
331 #endif
332 }
333
334 /* ----------------------------------------------------------------------------
335  * Shutting down the RTS
336  *
337  * The wait_foreign parameter means:
338  *       True  ==> wait for any threads doing foreign calls now.
339  *       False ==> threads doing foreign calls may return in the
340  *                 future, but will immediately block on a mutex.
341  *                 (capability->lock).
342  * 
343  * If this RTS is a DLL that we're about to unload, then you want
344  * safe=True, otherwise the thread might return to code that has been
345  * unloaded.  If this is a standalone program that is about to exit,
346  * then you can get away with safe=False, which is better because we
347  * won't hang on exit if there is a blocked foreign call outstanding.
348  *
349  ------------------------------------------------------------------------- */
350
351 static void
352 hs_exit_(rtsBool wait_foreign)
353 {
354     if (hs_init_count <= 0) {
355         errorBelch("warning: too many hs_exit()s");
356         return;
357     }
358     hs_init_count--;
359     if (hs_init_count > 0) {
360         // ignore until it's the last one
361         return;
362     }
363
364     /* start timing the shutdown */
365     stat_startExit();
366     
367     OnExitHook();
368
369 #if defined(THREADED_RTS)
370     ioManagerDie();
371 #endif
372
373     /* stop all running tasks */
374     exitScheduler(wait_foreign);
375
376     /* run C finalizers for all active weak pointers */
377     runAllCFinalizers(weak_ptr_list);
378     
379 #if defined(RTS_USER_SIGNALS)
380     if (RtsFlags.MiscFlags.install_signal_handlers) {
381         freeSignalHandlers();
382     }
383 #endif
384
385     /* stop the ticker */
386     stopTimer();
387     exitTimer();
388
389     /* reset the standard file descriptors to blocking mode */
390     resetNonBlockingFd(0);
391     resetNonBlockingFd(1);
392     resetNonBlockingFd(2);
393
394 #if HAVE_TERMIOS_H
395     // Reset the terminal settings on the standard file descriptors,
396     // if we changed them.  See System.Posix.Internals.tcSetAttr for
397     // more details, including the reason we termporarily disable
398     // SIGTTOU here.
399     { 
400         int fd;
401         sigset_t sigset, old_sigset;
402         sigemptyset(&sigset);
403         sigaddset(&sigset, SIGTTOU);
404         sigprocmask(SIG_BLOCK, &sigset, &old_sigset);
405         for (fd = 0; fd <= 2; fd++) {
406             struct termios* ts = (struct termios*)__hscore_get_saved_termios(fd);
407             if (ts != NULL) {
408                 tcsetattr(fd,TCSANOW,ts);
409             }
410         }
411         sigprocmask(SIG_SETMASK, &old_sigset, NULL);
412     }
413 #endif
414
415     // uninstall signal handlers
416     resetDefaultHandlers();
417
418     /* stop timing the shutdown, we're about to print stats */
419     stat_endExit();
420     
421     /* shutdown the hpc support (if needed) */
422     exitHpc();
423
424     // clean up things from the storage manager's point of view.
425     // also outputs the stats (+RTS -s) info.
426     exitStorage();
427     
428     /* free the tasks */
429     freeScheduler();
430
431     /* free shared Typeable store */
432     exitGlobalStore();
433
434     /* free file locking tables, if necessary */
435 #if !defined(mingw32_HOST_OS)    
436     freeFileLocking();
437 #endif
438
439     /* free the stable pointer table */
440     exitStablePtrTable();
441
442 #if defined(DEBUG)
443     /* free the thread label table */
444     freeThreadLabelTable();
445 #endif
446
447 #ifdef RTS_GTK_FRONTPANEL
448     if (RtsFlags.GcFlags.frontpanel) {
449         stopFrontPanel();
450     }
451 #endif
452
453 #if defined(PROFILING) 
454     reportCCSProfiling();
455 #endif
456
457     endProfiling();
458     freeProfiling1();
459
460 #ifdef PROFILING
461     // Originally, this was in report_ccs_profiling().  Now, retainer
462     // profiling might tack some extra stuff on to the end of this file
463     // during endProfiling().
464     if (prof_file != NULL) fclose(prof_file);
465 #endif
466
467 #ifdef EVENTLOG
468     if (RtsFlags.EventLogFlags.doEventLogging) {
469         endEventLogging();
470         freeEventLogging();
471     }
472 #endif
473
474 #if defined(TICKY_TICKY)
475     if (RtsFlags.TickyFlags.showTickyStats) PrintTickyInfo();
476 #endif
477
478 #if defined(mingw32_HOST_OS) && !defined(THREADED_RTS)
479     shutdownAsyncIO(wait_foreign);
480 #endif
481
482     /* free hash table storage */
483     exitHashTable();
484
485     // Finally, free all our storage
486     freeStorage();
487
488 #if defined(DEBUG)
489     /* and shut down the allocator debugging */
490     shutdownAllocator();
491 #endif
492
493 }
494
495 // The real hs_exit():
496 void
497 hs_exit(void)
498 {
499     hs_exit_(rtsTrue);
500     // be safe; this might be a DLL
501 }
502
503 // Compatibility interfaces
504 void
505 shutdownHaskell(void)
506 {
507     hs_exit();
508 }
509
510 void
511 shutdownHaskellAndExit(int n)
512 {
513     // we're about to exit(), no need to wait for foreign calls to return.
514     hs_exit_(rtsFalse);
515
516     if (hs_init_count == 0) {
517         stg_exit(n);
518     }
519 }
520
521 #ifndef mingw32_HOST_OS
522 void
523 shutdownHaskellAndSignal(int sig)
524 {
525     hs_exit_(rtsFalse);
526     kill(getpid(),sig);
527 }
528 #endif
529
530 /* 
531  * called from STG-land to exit the program
532  */
533
534 void (*exitFn)(int) = 0;
535
536 void  
537 stg_exit(int n)
538
539   if (exitFn)
540     (*exitFn)(n);
541   exit(n);
542 }