1 %/****************************************************************
3 %* This is where everything starts *
5 %****************************************************************/
8 #if defined(PROFILING) || defined(PAR) || defined(CONCURRENT)
10 #define NON_POSIX_SOURCE /* time things on Solaris -- sigh */
17 #if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
19 /* An ANSI string.h and pre-ANSI memory.h might conflict. */
20 # if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H)
22 # endif /* not STDC_HEADERS and HAVE_MEMORY_H */
24 #else /* not STDC_HEADERS and not HAVE_STRING_H */
26 /* memory.h and strings.h conflict on some systems. */
27 #endif /* not STDC_HEADERS and not HAVE_STRING_H */
29 #if defined(PROFILING) || defined(PAR) || defined(GRAN)
30 /* need some "time" things */
32 /* ToDo: This is a mess! Improve ? */
34 # ifdef HAVE_SYS_TYPES_H
35 # include <sys/types.h>
38 # ifdef HAVE_SYS_TIMES_H
39 # include <sys/times.h>
42 # ifdef HAVE_SYS_TIME_H
43 # include <sys/time.h>
45 #endif /* PROFILING || PAR */
48 STGRegisterTable MainRegTable;
52 void shutdownHaskell(STG_NO_ARGS);
54 EXTFUN(startStgWorld);
55 extern void PrintTickyInfo(STG_NO_ARGS);
56 extern void checkAStack(STG_NO_ARGS);
58 /* a real nasty Global Variable */
59 /* moved to main/TopClosure(13)?.lc -- *one* of them will get linked in
60 P_ TopClosure = GHCmain_mainPrimIO_closure;
63 /* structure to carry around info about the storage manager */
64 smInfo StorageMgrInfo;
67 extern I_ OkToGC, buckets;
68 extern rtsBool TraceSparks, DelaySparks,
71 void RunParallelSystem PROTO((P_));
72 void initParallelSystem(STG_NO_ARGS);
73 void SynchroniseSystem(STG_NO_ARGS);
75 void SetTrace PROTO((W_ address, I_ level/*?*/));
78 void *stgAllocForGMP PROTO((size_t));
79 void *stgReallocForGMP PROTO ((void *, size_t, size_t));
80 void stgDeallocForGMP PROTO ((void *, size_t));
82 /* NeXTs can't just reach out and touch "end", to use in
83 distinguishing things in static vs dynamic (malloc'd) memory.
85 #if nextstep2_TARGET_OS || nextstep3_TARGET_OS /* ToDo: use END_BY_FUNNY_MEANS or something */
89 int prog_argc; /* an "int" so as to match normal "argc" */
91 int rts_argc; /* ditto */
92 char *rts_argv[MAX_RTS_ARGS];
95 jmp_buf restart_main; /* For restarting after a signal */
99 int nPEs = 0; /* Number of PEs */
102 int /* return type of "main" is defined by the C standard */
103 main(int argc, char *argv[])
110 The very first thing we do is grab the start time...just in case we're
111 collecting timing statistics.
117 The parallel system needs to be initialised and synchronised before
118 the program is run. This is done {\em before} heap allocation, so we
119 can grab all remaining heap without needing to consider the System
120 Manager's requirements.
124 if (*argv[0] == '-') { /* Look to see whether we're the Main Thread */
125 IAmMainThread = rtsTrue;
126 argv++; argc--; /* Strip off flag argument */
127 /* fprintf(stderr, "I am Main Thread\n"); */
130 * Grab the number of PEs out of the argument vector, and
131 * eliminate it from further argument processing.
133 nPEs = atoi(argv[1]);
136 initEachPEHook(); /* HWL: hook to be execed on each PE */
140 #if defined(PROFILING) || defined(PAR) || defined(GRAN)
141 /* setup string indicating time of run -- only used for profiling */
145 #if nextstep2_TARGET_OS || nextstep3_TARGET_OS /* ToDo: use END_BY_FUNNY_MEANS or something */
146 get_end_result = get_end();
150 divide the command-line args between pgm and RTS; figure out
151 what statsfile to use (if any); [if so, write the whole
154 This is unlikely to work well in parallel! KH.
156 initRtsFlagsDefaults();
157 defaultsHook(); /* the one supplied does nothing;
158 the user may have supplied a more interesting one.
161 setupRtsFlags(&argc, argv, &rts_argc, rts_argv);
166 /* Initialise the parallel system -- before initHeap! */
167 initParallelSystem();
170 #if defined(PROFILING) || defined(PAR)
171 if (init_cc_profiling(rts_argc, rts_argv, prog_argv) != 0) {
173 fprintf(stderr, "init_cc_profiling failed!\n");
179 if (!RTSflags.GranFlags.granSimStats_suppressed)
180 if (init_gr_simulation(rts_argc, rts_argv, prog_argc, prog_argv) != 0) {
181 fprintf(stderr, "init_gr_simulation failed!\n");
187 if (RTSflags.ParFlags.granSimStats)
188 init_gr_profiling(rts_argc, rts_argv, prog_argc, prog_argv);
191 /* initialize the storage manager */
195 if (! initStacks( &StorageMgrInfo )) {
197 fprintf(stderr, "initStacks failed!\n");
202 if (! initHeap( &StorageMgrInfo )) {
204 fprintf(stderr, "initHeap failed!\n");
208 #if defined(CONCURRENT) && !defined(GRAN)
209 if (!initThreadPools()) {
211 fprintf(stderr, "initThreadPools failed!\n");
216 #if defined(PROFILING) || defined(PAR)
217 /* call cost centre registering routine (after heap allocated) */
221 #if defined(TICKY_TICKY)
222 max_SpA = MAIN_SpA; /* initial high-water marks */
226 /* Tell GNU multi-precision pkg about our custom alloc functions */
227 mp_set_memory_functions(stgAllocForGMP, stgReallocForGMP, stgDeallocForGMP);
229 /* Record initialization times */
232 #if defined(PROFILING) || defined(CONCURRENT)
234 * Both the context-switcher and the cost-center profiler use
237 if (install_vtalrm_handler()) {
239 fprintf(stderr, "Can't install VTALRM handler.\n");
242 #if (defined(CONCURRENT) && defined(PROFILING)) || defined(PAR)
243 if (! time_profiling)
244 RTSflags.CcFlags.msecsPerTick = RTSflags.ConcFlags.ctxtSwitchTime;
246 if (RTSflags.ConcFlags.ctxtSwitchTime % (1000/TICK_FREQUENCY) == 0)
247 RTSflags.CcFlags.msecsPerTick = TICK_MILLISECS;
249 RTSflags.CcFlags.msecsPerTick = CS_MIN_MILLISECS;
251 RTSflags.CcFlags.ctxtSwitchTicks = RTSflags.ConcFlags.ctxtSwitchTime / RTSflags.CcFlags.msecsPerTick;
252 RTSflags.CcFlags.profilerTicks = TICK_MILLISECS / RTSflags.CcFlags.msecsPerTick;
260 #endif /* PROFILING || CONCURRENT */
263 setjmp(restart_main);
268 AvailableStack = AvailableTSO = PrelBase_Z91Z93_closure;
269 # if defined(GRAN) /* HWL */
270 /* Moved in here from ScheduleThreads, to handle a restart_main
271 (because of a signal) properly. */
272 for (i=0; i<RTSflags.GranFlags.proc; i++)
274 RunnableThreadsHd[i] = RunnableThreadsTl[i] = PrelBase_Z91Z93_closure;
275 WaitThreadsHd[i] = WaitThreadsTl[i] = PrelBase_Z91Z93_closure;
276 PendingSparksHd[i][REQUIRED_POOL] = PendingSparksHd[i][ADVISORY_POOL] =
277 PendingSparksTl[i][REQUIRED_POOL] = PendingSparksTl[i][ADVISORY_POOL] =
281 RunnableThreadsHd = RunnableThreadsTl = PrelBase_Z91Z93_closure;
282 WaitingThreadsHd = WaitingThreadsTl = PrelBase_Z91Z93_closure;
283 PendingSparksHd[REQUIRED_POOL] =
284 PendingSparksTl[REQUIRED_POOL] = PendingSparksBase[REQUIRED_POOL];
285 PendingSparksHd[ADVISORY_POOL] =
286 PendingSparksTl[ADVISORY_POOL] = PendingSparksBase[ADVISORY_POOL];
289 CurrentTSO = PrelBase_Z91Z93_closure;
292 RunParallelSystem(TopClosure);
294 STKO_LINK(MainStkO) = PrelBase_Z91Z93_closure;
295 ScheduleThreads(TopClosure);
298 #else /* not threaded (sequential) */
300 miniInterpret((StgFunPtr)startStgWorld);
302 #endif /* !CONCURRENT */
305 return(EXIT_SUCCESS); /* don't use EXIT! :-) */
309 It should be possible to call @shutdownHaskell@ whenever you want to
310 shut a Haskell program down in an orderly way.
312 Note that some of this code probably depends on the integrity of
313 various internal data structures so this should not be called in
314 response to detecting a catastrophic error.
318 shutdownHaskell(STG_NO_ARGS)
323 /* For some reason this must be before exitSM */
324 if (!RTSflags.GranFlags.granSimStats_suppressed)
328 if (! exitSM(&StorageMgrInfo) ) {
330 fprintf(stderr, "exitSM failed!\n");
334 #if defined(PROFILING)
335 heap_profile_finish();
337 #if defined(PROFILING) || defined(PAR)
338 report_cc_profiling(1 /* final */ );
341 #if defined(TICKY_TICKY)
342 if (RTSflags.TickyFlags.showTickyStats) PrintTickyInfo();
345 /* Give the application a chance to do something sensible
351 /* This fflush is important, because: if "main" just returns,
352 then we will end up in pre-supplied exit code that will close
353 streams and flush buffers. In particular we have seen: it
354 will close fd 0 (stdin), then flush fd 1 (stdout), then <who
357 But if you're playing with sockets, that "close fd 0" might
358 suggest to the daemon that all is over, only to be presented
359 with more stuff on "fd 1" at the flush.
361 The fflush avoids this sad possibility.
366 Sets up and returns a string indicating the date/time of the run.
367 Successive calls simply return the same string again. Initially
368 called by @main.lc@ to initialise the string at the start of the run.
369 Only used for profiling.
372 #if defined(PROFILING) || defined(CONCURRENT) || defined(GRAN)
376 time_str(STG_NO_ARGS)
378 static time_t now = 0;
379 static char nowstr[26];
383 strcpy(nowstr, ctime(&now));
384 strcpy(nowstr+16,nowstr+19);
389 #endif /* profiling */
392 ToDo: Will this work under threads?
395 StgStablePtr errorHandler = -1; /* NB: prone to magic-value-ery (WDP 95/12) */
398 getErrorHandler(STG_NO_ARGS)
400 return (StgInt) errorHandler;
406 raiseError( handler )
407 StgStablePtr handler;
409 if (handler == -1) { /* beautiful magic value... (WDP 95/12) */
413 TopClosure = deRefStablePointer( handler );
414 longjmp(restart_main,1);
421 catchError( newErrorHandler )
422 StgStablePtr newErrorHandler;
424 StgStablePtr oldErrorHandler = errorHandler;
425 errorHandler = newErrorHandler;
426 return oldErrorHandler;
432 If we have installed an error handler, we might want to
433 indicate that we have successfully recovered from an error by
434 decrementing the counter.
438 decrementErrorCount()
440 ErrorIO_call_count-=1;