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