1 %/****************************************************************
3 %* This is where everything starts *
5 %****************************************************************/
8 #if defined(PROFILING) || defined(PAR) || defined(CONCURRENT)
9 #define NON_POSIX_SOURCE /* time things on Solaris -- sigh */
15 #if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
17 /* An ANSI string.h and pre-ANSI memory.h might conflict. */
18 # if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H)
20 # endif /* not STDC_HEADERS and HAVE_MEMORY_H */
22 #else /* not STDC_HEADERS and not HAVE_STRING_H */
24 /* memory.h and strings.h conflict on some systems. */
25 #endif /* not STDC_HEADERS and not HAVE_STRING_H */
27 #if defined(PROFILING) || defined(PAR)
28 /* need some "time" things */
30 /* ToDo: This is a mess! Improve ? */
32 # ifdef HAVE_SYS_TYPES_H
33 # include <sys/types.h>
36 # ifdef HAVE_SYS_TIMES_H
37 # include <sys/times.h>
40 # ifdef HAVE_SYS_TIME_H
41 # include <sys/time.h>
43 #endif /* PROFILING || PAR */
46 STGRegisterTable MainRegTable;
50 void shutdownHaskell(STG_NO_ARGS);
52 EXTFUN(startStgWorld);
53 extern void PrintTickyInfo(STG_NO_ARGS);
54 extern void checkAStack(STG_NO_ARGS);
56 /* a real nasty Global Variable */
57 /* moved to main/TopClosure(13)?.lc -- *one* of them will get linked in
58 P_ TopClosure = Main_mainPrimIO_closure;
61 /* structure to carry around info about the storage manager */
62 smInfo StorageMgrInfo;
65 extern I_ OkToGC, buckets;
66 extern rtsBool TraceSparks, DelaySparks,
69 extern void RunParallelSystem PROTO((P_));
70 extern void initParallelSystem(STG_NO_ARGS);
71 extern void SynchroniseSystem(STG_NO_ARGS);
73 extern void SetTrace PROTO((W_ address, I_ level/*?*/));
76 #if defined(GRAN_CHECK) && defined(GRAN)
78 extern W_ event_trace ;
79 extern W_ event_trace_all ;
82 extern void *stgAllocForGMP PROTO((size_t));
83 extern void *stgReallocForGMP PROTO ((void *, size_t, size_t));
84 extern void stgDeallocForGMP PROTO ((void *, size_t));
86 /* NeXTs can't just reach out and touch "end", to use in
87 distinguishing things in static vs dynamic (malloc'd) memory.
89 #if nextstep2_TARGET_OS || nextstep3_TARGET_OS /* ToDo: use END_BY_FUNNY_MEANS or something */
93 int prog_argc; /* an "int" so as to match normal "argc" */
95 int rts_argc; /* ditto */
96 char *rts_argv[MAX_RTS_ARGS];
99 jmp_buf restart_main; /* For restarting after a signal */
103 unsigned nPEs = 0, nIMUs = 0;
110 int /* return type of "main" is defined by the C standard */
111 main(int argc, char *argv[])
115 The very first thing we do is grab the start time...just in case we're
116 collecting timing statistics.
122 The parallel system needs to be initialised and synchronised before
123 the program is run. This is done {\em before} heap allocation, so we
124 can grab all remaining heap without needing to consider the System
125 Manager's requirements.
130 * Grab the number of PEs out of the argument vector, and
131 * eliminate it from further argument processing.
133 nPEs = atoi(argv[1]);
141 #if defined(PROFILING) || defined(PAR)
142 /* setup string indicating time of run -- only used for profiling */
146 #if nextstep2_TARGET_OS || nextstep3_TARGET_OS /* ToDo: use END_BY_FUNNY_MEANS or something */
147 get_end_result = get_end();
151 divide the command-line args between pgm and RTS; figure out
152 what statsfile to use (if any); [if so, write the whole
155 This is unlikely to work well in parallel! KH.
157 initRtsFlagsDefaults();
158 defaultsHook(); /* the one supplied does nothing;
159 the user may have supplied a more interesting one.
162 setupRtsFlags(&argc, argv, &rts_argc, rts_argv);
167 /* Initialise the parallel system -- before initHeap! */
168 initParallelSystem();
171 #if defined(PROFILING) || defined(PAR)
172 if (init_cc_profiling(rts_argc, rts_argv, prog_argv) != 0) {
174 fprintf(stderr, "init_cc_profiling failed!\n");
179 #if defined(CONCURRENT) && defined(GRAN)
181 if (init_gr_simulation(rts_argc, rts_argv, prog_argc, prog_argv) != 0) {
182 fprintf(stderr, "init_gr_simulation failed!\n"); EXIT(EXIT_FAILURE);
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 # if defined(GRAN) /* HWL */
269 /* RunnableThreadsHd etc. are init in ScheduleThreads */
271 * I'm not sure about this. Note that this code is for re-initializing
272 * things when a longjmp to restart_main occurs. --JSM
276 AvailableStack = AvailableTSO = Nil_closure;
277 RunnableThreadsHd = RunnableThreadsTl = Nil_closure;
278 WaitingThreadsHd = WaitingThreadsTl = Nil_closure;
279 PendingSparksHd[REQUIRED_POOL] =
280 PendingSparksTl[REQUIRED_POOL] = PendingSparksBase[REQUIRED_POOL];
281 PendingSparksHd[ADVISORY_POOL] =
282 PendingSparksTl[ADVISORY_POOL] = PendingSparksBase[ADVISORY_POOL];
285 CurrentTSO = Nil_closure;
288 RunParallelSystem(TopClosure);
290 STKO_LINK(MainStkO) = Nil_closure;
291 ScheduleThreads(TopClosure);
294 #else /* not threaded (sequential) */
296 miniInterpret((StgFunPtr)startStgWorld);
298 #endif /* !CONCURRENT */
301 return(EXIT_SUCCESS); /* don't use EXIT! :-) */
305 It should be possible to call @shutdownHaskell@ whenever you want to
306 shut a Haskell program down in an orderly way.
308 Note that some of this code probably depends on the integrity of
309 various internal data structures so this should not be called in
310 response to detecting a catastrophic error.
314 shutdownHaskell(STG_NO_ARGS)
318 if (! exitSM(&StorageMgrInfo)) {
320 fprintf(stderr, "exitSM failed!\n");
324 #if defined(PROFILING)
325 heap_profile_finish();
327 #if defined(PROFILING) || defined(PAR)
328 report_cc_profiling(1 /* final */ );
331 #if defined(TICKY_TICKY)
332 if (RTSflags.TickyFlags.showTickyStats) PrintTickyInfo();
335 #if defined(GRAN_CHECK) && defined(GRAN)
336 if (PrintFetchMisses)
337 fprintf(stderr,"Number of fetch misses: %d\n",fetch_misses);
340 fprintf(stderr,"COUNT statistics:\n");
341 fprintf(stderr," Total number of updates: %u\n",nUPDs);
342 fprintf(stderr," Needed to awaken BQ: %u with avg BQ len of: %f\n",
343 nUPDs_BQ,(float)BQ_lens/(float)nUPDs_BQ);
344 fprintf(stderr," Number of PAPs: %u\n",nPAPs);
352 /* This fflush is important, because: if "main" just returns,
353 then we will end up in pre-supplied exit code that will close
354 streams and flush buffers. In particular we have seen: it
355 will close fd 0 (stdin), then flush fd 1 (stdout), then <who
358 But if you're playing with sockets, that "close fd 0" might
359 suggest to the daemon that all is over, only to be presented
360 with more stuff on "fd 1" at the flush.
362 The fflush avoids this sad possibility.
367 Sets up and returns a string indicating the date/time of the run.
368 Successive calls simply return the same string again. Initially
369 called by @main.lc@ to initialise the string at the start of the run.
370 Only used for profiling.
373 #if defined(PROFILING) || defined(CONCURRENT)
377 time_str(STG_NO_ARGS)
379 static time_t now = 0;
380 static char nowstr[26];
384 strcpy(nowstr, ctime(&now));
385 strcpy(nowstr+16,nowstr+19);
390 #endif /* profiling */
393 ToDo: Will this work under threads?
396 StgStablePtr errorHandler = -1; /* NB: prone to magic-value-ery (WDP 95/12) */
399 getErrorHandler(STG_NO_ARGS)
401 return (StgInt) errorHandler;
407 raiseError( handler )
408 StgStablePtr handler;
410 if (handler == -1) { /* beautiful magic value... (WDP 95/12) */
414 TopClosure = deRefStablePointer( handler );
415 longjmp(restart_main,1);
422 catchError( newErrorHandler )
423 StgStablePtr newErrorHandler;
425 StgStablePtr oldErrorHandler = errorHandler;
426 errorHandler = newErrorHandler;
427 return oldErrorHandler;
433 If we have installed an error handler, we might want to
434 indicate that we have successfully recovered from an error by
435 decrementing the counter.
439 decrementErrorCount()
441 ErrorIO_call_count-=1;