whitespace
[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 "Timer.h"      /* startTimer, stopTimer */
23 #include "Weak.h"
24 #include "Ticky.h"
25 #include "StgRun.h"
26 #include "Prelude.h"            /* fixupRTStoPreludeRefs */
27 #include "HsFFI.h"
28 #include "Linker.h"
29 #include "ThreadLabels.h"
30 #include "BlockAlloc.h"
31 #include "Trace.h"
32 #include "RtsTypeable.h"
33 #include "Stable.h"
34 #include "Hpc.h"
35
36 #if defined(RTS_GTK_FRONTPANEL)
37 #include "FrontPanel.h"
38 #endif
39
40 #if defined(PROFILING) || defined(DEBUG)
41 # include "Profiling.h"
42 # include "ProfHeap.h"
43 # include "RetainerProfile.h"
44 #endif
45
46 #if defined(GRAN)
47 # include "GranSimRts.h"
48 #endif
49
50 #if defined(GRAN) || defined(PAR)
51 # include "ParallelRts.h"
52 #endif
53
54 #if defined(PAR)
55 # include "Parallel.h"
56 # include "LLC.h"
57 #endif
58
59 #if defined(mingw32_HOST_OS)
60 #include "win32/AsyncIO.h"
61 #endif
62
63 #include <stdlib.h>
64
65 #ifdef HAVE_TERMIOS_H
66 #include <termios.h>
67 #endif
68 #ifdef HAVE_SIGNAL_H
69 #include <signal.h>
70 #endif
71
72 #if USE_PAPI
73 #include "Papi.h"
74 #endif
75
76 // Count of how many outstanding hs_init()s there have been.
77 static int hs_init_count = 0;
78
79 // Here we save the terminal settings on the standard file
80 // descriptors, if we need to change them (eg. to support NoBuffering
81 // input).
82 static void *saved_termios[3] = {NULL,NULL,NULL};
83
84 void*
85 __hscore_get_saved_termios(int fd)
86 {
87   return (0 <= fd && fd < (int)(sizeof(saved_termios) / sizeof(*saved_termios))) ?
88     saved_termios[fd] : NULL;
89 }
90
91 void
92 __hscore_set_saved_termios(int fd, void* ts)
93 {
94   if (0 <= fd && fd < (int)(sizeof(saved_termios) / sizeof(*saved_termios))) {
95     saved_termios[fd] = ts;
96   }
97 }
98
99 /* -----------------------------------------------------------------------------
100    Initialise floating point unit on x86 (currently disabled. why?)
101    (see comment in ghc/compiler/nativeGen/MachInstrs.lhs).
102    -------------------------------------------------------------------------- */
103
104 #define X86_INIT_FPU 0
105
106 #if X86_INIT_FPU
107 static void
108 x86_init_fpu ( void )
109 {
110   __volatile unsigned short int fpu_cw;
111
112   // Grab the control word
113   __asm __volatile ("fnstcw %0" : "=m" (fpu_cw));
114
115 #if 0
116   printf("fpu_cw: %x\n", fpu_cw);
117 #endif
118
119   // Set bits 8-9 to 10 (64-bit precision).
120   fpu_cw = (fpu_cw & 0xfcff) | 0x0200;
121
122   // Store the new control word back
123   __asm __volatile ("fldcw %0" : : "m" (fpu_cw));
124 }
125 #endif
126
127 /* -----------------------------------------------------------------------------
128    Starting up the RTS
129    -------------------------------------------------------------------------- */
130
131 void
132 hs_init(int *argc, char **argv[])
133 {
134     hs_init_count++;
135     if (hs_init_count > 1) {
136         // second and subsequent inits are ignored
137         return;
138     }
139
140     /* The very first thing we do is grab the start time...just in case we're
141      * collecting timing statistics.
142      */
143     stat_startInit();
144
145 #ifdef PAR
146     /*
147      * The parallel system needs to be initialised and synchronised before
148      * the program is run.  
149      */ 
150     startupParallelSystem(argv);
151      
152     if (*argv[0] == '-') { /* Strip off mainPE flag argument */
153       argv++; 
154       argc--;                   
155     }
156
157     argv[1] = argv[0];   /* ignore the nPEs argument */
158     argv++; argc--;
159 #endif
160
161     /* Initialise the performance tracking library */
162 #ifdef USE_PAPI
163     {
164         int ver;
165         if ((ver = PAPI_library_init(PAPI_VER_CURRENT)) != PAPI_VER_CURRENT) {
166             if (ver > 0) {
167                 errorBelch("PAPI_library_init: wrong version: %x", ver);
168                 stg_exit(EXIT_FAILURE);
169             } else {
170                 sysErrorBelch("PAPI_library_init");
171                 stg_exit(EXIT_FAILURE);
172             }
173         }
174     }
175 #ifdef THREADED_RTS
176     {
177         int err;
178         if ((err = PAPI_thread_init(osThreadId)) < 0) {
179             barf("PAPI_thread_init: %d",err);
180         }
181     }
182 #endif
183 #endif
184
185     /* Set the RTS flags to default values. */
186
187     initRtsFlagsDefaults();
188
189     /* Call the user hook to reset defaults, if present */
190     defaultsHook();
191
192     /* Parse the flags, separating the RTS flags from the programs args */
193     if (argc != NULL && argv != NULL) {
194         setupRtsFlags(argc, *argv, &rts_argc, rts_argv);
195         setProgArgv(*argc,*argv);
196     }
197
198     /* initTracing must be after setupRtsFlags() */
199     initTracing();
200
201 #if defined(PAR)
202     /* NB: this really must be done after processing the RTS flags */
203     IF_PAR_DEBUG(verbose,
204                  debugBelch("==== Synchronising system (%d PEs)\n", nPEs));
205     synchroniseSystem();             // calls initParallelSystem etc
206 #endif  /* PAR */
207
208     /* Perform initialisation of adjustor thunk layer. */
209     initAdjustor();
210
211     /* initialise scheduler data structures (needs to be done before
212      * initStorage()).
213      */
214     initScheduler();
215
216 #if defined(GRAN)
217     /* And start GranSim profiling if required: */
218     if (RtsFlags.GranFlags.GranSimStats.Full)
219       init_gr_simulation(rts_argc, rts_argv, prog_argc, prog_argv);
220 #elif defined(PAR)
221     /* And start GUM profiling if required: */
222     if (RtsFlags.ParFlags.ParStats.Full)
223       init_gr_simulation(rts_argc, rts_argv, prog_argc, prog_argv);
224 #endif  /* PAR || GRAN */
225
226     /* initialize the storage manager */
227     initStorage();
228
229     /* initialise the stable pointer table */
230     initStablePtrTable();
231
232     /* initialise the shared Typeable store */
233     initTypeableStore();
234
235 #if defined(DEBUG)
236     /* initialise thread label table (tso->char*) */
237     initThreadLabelTable();
238 #endif
239
240 #if defined(PROFILING) || defined(DEBUG)
241     initProfiling1();
242 #endif
243
244     /* start the virtual timer 'subsystem'. */
245     startTimer();
246
247     /* Initialise the stats department */
248     initStats();
249
250 #if defined(RTS_USER_SIGNALS)
251     /* Initialise the user signal handler set */
252     initUserSignals();
253     /* Set up handler to run on SIGINT, etc. */
254     initDefaultHandlers();
255 #endif
256  
257 #if defined(mingw32_HOST_OS)
258     startupAsyncIO();
259 #endif
260
261 #ifdef RTS_GTK_FRONTPANEL
262     if (RtsFlags.GcFlags.frontpanel) {
263         initFrontPanel();
264     }
265 #endif
266
267 #if X86_INIT_FPU
268     x86_init_fpu();
269 #endif
270
271 #if defined(THREADED_RTS) && !defined(mingw32_HOST_OS)
272     ioManagerStart();
273 #endif
274
275     /* Record initialization times */
276     stat_endInit();
277 }
278
279 // Compatibility interface
280 void
281 startupHaskell(int argc, char *argv[], void (*init_root)(void))
282 {
283     hs_init(&argc, &argv);
284     if(init_root)
285         hs_add_root(init_root);
286 }
287
288
289 /* -----------------------------------------------------------------------------
290    Per-module initialisation
291
292    This process traverses all the compiled modules in the program
293    starting with "Main", and performing per-module initialisation for
294    each one.
295
296    So far, two things happen at initialisation time:
297
298       - we register stable names for each foreign-exported function
299         in that module.  This prevents foreign-exported entities, and
300         things they depend on, from being garbage collected.
301
302       - we supply a unique integer to each statically declared cost
303         centre and cost centre stack in the program.
304
305    The code generator inserts a small function "__stginit_<module>" in each
306    module and calls the registration functions in each of the modules it
307    imports.
308
309    The init* functions are compiled in the same way as STG code,
310    i.e. without normal C call/return conventions.  Hence we must use
311    StgRun to call this stuff.
312    -------------------------------------------------------------------------- */
313
314 /* The init functions use an explicit stack... 
315  */
316 #define INIT_STACK_BLOCKS  4
317 static F_ *init_stack = NULL;
318
319 void
320 hs_add_root(void (*init_root)(void))
321 {
322     bdescr *bd;
323     nat init_sp;
324     Capability *cap = &MainCapability;
325
326     if (hs_init_count <= 0) {
327         barf("hs_add_root() must be called after hs_init()");
328     }
329
330     /* The initialisation stack grows downward, with sp pointing 
331        to the last occupied word */
332     init_sp = INIT_STACK_BLOCKS*BLOCK_SIZE_W;
333     bd = allocGroup_lock(INIT_STACK_BLOCKS);
334     init_stack = (F_ *)bd->start;
335     init_stack[--init_sp] = (F_)stg_init_finish;
336     if (init_root != NULL) {
337         init_stack[--init_sp] = (F_)init_root;
338     }
339     
340     cap->r.rSp = (P_)(init_stack + init_sp);
341     StgRun((StgFunPtr)stg_init, &cap->r);
342
343     freeGroup_lock(bd);
344
345     startupHpc();
346
347 #if defined(PROFILING) || defined(DEBUG)
348     // This must be done after module initialisation.
349     // ToDo: make this work in the presence of multiple hs_add_root()s.
350     initProfiling2();
351 #endif
352 }
353
354 /* -----------------------------------------------------------------------------
355    Shutting down the RTS
356    -------------------------------------------------------------------------- */
357
358 void
359 hs_exit(void)
360 {
361     if (hs_init_count <= 0) {
362         errorBelch("warning: too many hs_exit()s");
363         return;
364     }
365     hs_init_count--;
366     if (hs_init_count > 0) {
367         // ignore until it's the last one
368         return;
369     }
370
371     /* start timing the shutdown */
372     stat_startExit();
373     
374 #if defined(THREADED_RTS) && !defined(mingw32_HOST_OS)
375     ioManagerDie();
376 #endif
377
378     /* stop all running tasks */
379     exitScheduler();
380     
381 #if defined(GRAN)
382     /* end_gr_simulation prints global stats if requested -- HWL */
383     if (!RtsFlags.GranFlags.GranSimStats.Suppressed)
384         end_gr_simulation();
385 #endif
386     
387     /* stop the ticker */
388     stopTimer();
389     
390     /* reset the standard file descriptors to blocking mode */
391     resetNonBlockingFd(0);
392     resetNonBlockingFd(1);
393     resetNonBlockingFd(2);
394
395 #if HAVE_TERMIOS_H
396     // Reset the terminal settings on the standard file descriptors,
397     // if we changed them.  See System.Posix.Internals.tcSetAttr for
398     // more details, including the reason we termporarily disable
399     // SIGTTOU here.
400     { 
401         int fd;
402         sigset_t sigset, old_sigset;
403         sigemptyset(&sigset);
404         sigaddset(&sigset, SIGTTOU);
405         sigprocmask(SIG_BLOCK, &sigset, &old_sigset);
406         for (fd = 0; fd <= 2; fd++) {
407             struct termios* ts = (struct termios*)__hscore_get_saved_termios(fd);
408             if (ts != NULL) {
409                 tcsetattr(fd,TCSANOW,ts);
410             }
411         }
412         sigprocmask(SIG_SETMASK, &old_sigset, NULL);
413     }
414 #endif
415
416 #if defined(PAR)
417     /* controlled exit; good thread! */
418     shutdownParallelSystem(0);
419     
420     /* global statistics in parallel system */
421     PAR_TICKY_PAR_END();
422 #endif
423
424     /* stop timing the shutdown, we're about to print stats */
425     stat_endExit();
426     
427     /* shutdown the hpc support (if needed) */
428     exitHpc();
429
430     // clean up things from the storage manager's point of view.
431     // also outputs the stats (+RTS -s) info.
432     exitStorage();
433     
434     /* free shared Typeable store */
435     exitTypeableStore();
436
437     /* initialise the stable pointer table */
438     exitStablePtrTable();
439
440     /* free hash table storage */
441     exitHashTable();
442
443 #ifdef RTS_GTK_FRONTPANEL
444     if (RtsFlags.GcFlags.frontpanel) {
445         stopFrontPanel();
446     }
447 #endif
448
449 #if defined(PROFILING) 
450     reportCCSProfiling();
451 #endif
452
453 #if defined(PROFILING) || defined(DEBUG)
454     endProfiling();
455 #endif
456
457 #ifdef PROFILING
458     // Originally, this was in report_ccs_profiling().  Now, retainer
459     // profiling might tack some extra stuff on to the end of this file
460     // during endProfiling().
461     fclose(prof_file);
462 #endif
463
464 #if defined(TICKY_TICKY)
465     if (RtsFlags.TickyFlags.showTickyStats) PrintTickyInfo();
466 #endif
467
468 #if defined(mingw32_HOST_OS)
469     shutdownAsyncIO();
470 #endif
471
472     // Finally, free all our storage.
473     freeStorage();
474 }
475
476 // Compatibility interfaces
477 void
478 shutdownHaskell(void)
479 {
480     hs_exit();
481 }
482
483 void
484 shutdownHaskellAndExit(int n)
485 {
486     if (hs_init_count == 1) {
487         OnExitHook();
488         hs_exit();
489 #if defined(PAR)
490         /* really exit (stg_exit() would call shutdownParallelSystem() again) */
491         exit(n);
492 #else
493         stg_exit(n);
494 #endif
495     }
496 }
497
498 /* 
499  * called from STG-land to exit the program
500  */
501
502 #ifdef PAR
503 static int exit_started=rtsFalse;
504 #endif
505
506 void (*exitFn)(int) = 0;
507
508 void  
509 stg_exit(int n)
510
511 #ifdef PAR
512   /* HACK: avoid a loop when exiting due to a stupid error */
513   if (exit_started) 
514     return;
515   exit_started=rtsTrue;
516
517   IF_PAR_DEBUG(verbose, debugBelch("==-- stg_exit %d on [%x]...", n, mytid));
518   shutdownParallelSystem(n);
519 #endif
520   if (exitFn)
521     (*exitFn)(n);
522   exit(n);
523 }