Default to infinite stack size (#8189)
[ghc.git] / rts / RtsFlags.c
1 /* -----------------------------------------------------------------------------
2 *
3 * (c) The AQUA Project, Glasgow University, 1994-1997
4 * (c) The GHC Team, 1998-2006
5 *
6 * Functions for parsing the argument list.
7 *
8 * ---------------------------------------------------------------------------*/
9
10 #include "PosixSource.h"
11 #include "Rts.h"
12
13 #include "RtsUtils.h"
14 #include "Profiling.h"
15 #include "RtsFlags.h"
16
17 #ifdef HAVE_CTYPE_H
18 #include <ctype.h>
19 #endif
20
21 #include <string.h>
22
23 #ifdef HAVE_UNISTD_H
24 #include <unistd.h>
25 #endif
26
27 #ifdef HAVE_SYS_TYPES_H
28 #include <sys/types.h>
29 #endif
30
31 // Flag Structure
32 RTS_FLAGS RtsFlags;
33
34 /*
35 * Split argument lists
36 */
37 int prog_argc = 0; /* an "int" so as to match normal "argc" */
38 char **prog_argv = NULL;
39 int full_prog_argc = 0; /* an "int" so as to match normal "argc" */
40 char **full_prog_argv = NULL;
41 char *prog_name = NULL; /* 'basename' of prog_argv[0] */
42 int rts_argc = 0; /* ditto */
43 char **rts_argv = NULL;
44 int rts_argv_size = 0;
45 #if defined(mingw32_HOST_OS)
46 // On Windows, we want to use GetCommandLineW rather than argc/argv,
47 // but we need to mutate the command line arguments for withProgName and
48 // friends. The System.Environment module achieves that using this bit of
49 // shared state:
50 int win32_prog_argc = 0;
51 wchar_t **win32_prog_argv = NULL;
52 #endif
53
54 /*
55 * constants, used later
56 */
57 #define RTS 1
58 #define PGM 0
59
60 /* -----------------------------------------------------------------------------
61 Static function decls
62 -------------------------------------------------------------------------- */
63
64 static void procRtsOpts (int rts_argc0, RtsOptsEnabledEnum enabled);
65
66 static void normaliseRtsOpts (void);
67
68 static void initStatsFile (FILE *f);
69
70 static int openStatsFile (char *filename, const char *FILENAME_FMT,
71 FILE **file_ret);
72
73 static StgWord64 decodeSize (const char *flag, nat offset,
74 StgWord64 min, StgWord64 max);
75
76 static void bad_option (const char *s);
77
78 #ifdef TRACING
79 static void read_trace_flags(char *arg);
80 #endif
81
82 static void errorUsage (void) GNU_ATTRIBUTE(__noreturn__);
83
84 static char * copyArg (char *arg);
85 static char ** copyArgv (int argc, char *argv[]);
86 static void freeArgv (int argc, char *argv[]);
87
88 /* -----------------------------------------------------------------------------
89 * Command-line option parsing routines.
90 * ---------------------------------------------------------------------------*/
91
92 void initRtsFlagsDefaults(void)
93 {
94 RtsFlags.GcFlags.statsFile = NULL;
95 RtsFlags.GcFlags.giveStats = NO_GC_STATS;
96
97 RtsFlags.GcFlags.maxStkSize = 0; /* off by default */
98 RtsFlags.GcFlags.initialStkSize = 1024 / sizeof(W_);
99 RtsFlags.GcFlags.stkChunkSize = (32 * 1024) / sizeof(W_);
100 RtsFlags.GcFlags.stkChunkBufferSize = (1 * 1024) / sizeof(W_);
101
102 RtsFlags.GcFlags.minAllocAreaSize = (512 * 1024) / BLOCK_SIZE;
103 RtsFlags.GcFlags.minOldGenSize = (1024 * 1024) / BLOCK_SIZE;
104 RtsFlags.GcFlags.maxHeapSize = 0; /* off by default */
105 RtsFlags.GcFlags.heapSizeSuggestion = 0; /* none */
106 RtsFlags.GcFlags.heapSizeSuggestionAuto = rtsFalse;
107 RtsFlags.GcFlags.pcFreeHeap = 3; /* 3% */
108 RtsFlags.GcFlags.oldGenFactor = 2;
109 RtsFlags.GcFlags.generations = 2;
110 RtsFlags.GcFlags.squeezeUpdFrames = rtsTrue;
111 RtsFlags.GcFlags.compact = rtsFalse;
112 RtsFlags.GcFlags.compactThreshold = 30.0;
113 RtsFlags.GcFlags.sweep = rtsFalse;
114 RtsFlags.GcFlags.idleGCDelayTime = USToTime(300000); // 300ms
115 #ifdef THREADED_RTS
116 RtsFlags.GcFlags.doIdleGC = rtsTrue;
117 #else
118 RtsFlags.GcFlags.doIdleGC = rtsFalse;
119 #endif
120
121 #if osf3_HOST_OS
122 /* ToDo: Perhaps by adjusting this value we can make linking without
123 * -static work (i.e., not generate a core-dumping executable)? */
124 # if SIZEOF_VOID_P == 8
125 RtsFlags.GcFlags.heapBase = 0x180000000L;
126 # else
127 # error I have no idea where to begin the heap on a non-64-bit osf3 machine.
128 # endif
129 #else
130 RtsFlags.GcFlags.heapBase = 0; /* means don't care */
131 #endif
132
133 #ifdef DEBUG
134 RtsFlags.DebugFlags.scheduler = rtsFalse;
135 RtsFlags.DebugFlags.interpreter = rtsFalse;
136 RtsFlags.DebugFlags.weak = rtsFalse;
137 RtsFlags.DebugFlags.gccafs = rtsFalse;
138 RtsFlags.DebugFlags.gc = rtsFalse;
139 RtsFlags.DebugFlags.block_alloc = rtsFalse;
140 RtsFlags.DebugFlags.sanity = rtsFalse;
141 RtsFlags.DebugFlags.stable = rtsFalse;
142 RtsFlags.DebugFlags.stm = rtsFalse;
143 RtsFlags.DebugFlags.prof = rtsFalse;
144 RtsFlags.DebugFlags.apply = rtsFalse;
145 RtsFlags.DebugFlags.linker = rtsFalse;
146 RtsFlags.DebugFlags.squeeze = rtsFalse;
147 RtsFlags.DebugFlags.hpc = rtsFalse;
148 RtsFlags.DebugFlags.sparks = rtsFalse;
149 #endif
150
151 #if defined(PROFILING)
152 RtsFlags.CcFlags.doCostCentres = 0;
153 #endif /* PROFILING */
154
155 RtsFlags.ProfFlags.doHeapProfile = rtsFalse;
156 RtsFlags.ProfFlags. heapProfileInterval = USToTime(100000); // 100ms
157
158 #ifdef PROFILING
159 RtsFlags.ProfFlags.includeTSOs = rtsFalse;
160 RtsFlags.ProfFlags.showCCSOnException = rtsFalse;
161 RtsFlags.ProfFlags.maxRetainerSetSize = 8;
162 RtsFlags.ProfFlags.ccsLength = 25;
163 RtsFlags.ProfFlags.modSelector = NULL;
164 RtsFlags.ProfFlags.descrSelector = NULL;
165 RtsFlags.ProfFlags.typeSelector = NULL;
166 RtsFlags.ProfFlags.ccSelector = NULL;
167 RtsFlags.ProfFlags.ccsSelector = NULL;
168 RtsFlags.ProfFlags.retainerSelector = NULL;
169 RtsFlags.ProfFlags.bioSelector = NULL;
170 #endif
171
172 #ifdef TRACING
173 RtsFlags.TraceFlags.tracing = TRACE_NONE;
174 RtsFlags.TraceFlags.timestamp = rtsFalse;
175 RtsFlags.TraceFlags.scheduler = rtsFalse;
176 RtsFlags.TraceFlags.gc = rtsFalse;
177 RtsFlags.TraceFlags.sparks_sampled= rtsFalse;
178 RtsFlags.TraceFlags.sparks_full = rtsFalse;
179 RtsFlags.TraceFlags.user = rtsFalse;
180 #endif
181
182 #ifdef PROFILING
183 // When profiling we want a lot more ticks
184 RtsFlags.MiscFlags.tickInterval = USToTime(1000); // 1ms
185 #else
186 RtsFlags.MiscFlags.tickInterval = DEFAULT_TICK_INTERVAL;
187 #endif
188 RtsFlags.ConcFlags.ctxtSwitchTime = USToTime(20000); // 20ms
189
190 RtsFlags.MiscFlags.install_signal_handlers = rtsTrue;
191 RtsFlags.MiscFlags.machineReadable = rtsFalse;
192 RtsFlags.MiscFlags.linkerMemBase = 0;
193
194 #ifdef THREADED_RTS
195 RtsFlags.ParFlags.nNodes = 1;
196 RtsFlags.ParFlags.migrate = rtsTrue;
197 RtsFlags.ParFlags.parGcEnabled = 1;
198 RtsFlags.ParFlags.parGcGen = 0;
199 RtsFlags.ParFlags.parGcLoadBalancingEnabled = rtsTrue;
200 RtsFlags.ParFlags.parGcLoadBalancingGen = 1;
201 RtsFlags.ParFlags.parGcNoSyncWithIdle = 0;
202 RtsFlags.ParFlags.setAffinity = 0;
203 #endif
204
205 #if defined(THREADED_RTS)
206 RtsFlags.ParFlags.maxLocalSparks = 4096;
207 #endif /* THREADED_RTS */
208
209 #ifdef TICKY_TICKY
210 RtsFlags.TickyFlags.showTickyStats = rtsFalse;
211 RtsFlags.TickyFlags.tickyFile = NULL;
212 #endif
213
214 #ifdef USE_PAPI
215 /* By default no special measurements taken */
216 RtsFlags.PapiFlags.eventType = 0;
217 RtsFlags.PapiFlags.numUserEvents = 0;
218 #endif
219 }
220
221 static const char *
222 usage_text[] = {
223 "",
224 "Usage: <prog> <args> [+RTS <rtsopts> | -RTS <args>] ... --RTS <args>",
225 "",
226 " +RTS Indicates run time system options follow",
227 " -RTS Indicates program arguments follow",
228 " --RTS Indicates that ALL subsequent arguments will be given to the",
229 " program (including any of these RTS flags)",
230 "",
231 "The following run time system options are available:",
232 "",
233 " -? Prints this message and exits; the program is not executed",
234 " --info Print information about the RTS used by this program",
235 "",
236 " -K<size> Sets the maximum stack size (defaults to infinite) Egs: -K32k -K512k",
237 " -ki<size> Sets the initial thread stack size (default 1k) Egs: -ki4k -ki2m",
238 " -kc<size> Sets the stack chunk size (default 32k)",
239 " -kb<size> Sets the stack chunk buffer size (default 1k)",
240 "",
241 " -A<size> Sets the minimum allocation area size (default 512k) Egs: -A1m -A10k",
242 " -M<size> Sets the maximum heap size (default unlimited) Egs: -M256k -M1G",
243 " -H<size> Sets the minimum heap size (default 0M) Egs: -H24m -H1G",
244 " -m<n> Minimum % of heap which must be available (default 3%)",
245 " -G<n> Number of generations (default: 2)",
246 " -c<n> Use in-place compaction instead of copying in the oldest generation",
247 " when live data is at least <n>% of the maximum heap size set with",
248 " -M (default: 30%)",
249 " -c Use in-place compaction for all oldest generation collections",
250 " (the default is to use copying)",
251 " -w Use mark-region for the oldest generation (experimental)",
252 #if defined(THREADED_RTS)
253 " -I<sec> Perform full GC after <sec> idle time (default: 0.3, 0 == off)",
254 #endif
255 "",
256 " -T Collect GC statistics (useful for in-program statistics access)",
257 " -t[<file>] One-line GC statistics (if <file> omitted, uses stderr)",
258 " -s[<file>] Summary GC statistics (if <file> omitted, uses stderr)",
259 " -S[<file>] Detailed GC statistics (if <file> omitted, uses stderr)",
260 "",
261 "",
262 " -Z Don't squeeze out update frames on stack overflow",
263 " -B Sound the bell at the start of each garbage collection",
264 #if defined(PROFILING)
265 "",
266 " -p Time/allocation profile (output file <program>.prof)",
267 " -P More detailed Time/Allocation profile",
268 " -Pa Give information about *all* cost centres",
269
270 # if defined(PROFILING)
271 "",
272 " -h<break-down> Heap residency profile (hp2ps) (output file <program>.hp)",
273 " break-down: c = cost centre stack (default)",
274 " m = module",
275 " d = closure description",
276 " y = type description",
277 " r = retainer",
278 " b = biography (LAG,DRAG,VOID,USE)",
279 " A subset of closures may be selected thusly:",
280 " -hc<cc>,... specific cost centre(s) (top of stack only)",
281 " -hC<cc>,... specific cost centre(s) (anywhere in stack)",
282 " -hm<mod>... all cost centres from the specified modules(s)",
283 " -hd<des>,... closures with specified closure descriptions",
284 " -hy<typ>... closures with specified type descriptions",
285 " -hr<cc>... closures with specified retainers",
286 " -hb<bio>... closures with specified biographies (lag,drag,void,use)",
287 "",
288 " -R<size> Set the maximum retainer set size (default: 8)",
289 "",
290 " -L<chars> Maximum length of a cost-centre stack in a heap profile",
291 " (default: 25)",
292 "",
293 " -xt Include threads (TSOs) in a heap profile",
294 "",
295 " -xc Show current cost centre stack on raising an exception",
296 # endif
297 #endif /* PROFILING or PAR */
298
299 #ifdef TRACING
300 "",
301 " -l[flags] Log events in binary format to the file <program>.eventlog",
302 # ifdef DEBUG
303 " -v[flags] Log events to stderr",
304 # endif
305 " where [flags] can contain:",
306 " s scheduler events",
307 " g GC and heap events",
308 " p par spark events (sampled)",
309 " f par spark events (full detail)",
310 " u user events (emitted from Haskell code)",
311 " a all event classes above",
312 # ifdef DEBUG
313 " t add time stamps (only useful with -v)",
314 # endif
315 " -x disable an event class, for any flag above",
316 " the initial enabled event classes are 'sgpu'",
317 #endif
318
319 #if !defined(PROFILING)
320 "",
321 " -h Heap residency profile (output file <program>.hp)",
322 #endif
323 " -i<sec> Time between heap profile samples (seconds, default: 0.1)",
324 "",
325 #if defined(TICKY_TICKY)
326 " -r<file> Produce ticky-ticky statistics (with -rstderr for stderr)",
327 "",
328 #endif
329 " -C<secs> Context-switch interval in seconds.",
330 " 0 or no argument means switch as often as possible.",
331 " Default: 0.02 sec.",
332 " -V<secs> Master tick interval in seconds (0 == disable timer).",
333 " This sets the resolution for -C and the heap profile timer -i,",
334 " and is the frequence of time profile samples.",
335 #ifdef PROFILING
336 " Default: 0.001 sec.",
337 #else
338 " Default: 0.01 sec.",
339 #endif
340 "",
341 #if defined(DEBUG)
342 " -Ds DEBUG: scheduler",
343 " -Di DEBUG: interpreter",
344 " -Dw DEBUG: weak",
345 " -DG DEBUG: gccafs",
346 " -Dg DEBUG: gc",
347 " -Db DEBUG: block",
348 " -DS DEBUG: sanity",
349 " -Dt DEBUG: stable",
350 " -Dp DEBUG: prof",
351 " -Da DEBUG: apply",
352 " -Dl DEBUG: linker",
353 " -Dm DEBUG: stm",
354 " -Dz DEBUG: stack squeezing",
355 " -Dc DEBUG: program coverage",
356 " -Dr DEBUG: sparks",
357 "",
358 " NOTE: DEBUG events are sent to stderr by default; add -l to create a",
359 " binary event log file instead.",
360 "",
361 #endif /* DEBUG */
362 #if defined(THREADED_RTS) && !defined(NOSMP)
363 " -N[<n>] Use <n> processors (default: 1, -N alone determines",
364 " the number of processors to use automatically)",
365 " -qg[<n>] Use parallel GC only for generations >= <n>",
366 " (default: 0, -qg alone turns off parallel GC)",
367 " -qb[<n>] Use load-balancing in the parallel GC only for generations >= <n>",
368 " (default: 1, -qb alone turns off load-balancing)",
369 " -qa Use the OS to set thread affinity (experimental)",
370 " -qm Don't automatically migrate threads between CPUs",
371 " -qi<n> If a processor has been idle for the last <n> GCs, do not",
372 " wake it up for a non-load-balancing parallel GC.",
373 " (0 disables, default: 0)",
374 #endif
375 " --install-signal-handlers=<yes|no>",
376 " Install signal handlers (default: yes)",
377 #if defined(THREADED_RTS)
378 " -e<n> Maximum number of outstanding local sparks (default: 4096)",
379 #endif
380 #if defined(x86_64_HOST_ARCH)
381 " -xm Base address to mmap memory in the GHCi linker",
382 " (hex; must be <80000000)",
383 #endif
384 #if defined(USE_PAPI)
385 " -aX CPU performance counter measurements using PAPI",
386 " (use with the -s<file> option). X is one of:",
387 "",
388 /* " y - cycles", */
389 " 1 - level 1 cache misses",
390 " 2 - level 2 cache misses",
391 " b - branch mispredictions",
392 " s - stalled cycles",
393 " e - cache miss and branch misprediction events",
394 " +PAPI_EVENT - collect papi preset event PAPI_EVENT",
395 " #NATIVE_EVENT - collect native event NATIVE_EVENT (in hex)",
396 #endif
397 "",
398 "RTS options may also be specified using the GHCRTS environment variable.",
399 "",
400 "Other RTS options may be available for programs compiled a different way.",
401 "The GHC User's Guide has full details.",
402 "",
403 0
404 };
405
406 STATIC_INLINE rtsBool
407 strequal(const char *a, const char * b)
408 {
409 return(strcmp(a, b) == 0);
410 }
411
412 // We can't predict up front how much space we'll need for rts_argv,
413 // because it involves parsing ghc_rts_opts and GHCRTS, so we
414 // expand it on demand.
415 static void appendRtsArg (char *arg)
416 {
417 if (rts_argc == rts_argv_size) {
418 rts_argv_size *= 2;
419 rts_argv = stgReallocBytes(rts_argv, rts_argv_size * sizeof (char *),
420 "RtsFlags.c:appendRtsArg");
421 }
422 rts_argv[rts_argc++] = arg;
423 }
424
425 static void splitRtsFlags(const char *s)
426 {
427 const char *c1, *c2;
428 char *t;
429
430 c1 = s;
431 do {
432 while (isspace(*c1)) { c1++; };
433 c2 = c1;
434 while (!isspace(*c2) && *c2 != '\0') { c2++; };
435
436 if (c1 == c2) { break; }
437
438 t = stgMallocBytes(c2-c1+1, "RtsFlags.c:splitRtsFlags()");
439 strncpy(t, c1, c2-c1);
440 t[c2-c1] = '\0';
441 appendRtsArg(t);
442
443 c1 = c2;
444 } while (*c1 != '\0');
445 }
446
447 /* -----------------------------------------------------------------------------
448 Parse the command line arguments, collecting options for the RTS.
449
450 On return:
451 - argv[] is *modified*, any RTS options have been stripped out
452 - *argc contains the new count of arguments in argv[]
453
454 - rts_argv[] (global) contains a copy of the collected RTS args
455 - rts_argc (global) contains the count of args in rts_argv
456
457 - prog_argv[] (global) contains a copy of the non-RTS args (== argv)
458 - prog_argc (global) contains the count of args in prog_argv
459
460 - prog_name (global) contains the basename of prog_argv[0]
461
462 -------------------------------------------------------------------------- */
463
464 void setupRtsFlags (int *argc, char *argv[],
465 RtsOptsEnabledEnum rtsOptsEnabled,
466 const char *ghc_rts_opts)
467 {
468 nat mode;
469 nat total_arg;
470 nat arg, rts_argc0;
471
472 setProgName (argv);
473 total_arg = *argc;
474 arg = 1;
475
476 if (*argc > 1) { *argc = 1; };
477 rts_argc = 0;
478
479 rts_argv_size = total_arg + 1;
480 rts_argv = stgMallocBytes(rts_argv_size * sizeof (char *), "setupRtsFlags");
481
482 rts_argc0 = rts_argc;
483
484 // process arguments from the -with-rtsopts compile-time flag first
485 // (arguments from the GHCRTS environment variable and the command
486 // line override these).
487 {
488 if (ghc_rts_opts != NULL) {
489 splitRtsFlags(ghc_rts_opts);
490 // opts from ghc_rts_opts are always enabled:
491 procRtsOpts(rts_argc0, RtsOptsAll);
492 rts_argc0 = rts_argc;
493 }
494 }
495
496 // process arguments from the GHCRTS environment variable next
497 // (arguments from the command line override these).
498 {
499 char *ghc_rts = getenv("GHCRTS");
500
501 if (ghc_rts != NULL) {
502 if (rtsOptsEnabled == RtsOptsNone) {
503 errorBelch("Warning: Ignoring GHCRTS variable as RTS options are disabled.\n Link with -rtsopts to enable them.");
504 // We don't actually exit, just warn
505 } else {
506 splitRtsFlags(ghc_rts);
507 procRtsOpts(rts_argc0, rtsOptsEnabled);
508 rts_argc0 = rts_argc;
509 }
510 }
511 }
512
513 // Split arguments (argv) into PGM (argv) and RTS (rts_argv) parts
514 // argv[0] must be PGM argument -- leave in argv
515
516 for (mode = PGM; arg < total_arg; arg++) {
517 // The '--RTS' argument disables all future +RTS ... -RTS processing.
518 if (strequal("--RTS", argv[arg])) {
519 arg++;
520 break;
521 }
522 // The '--' argument is passed through to the program, but
523 // disables all further +RTS ... -RTS processing.
524 else if (strequal("--", argv[arg])) {
525 break;
526 }
527 else if (strequal("+RTS", argv[arg])) {
528 mode = RTS;
529 }
530 else if (strequal("-RTS", argv[arg])) {
531 mode = PGM;
532 }
533 else if (mode == RTS) {
534 appendRtsArg(copyArg(argv[arg]));
535 }
536 else {
537 argv[(*argc)++] = argv[arg];
538 }
539 }
540 // process remaining program arguments
541 for (; arg < total_arg; arg++) {
542 argv[(*argc)++] = argv[arg];
543 }
544 argv[*argc] = (char *) 0;
545
546 procRtsOpts(rts_argc0, rtsOptsEnabled);
547
548 appendRtsArg((char *)0);
549 rts_argc--; // appendRtsArg will have bumped it for the NULL (#7227)
550
551 normaliseRtsOpts();
552
553 setProgArgv(*argc, argv);
554
555 if (RtsFlags.GcFlags.statsFile != NULL) {
556 initStatsFile (RtsFlags.GcFlags.statsFile);
557 }
558 if (RtsFlags.TickyFlags.tickyFile != NULL) {
559 initStatsFile (RtsFlags.GcFlags.statsFile);
560 }
561 }
562
563 /* -----------------------------------------------------------------------------
564 * procRtsOpts: Process rts_argv between rts_argc0 and rts_argc.
565 * -------------------------------------------------------------------------- */
566
567 static void checkSuid(RtsOptsEnabledEnum enabled)
568 {
569 if (enabled == RtsOptsSafeOnly) {
570 #if defined(HAVE_UNISTD_H) && defined(HAVE_SYS_TYPES_H) && !defined(mingw32_HOST_OS)
571 /* This doesn't cover linux/posix capabilities like CAP_DAC_OVERRIDE,
572 we'd have to link with -lcap for that. */
573 if ((getuid() != geteuid()) || (getgid() != getegid())) {
574 errorBelch("RTS options are disabled for setuid binaries. Link with -rtsopts to enable them.");
575 stg_exit(EXIT_FAILURE);
576 }
577 #endif
578 }
579 }
580
581 static void checkUnsafe(RtsOptsEnabledEnum enabled)
582 {
583 if (enabled == RtsOptsSafeOnly) {
584 errorBelch("Most RTS options are disabled. Link with -rtsopts to enable them.");
585 stg_exit(EXIT_FAILURE);
586 }
587 }
588
589 static void procRtsOpts (int rts_argc0, RtsOptsEnabledEnum rtsOptsEnabled)
590 {
591 rtsBool error = rtsFalse;
592 int arg;
593
594 if (!(rts_argc0 < rts_argc)) return;
595
596 if (rtsOptsEnabled == RtsOptsNone) {
597 errorBelch("RTS options are disabled. Link with -rtsopts to enable them.");
598 stg_exit(EXIT_FAILURE);
599 }
600
601 checkSuid(rtsOptsEnabled);
602
603 // Process RTS (rts_argv) part: mainly to determine statsfile
604 for (arg = rts_argc0; arg < rts_argc; arg++) {
605
606 /* We handle RtsOptsSafeOnly mode by declaring each option as
607 either OPTION_SAFE or OPTION_UNSAFE. To make sure we cover
608 every branch we use an option_checked flag which is reset
609 at the start each iteration and checked at the end. */
610 rtsBool option_checked = rtsFalse;
611
612 #define OPTION_SAFE option_checked = rtsTrue;
613 #define OPTION_UNSAFE checkUnsafe(rtsOptsEnabled); option_checked = rtsTrue;
614
615 if (rts_argv[arg][0] != '-') {
616 fflush(stdout);
617 errorBelch("unexpected RTS argument: %s", rts_argv[arg]);
618 error = rtsTrue;
619
620 } else {
621
622 switch(rts_argv[arg][1]) {
623
624 /* process: general args, then PROFILING-only ones, then
625 CONCURRENT-only, TICKY-only (same order as defined in
626 RtsFlags.lh); within those groups, mostly in
627 case-insensitive alphabetical order. Final group is
628 x*, which allows for more options.
629 */
630
631 #ifdef TICKY_TICKY
632 # define TICKY_BUILD_ONLY(x) x
633 #else
634 # define TICKY_BUILD_ONLY(x) \
635 errorBelch("the flag %s requires the program to be built with -ticky", rts_argv[arg]); \
636 error = rtsTrue;
637 #endif
638
639 #ifdef PROFILING
640 # define PROFILING_BUILD_ONLY(x) x
641 #else
642 # define PROFILING_BUILD_ONLY(x) \
643 errorBelch("the flag %s requires the program to be built with -prof", rts_argv[arg]); \
644 error = rtsTrue;
645 #endif
646
647 #ifdef TRACING
648 # define TRACING_BUILD_ONLY(x) x
649 #else
650 # define TRACING_BUILD_ONLY(x) \
651 errorBelch("the flag %s requires the program to be built with -eventlog or -debug", rts_argv[arg]); \
652 error = rtsTrue;
653 #endif
654
655 #ifdef THREADED_RTS
656 # define THREADED_BUILD_ONLY(x) x
657 #else
658 # define THREADED_BUILD_ONLY(x) \
659 errorBelch("the flag %s requires the program to be built with -threaded", rts_argv[arg]); \
660 error = rtsTrue;
661 #endif
662
663 #ifdef DEBUG
664 # define DEBUG_BUILD_ONLY(x) x
665 #else
666 # define DEBUG_BUILD_ONLY(x) \
667 errorBelch("the flag %s requires the program to be built with -debug", rts_argv[arg]); \
668 error = rtsTrue;
669 #endif
670
671 /* =========== GENERAL ========================== */
672 case '?':
673 OPTION_SAFE;
674 error = rtsTrue;
675 break;
676
677 /* This isn't going to allow us to keep related options
678 together as we add more --* flags. We really need a
679 proper options parser. */
680 case '-':
681 if (strequal("install-signal-handlers=yes",
682 &rts_argv[arg][2])) {
683 OPTION_UNSAFE;
684 RtsFlags.MiscFlags.install_signal_handlers = rtsTrue;
685 }
686 else if (strequal("install-signal-handlers=no",
687 &rts_argv[arg][2])) {
688 OPTION_UNSAFE;
689 RtsFlags.MiscFlags.install_signal_handlers = rtsFalse;
690 }
691 else if (strequal("machine-readable",
692 &rts_argv[arg][2])) {
693 OPTION_UNSAFE;
694 RtsFlags.MiscFlags.machineReadable = rtsTrue;
695 }
696 else if (strequal("info",
697 &rts_argv[arg][2])) {
698 OPTION_SAFE;
699 printRtsInfo();
700 stg_exit(0);
701 }
702 else {
703 OPTION_SAFE;
704 errorBelch("unknown RTS option: %s",rts_argv[arg]);
705 error = rtsTrue;
706 }
707 break;
708 case 'A':
709 OPTION_UNSAFE;
710 RtsFlags.GcFlags.minAllocAreaSize
711 = decodeSize(rts_argv[arg], 2, BLOCK_SIZE, HS_INT_MAX)
712 / BLOCK_SIZE;
713 break;
714
715 #ifdef USE_PAPI
716 case 'a':
717 OPTION_UNSAFE;
718 switch(rts_argv[arg][2]) {
719 case '1':
720 RtsFlags.PapiFlags.eventType = PAPI_FLAG_CACHE_L1;
721 break;
722 case '2':
723 RtsFlags.PapiFlags.eventType = PAPI_FLAG_CACHE_L2;
724 break;
725 case 'b':
726 RtsFlags.PapiFlags.eventType = PAPI_FLAG_BRANCH;
727 break;
728 case 's':
729 RtsFlags.PapiFlags.eventType = PAPI_FLAG_STALLS;
730 break;
731 case 'e':
732 RtsFlags.PapiFlags.eventType = PAPI_FLAG_CB_EVENTS;
733 break;
734 case '+':
735 case '#':
736 if (RtsFlags.PapiFlags.numUserEvents >= MAX_PAPI_USER_EVENTS) {
737 errorBelch("maximum number of PAPI events reached");
738 stg_exit(EXIT_FAILURE);
739 }
740 nat eventNum = RtsFlags.PapiFlags.numUserEvents++;
741 char kind = rts_argv[arg][2];
742 nat eventKind = kind == '+' ? PAPI_PRESET_EVENT_KIND : PAPI_NATIVE_EVENT_KIND;
743
744 RtsFlags.PapiFlags.userEvents[eventNum] = rts_argv[arg] + 3;
745 RtsFlags.PapiFlags.eventType = PAPI_USER_EVENTS;
746 RtsFlags.PapiFlags.userEventsKind[eventNum] = eventKind;
747 break;
748 default:
749 bad_option( rts_argv[arg] );
750 }
751 break;
752 #endif
753
754 case 'B':
755 OPTION_UNSAFE;
756 RtsFlags.GcFlags.ringBell = rtsTrue;
757 break;
758
759 case 'c':
760 OPTION_UNSAFE;
761 if (rts_argv[arg][2] != '\0') {
762 RtsFlags.GcFlags.compactThreshold =
763 atof(rts_argv[arg]+2);
764 } else {
765 RtsFlags.GcFlags.compact = rtsTrue;
766 }
767 break;
768
769 case 'w':
770 OPTION_UNSAFE;
771 RtsFlags.GcFlags.sweep = rtsTrue;
772 break;
773
774 case 'F':
775 OPTION_UNSAFE;
776 RtsFlags.GcFlags.oldGenFactor = atof(rts_argv[arg]+2);
777
778 if (RtsFlags.GcFlags.oldGenFactor < 0)
779 bad_option( rts_argv[arg] );
780 break;
781
782 case 'D':
783 OPTION_SAFE;
784 DEBUG_BUILD_ONLY(
785 {
786 char *c;
787
788 for (c = rts_argv[arg] + 2; *c != '\0'; c++) {
789 switch (*c) {
790 case 's':
791 RtsFlags.DebugFlags.scheduler = rtsTrue;
792 break;
793 case 'i':
794 RtsFlags.DebugFlags.interpreter = rtsTrue;
795 break;
796 case 'w':
797 RtsFlags.DebugFlags.weak = rtsTrue;
798 break;
799 case 'G':
800 RtsFlags.DebugFlags.gccafs = rtsTrue;
801 break;
802 case 'g':
803 RtsFlags.DebugFlags.gc = rtsTrue;
804 break;
805 case 'b':
806 RtsFlags.DebugFlags.block_alloc = rtsTrue;
807 break;
808 case 'S':
809 RtsFlags.DebugFlags.sanity = rtsTrue;
810 break;
811 case 't':
812 RtsFlags.DebugFlags.stable = rtsTrue;
813 break;
814 case 'p':
815 RtsFlags.DebugFlags.prof = rtsTrue;
816 break;
817 case 'l':
818 RtsFlags.DebugFlags.linker = rtsTrue;
819 break;
820 case 'a':
821 RtsFlags.DebugFlags.apply = rtsTrue;
822 break;
823 case 'm':
824 RtsFlags.DebugFlags.stm = rtsTrue;
825 break;
826 case 'z':
827 RtsFlags.DebugFlags.squeeze = rtsTrue;
828 break;
829 case 'c':
830 RtsFlags.DebugFlags.hpc = rtsTrue;
831 break;
832 case 'r':
833 RtsFlags.DebugFlags.sparks = rtsTrue;
834 break;
835 default:
836 bad_option( rts_argv[arg] );
837 }
838 }
839 // -Dx also turns on -v. Use -l to direct trace
840 // events to the .eventlog file instead.
841 RtsFlags.TraceFlags.tracing = TRACE_STDERR;
842 })
843 break;
844
845 case 'K':
846 OPTION_UNSAFE;
847 RtsFlags.GcFlags.maxStkSize =
848 decodeSize(rts_argv[arg], 2, sizeof(W_), HS_WORD_MAX) / sizeof(W_);
849 break;
850
851 case 'k':
852 OPTION_UNSAFE;
853 switch(rts_argv[arg][2]) {
854 case 'c':
855 RtsFlags.GcFlags.stkChunkSize =
856 decodeSize(rts_argv[arg], 3, sizeof(W_), HS_WORD_MAX) / sizeof(W_);
857 break;
858 case 'b':
859 RtsFlags.GcFlags.stkChunkBufferSize =
860 decodeSize(rts_argv[arg], 3, sizeof(W_), HS_WORD_MAX) / sizeof(W_);
861 break;
862 case 'i':
863 RtsFlags.GcFlags.initialStkSize =
864 decodeSize(rts_argv[arg], 3, sizeof(W_), HS_WORD_MAX) / sizeof(W_);
865 break;
866 default:
867 RtsFlags.GcFlags.initialStkSize =
868 decodeSize(rts_argv[arg], 2, sizeof(W_), HS_WORD_MAX) / sizeof(W_);
869 break;
870 }
871 break;
872
873 case 'M':
874 OPTION_UNSAFE;
875 RtsFlags.GcFlags.maxHeapSize =
876 decodeSize(rts_argv[arg], 2, BLOCK_SIZE, HS_WORD_MAX) / BLOCK_SIZE;
877 /* user give size in *bytes* but "maxHeapSize" is in *blocks* */
878 break;
879
880 case 'm':
881 OPTION_UNSAFE;
882 RtsFlags.GcFlags.pcFreeHeap = atof(rts_argv[arg]+2);
883
884 if (RtsFlags.GcFlags.pcFreeHeap < 0 ||
885 RtsFlags.GcFlags.pcFreeHeap > 100)
886 bad_option( rts_argv[arg] );
887 break;
888
889 case 'G':
890 OPTION_UNSAFE;
891 RtsFlags.GcFlags.generations =
892 decodeSize(rts_argv[arg], 2, 1, HS_INT_MAX);
893 break;
894
895 case 'H':
896 OPTION_UNSAFE;
897 if (rts_argv[arg][2] == '\0') {
898 RtsFlags.GcFlags.heapSizeSuggestionAuto = rtsTrue;
899 } else {
900 RtsFlags.GcFlags.heapSizeSuggestion =
901 (nat)(decodeSize(rts_argv[arg], 2, BLOCK_SIZE, HS_WORD_MAX) / BLOCK_SIZE);
902 }
903 break;
904
905 case 'I': /* idle GC delay */
906 OPTION_UNSAFE;
907 if (rts_argv[arg][2] == '\0') {
908 /* use default */
909 } else {
910 Time t = fsecondsToTime(atof(rts_argv[arg]+2));
911 if (t == 0) {
912 RtsFlags.GcFlags.doIdleGC = rtsFalse;
913 } else {
914 RtsFlags.GcFlags.doIdleGC = rtsTrue;
915 RtsFlags.GcFlags.idleGCDelayTime = t;
916 }
917 }
918 break;
919
920 case 'T':
921 OPTION_SAFE;
922 RtsFlags.GcFlags.giveStats = COLLECT_GC_STATS;
923 break; /* Don't initialize statistics file. */
924
925 case 'S':
926 OPTION_SAFE; /* but see below */
927 RtsFlags.GcFlags.giveStats = VERBOSE_GC_STATS;
928 goto stats;
929
930 case 's':
931 OPTION_SAFE; /* but see below */
932 RtsFlags.GcFlags.giveStats = SUMMARY_GC_STATS;
933 goto stats;
934
935 case 't':
936 OPTION_SAFE; /* but see below */
937 RtsFlags.GcFlags.giveStats = ONELINE_GC_STATS;
938 goto stats;
939
940 stats:
941 {
942 int r;
943 if (rts_argv[arg][2] != '\0') {
944 OPTION_UNSAFE;
945 }
946 r = openStatsFile(rts_argv[arg]+2, NULL,
947 &RtsFlags.GcFlags.statsFile);
948 if (r == -1) { error = rtsTrue; }
949 }
950 break;
951
952 case 'Z':
953 OPTION_UNSAFE;
954 RtsFlags.GcFlags.squeezeUpdFrames = rtsFalse;
955 break;
956
957 /* =========== PROFILING ========================== */
958
959 case 'P': /* detailed cost centre profiling (time/alloc) */
960 case 'p': /* cost centre profiling (time/alloc) */
961 OPTION_SAFE;
962 PROFILING_BUILD_ONLY(
963 switch (rts_argv[arg][2]) {
964 case 'a':
965 RtsFlags.CcFlags.doCostCentres = COST_CENTRES_ALL;
966 break;
967 default:
968 if (rts_argv[arg][1] == 'P') {
969 RtsFlags.CcFlags.doCostCentres =
970 COST_CENTRES_VERBOSE;
971 } else {
972 RtsFlags.CcFlags.doCostCentres =
973 COST_CENTRES_SUMMARY;
974 }
975 break;
976 }
977 ) break;
978
979 case 'R':
980 OPTION_SAFE;
981 PROFILING_BUILD_ONLY(
982 RtsFlags.ProfFlags.maxRetainerSetSize = atof(rts_argv[arg]+2);
983 ) break;
984 case 'L':
985 OPTION_SAFE;
986 PROFILING_BUILD_ONLY(
987 RtsFlags.ProfFlags.ccsLength = atof(rts_argv[arg]+2);
988 if(RtsFlags.ProfFlags.ccsLength <= 0) {
989 bad_option(rts_argv[arg]);
990 }
991 ) break;
992 case 'h': /* serial heap profile */
993 #if !defined(PROFILING)
994 OPTION_UNSAFE;
995 switch (rts_argv[arg][2]) {
996 case '\0':
997 case 'T':
998 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_CLOSURE_TYPE;
999 break;
1000 default:
1001 errorBelch("invalid heap profile option: %s",rts_argv[arg]);
1002 error = rtsTrue;
1003 }
1004 #else
1005 OPTION_SAFE;
1006 PROFILING_BUILD_ONLY(
1007 switch (rts_argv[arg][2]) {
1008 case '\0':
1009 case 'C':
1010 case 'c':
1011 case 'M':
1012 case 'm':
1013 case 'D':
1014 case 'd':
1015 case 'Y':
1016 case 'y':
1017 case 'R':
1018 case 'r':
1019 case 'B':
1020 case 'b':
1021 if (rts_argv[arg][2] != '\0' && rts_argv[arg][3] != '\0') {
1022 {
1023 char *left = strchr(rts_argv[arg], '{');
1024 char *right = strrchr(rts_argv[arg], '}');
1025
1026 // curly braces are optional, for
1027 // backwards compat.
1028 if (left)
1029 left = left+1;
1030 else
1031 left = rts_argv[arg] + 3;
1032
1033 if (!right)
1034 right = rts_argv[arg] + strlen(rts_argv[arg]);
1035
1036 *right = '\0';
1037
1038 switch (rts_argv[arg][2]) {
1039 case 'c': // cost centre label select
1040 RtsFlags.ProfFlags.ccSelector = left;
1041 break;
1042 case 'C':
1043 RtsFlags.ProfFlags.ccsSelector = left;
1044 break;
1045 case 'M':
1046 case 'm': // cost centre module select
1047 RtsFlags.ProfFlags.modSelector = left;
1048 break;
1049 case 'D':
1050 case 'd': // closure descr select
1051 RtsFlags.ProfFlags.descrSelector = left;
1052 break;
1053 case 'Y':
1054 case 'y': // closure type select
1055 RtsFlags.ProfFlags.typeSelector = left;
1056 break;
1057 case 'R':
1058 case 'r': // retainer select
1059 RtsFlags.ProfFlags.retainerSelector = left;
1060 break;
1061 case 'B':
1062 case 'b': // biography select
1063 RtsFlags.ProfFlags.bioSelector = left;
1064 break;
1065 }
1066 }
1067 break;
1068 }
1069
1070 if (RtsFlags.ProfFlags.doHeapProfile != 0) {
1071 errorBelch("multiple heap profile options");
1072 error = rtsTrue;
1073 break;
1074 }
1075
1076 switch (rts_argv[arg][2]) {
1077 case '\0':
1078 case 'C':
1079 case 'c':
1080 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_CCS;
1081 break;
1082 case 'M':
1083 case 'm':
1084 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_MOD;
1085 break;
1086 case 'D':
1087 case 'd':
1088 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_DESCR;
1089 break;
1090 case 'Y':
1091 case 'y':
1092 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_TYPE;
1093 break;
1094 case 'R':
1095 case 'r':
1096 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_RETAINER;
1097 break;
1098 case 'B':
1099 case 'b':
1100 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_LDV;
1101 break;
1102 }
1103 break;
1104
1105 default:
1106 errorBelch("invalid heap profile option: %s",rts_argv[arg]);
1107 error = rtsTrue;
1108 }
1109 )
1110 #endif /* PROFILING */
1111 break;
1112
1113 case 'i': /* heap sample interval */
1114 OPTION_UNSAFE;
1115 if (rts_argv[arg][2] == '\0') {
1116 /* use default */
1117 } else {
1118 RtsFlags.ProfFlags.heapProfileInterval =
1119 fsecondsToTime(atof(rts_argv[arg]+2));
1120 }
1121 break;
1122
1123 /* =========== CONCURRENT ========================= */
1124 case 'C': /* context switch interval */
1125 OPTION_UNSAFE;
1126 if (rts_argv[arg][2] == '\0')
1127 RtsFlags.ConcFlags.ctxtSwitchTime = 0;
1128 else {
1129 RtsFlags.ConcFlags.ctxtSwitchTime =
1130 fsecondsToTime(atof(rts_argv[arg]+2));
1131 }
1132 break;
1133
1134 case 'V': /* master tick interval */
1135 OPTION_UNSAFE;
1136 if (rts_argv[arg][2] == '\0') {
1137 // turns off ticks completely
1138 RtsFlags.MiscFlags.tickInterval = 0;
1139 } else {
1140 RtsFlags.MiscFlags.tickInterval =
1141 fsecondsToTime(atof(rts_argv[arg]+2));
1142 }
1143 break;
1144
1145 #if !defined(NOSMP)
1146 case 'N':
1147 OPTION_SAFE;
1148 THREADED_BUILD_ONLY(
1149 if (rts_argv[arg][2] == '\0') {
1150 #if defined(PROFILING)
1151 RtsFlags.ParFlags.nNodes = 1;
1152 #else
1153 RtsFlags.ParFlags.nNodes = getNumberOfProcessors();
1154 #endif
1155 } else {
1156 int nNodes;
1157 OPTION_SAFE; /* but see extra checks below... */
1158 nNodes = strtol(rts_argv[arg]+2, (char **) NULL, 10);
1159 if (nNodes <= 0) {
1160 errorBelch("bad value for -N");
1161 error = rtsTrue;
1162 }
1163 if (rtsOptsEnabled == RtsOptsSafeOnly &&
1164 nNodes > (int)getNumberOfProcessors()) {
1165 errorBelch("Using large values for -N is not allowed by default. Link with -rtsopts to allow full control.");
1166 stg_exit(EXIT_FAILURE);
1167 }
1168 RtsFlags.ParFlags.nNodes = (nat)nNodes;
1169 }
1170 ) break;
1171
1172 case 'g':
1173 OPTION_UNSAFE;
1174 THREADED_BUILD_ONLY(
1175 switch (rts_argv[arg][2]) {
1176 case '1':
1177 // backwards compat only
1178 RtsFlags.ParFlags.parGcEnabled = rtsFalse;
1179 break;
1180 default:
1181 errorBelch("unknown RTS option: %s",rts_argv[arg]);
1182 error = rtsTrue;
1183 break;
1184 }
1185 ) break;
1186
1187 case 'q':
1188 OPTION_UNSAFE;
1189 THREADED_BUILD_ONLY(
1190 switch (rts_argv[arg][2]) {
1191 case '\0':
1192 errorBelch("incomplete RTS option: %s",rts_argv[arg]);
1193 error = rtsTrue;
1194 break;
1195 case 'g':
1196 if (rts_argv[arg][3] == '\0') {
1197 RtsFlags.ParFlags.parGcEnabled = rtsFalse;
1198 } else {
1199 RtsFlags.ParFlags.parGcEnabled = rtsTrue;
1200 RtsFlags.ParFlags.parGcGen
1201 = strtol(rts_argv[arg]+3, (char **) NULL, 10);
1202 }
1203 break;
1204 case 'b':
1205 if (rts_argv[arg][3] == '\0') {
1206 RtsFlags.ParFlags.parGcLoadBalancingEnabled = rtsFalse;
1207 }
1208 else {
1209 RtsFlags.ParFlags.parGcLoadBalancingEnabled = rtsTrue;
1210 RtsFlags.ParFlags.parGcLoadBalancingGen
1211 = strtol(rts_argv[arg]+3, (char **) NULL, 10);
1212 }
1213 break;
1214 case 'i':
1215 RtsFlags.ParFlags.parGcNoSyncWithIdle
1216 = strtol(rts_argv[arg]+3, (char **) NULL, 10);
1217 break;
1218 case 'a':
1219 RtsFlags.ParFlags.setAffinity = rtsTrue;
1220 break;
1221 case 'm':
1222 RtsFlags.ParFlags.migrate = rtsFalse;
1223 break;
1224 case 'w':
1225 // -qw was removed; accepted for backwards compat
1226 break;
1227 default:
1228 errorBelch("unknown RTS option: %s",rts_argv[arg]);
1229 error = rtsTrue;
1230 break;
1231 }
1232 ) break;
1233 #endif
1234 /* =========== PARALLEL =========================== */
1235 case 'e':
1236 OPTION_UNSAFE;
1237 THREADED_BUILD_ONLY(
1238 if (rts_argv[arg][2] != '\0') {
1239 RtsFlags.ParFlags.maxLocalSparks
1240 = strtol(rts_argv[arg]+2, (char **) NULL, 10);
1241 if (RtsFlags.ParFlags.maxLocalSparks <= 0) {
1242 errorBelch("bad value for -e");
1243 error = rtsTrue;
1244 }
1245 }
1246 ) break;
1247
1248 /* =========== TICKY ============================== */
1249
1250 case 'r': /* Basic profiling stats */
1251 OPTION_SAFE;
1252 TICKY_BUILD_ONLY(
1253
1254 RtsFlags.TickyFlags.showTickyStats = rtsTrue;
1255
1256 {
1257 int r;
1258 if (rts_argv[arg][2] != '\0') {
1259 OPTION_UNSAFE;
1260 }
1261 r = openStatsFile(rts_argv[arg]+2,
1262 TICKY_FILENAME_FMT,
1263 &RtsFlags.TickyFlags.tickyFile);
1264 if (r == -1) { error = rtsTrue; }
1265 }
1266 ) break;
1267
1268 /* =========== TRACING ---------=================== */
1269
1270 case 'l':
1271 OPTION_SAFE;
1272 TRACING_BUILD_ONLY(
1273 RtsFlags.TraceFlags.tracing = TRACE_EVENTLOG;
1274 read_trace_flags(&rts_argv[arg][2]);
1275 );
1276 break;
1277
1278 case 'v':
1279 OPTION_SAFE;
1280 DEBUG_BUILD_ONLY(
1281 RtsFlags.TraceFlags.tracing = TRACE_STDERR;
1282 read_trace_flags(&rts_argv[arg][2]);
1283 );
1284 break;
1285
1286 /* =========== EXTENDED OPTIONS =================== */
1287
1288 case 'x': /* Extend the argument space */
1289 switch(rts_argv[arg][2]) {
1290 case '\0':
1291 OPTION_SAFE;
1292 errorBelch("incomplete RTS option: %s",rts_argv[arg]);
1293 error = rtsTrue;
1294 break;
1295
1296 case 'b': /* heapBase in hex; undocumented */
1297 OPTION_UNSAFE;
1298 if (rts_argv[arg][3] != '\0') {
1299 RtsFlags.GcFlags.heapBase
1300 = strtol(rts_argv[arg]+3, (char **) NULL, 16);
1301 } else {
1302 errorBelch("-xb: requires argument");
1303 error = rtsTrue;
1304 }
1305 break;
1306
1307 #if defined(x86_64_HOST_ARCH)
1308 case 'm': /* linkerMemBase */
1309 OPTION_UNSAFE;
1310 if (rts_argv[arg][3] != '\0') {
1311 RtsFlags.MiscFlags.linkerMemBase
1312 = strtol(rts_argv[arg]+3, (char **) NULL, 16);
1313 if (RtsFlags.MiscFlags.linkerMemBase > 0x80000000) {
1314 errorBelch("-xm: value must be <80000000");
1315 error = rtsTrue;
1316 }
1317 } else {
1318 RtsFlags.MiscFlags.linkerMemBase = 0;
1319 }
1320 break;
1321 #endif
1322
1323 case 'c': /* Debugging tool: show current cost centre on an exception */
1324 OPTION_SAFE;
1325 PROFILING_BUILD_ONLY(
1326 RtsFlags.ProfFlags.showCCSOnException = rtsTrue;
1327 );
1328 break;
1329
1330 case 't': /* Include memory used by TSOs in a heap profile */
1331 OPTION_SAFE;
1332 PROFILING_BUILD_ONLY(
1333 RtsFlags.ProfFlags.includeTSOs = rtsTrue;
1334 );
1335 break;
1336
1337 /* The option prefix '-xx' is reserved for future extension. KSW 1999-11. */
1338
1339 default:
1340 OPTION_SAFE;
1341 errorBelch("unknown RTS option: %s",rts_argv[arg]);
1342 error = rtsTrue;
1343 break;
1344 }
1345 break; /* defensive programming */
1346
1347 /* =========== OH DEAR ============================ */
1348 default:
1349 OPTION_SAFE;
1350 errorBelch("unknown RTS option: %s",rts_argv[arg]);
1351 error = rtsTrue;
1352 break;
1353 }
1354
1355 if (!option_checked) {
1356 /* Naughty! Someone didn't use OPTION_UNSAFE / OPTION_SAFE for
1357 an option above */
1358 errorBelch("Internal error in the RTS options parser");
1359 stg_exit(EXIT_FAILURE);
1360 }
1361 }
1362 }
1363
1364 if (error) errorUsage();
1365 }
1366
1367 /* -----------------------------------------------------------------------------
1368 * normaliseRtsOpts: Set some derived values, and make sure things are
1369 * within sensible ranges.
1370 * -------------------------------------------------------------------------- */
1371
1372 static void normaliseRtsOpts (void)
1373 {
1374 if (RtsFlags.MiscFlags.tickInterval < 0) {
1375 RtsFlags.MiscFlags.tickInterval = DEFAULT_TICK_INTERVAL;
1376 }
1377
1378 // If the master timer is disabled, turn off the other timers.
1379 if (RtsFlags.MiscFlags.tickInterval == 0) {
1380 RtsFlags.ConcFlags.ctxtSwitchTime = 0;
1381 RtsFlags.GcFlags.idleGCDelayTime = 0;
1382 RtsFlags.ProfFlags.heapProfileInterval = 0;
1383 }
1384
1385 // Determine what tick interval we should use for the RTS timer
1386 // by taking the shortest of the various intervals that we need to
1387 // monitor.
1388 if (RtsFlags.ConcFlags.ctxtSwitchTime > 0) {
1389 RtsFlags.MiscFlags.tickInterval =
1390 stg_min(RtsFlags.ConcFlags.ctxtSwitchTime,
1391 RtsFlags.MiscFlags.tickInterval);
1392 }
1393
1394 if (RtsFlags.GcFlags.idleGCDelayTime > 0) {
1395 RtsFlags.MiscFlags.tickInterval =
1396 stg_min(RtsFlags.GcFlags.idleGCDelayTime,
1397 RtsFlags.MiscFlags.tickInterval);
1398 }
1399
1400 if (RtsFlags.ProfFlags.heapProfileInterval > 0) {
1401 RtsFlags.MiscFlags.tickInterval =
1402 stg_min(RtsFlags.ProfFlags.heapProfileInterval,
1403 RtsFlags.MiscFlags.tickInterval);
1404 }
1405
1406 if (RtsFlags.ConcFlags.ctxtSwitchTime > 0) {
1407 RtsFlags.ConcFlags.ctxtSwitchTicks =
1408 RtsFlags.ConcFlags.ctxtSwitchTime /
1409 RtsFlags.MiscFlags.tickInterval;
1410 } else {
1411 RtsFlags.ConcFlags.ctxtSwitchTicks = 0;
1412 }
1413
1414 if (RtsFlags.ProfFlags.heapProfileInterval > 0) {
1415 RtsFlags.ProfFlags.heapProfileIntervalTicks =
1416 RtsFlags.ProfFlags.heapProfileInterval /
1417 RtsFlags.MiscFlags.tickInterval;
1418 } else {
1419 RtsFlags.ProfFlags.heapProfileIntervalTicks = 0;
1420 }
1421
1422 if (RtsFlags.GcFlags.stkChunkBufferSize >
1423 RtsFlags.GcFlags.stkChunkSize / 2) {
1424 errorBelch("stack chunk buffer size (-kb) must be less than 50%% of the stack chunk size (-kc)");
1425 errorUsage();
1426 }
1427 }
1428
1429 static void errorUsage (void)
1430 {
1431 const char **p;
1432
1433 fflush(stdout);
1434 for (p = usage_text; *p; p++)
1435 errorBelch("%s", *p);
1436 stg_exit(EXIT_FAILURE);
1437 }
1438
1439 static void
1440 stats_fprintf(FILE *f, char *s, ...)
1441 {
1442 va_list ap;
1443 va_start(ap,s);
1444 if (f == NULL) {
1445 vdebugBelch(s, ap);
1446 } else {
1447 vfprintf(f, s, ap);
1448 }
1449 va_end(ap);
1450 }
1451
1452 /* -----------------------------------------------------------------------------
1453 * openStatsFile: open a file in which to put some runtime stats
1454 * -------------------------------------------------------------------------- */
1455
1456 static int // return -1 on error
1457 openStatsFile (char *filename, // filename, or NULL
1458 const char *filename_fmt, // if filename == NULL, use
1459 // this fmt with sprintf to
1460 // generate the filename. %s
1461 // expands to the program name.
1462 FILE **file_ret) // return the FILE*
1463 {
1464 FILE *f = NULL;
1465
1466 if (strequal(filename, "stderr")
1467 || (filename_fmt == NULL && *filename == '\0')) {
1468 f = NULL; /* NULL means use debugBelch */
1469 } else {
1470 if (*filename != '\0') { /* stats file specified */
1471 f = fopen(filename,"w");
1472 } else {
1473 char stats_filename[STATS_FILENAME_MAXLEN]; /* default <program>.<ext> */
1474 sprintf(stats_filename, filename_fmt, prog_name);
1475 f = fopen(stats_filename,"w");
1476 }
1477 if (f == NULL) {
1478 errorBelch("Can't open stats file %s\n", filename);
1479 return -1;
1480 }
1481 }
1482 *file_ret = f;
1483
1484 return 0;
1485 }
1486
1487 /* -----------------------------------------------------------------------------
1488 * initStatsFile: write a line to the file containing the program name
1489 * and the arguments it was invoked with.
1490 -------------------------------------------------------------------------- */
1491
1492 static void initStatsFile (FILE *f)
1493 {
1494 /* Write prog_argv and rts_argv into start of stats file */
1495 int count;
1496 for (count = 0; count < prog_argc; count++) {
1497 stats_fprintf(f, "%s ", prog_argv[count]);
1498 }
1499 stats_fprintf(f, "+RTS ");
1500 for (count = 0; count < rts_argc; count++)
1501 stats_fprintf(f, "%s ", rts_argv[count]);
1502 stats_fprintf(f, "\n");
1503 }
1504
1505 /* -----------------------------------------------------------------------------
1506 * decodeSize: parse a string containing a size, like 300K or 1.2M
1507 -------------------------------------------------------------------------- */
1508
1509 static StgWord64
1510 decodeSize(const char *flag, nat offset, StgWord64 min, StgWord64 max)
1511 {
1512 char c;
1513 const char *s;
1514 StgDouble m;
1515 StgWord64 val;
1516
1517 s = flag + offset;
1518
1519 if (!*s)
1520 {
1521 m = 0;
1522 }
1523 else
1524 {
1525 m = atof(s);
1526 c = s[strlen(s)-1];
1527
1528 if (c == 'g' || c == 'G')
1529 m *= 1024*1024*1024;
1530 else if (c == 'm' || c == 'M')
1531 m *= 1024*1024;
1532 else if (c == 'k' || c == 'K')
1533 m *= 1024;
1534 else if (c == 'w' || c == 'W')
1535 m *= sizeof(W_);
1536 }
1537
1538 val = (StgWord64)m;
1539
1540 if (m < 0 || val < min || val > max) {
1541 // printf doesn't like 64-bit format specs on Windows
1542 // apparently, so fall back to unsigned long.
1543 errorBelch("error in RTS option %s: size outside allowed range (%" FMT_Word " - %" FMT_Word ")", flag, (W_)min, (W_)max);
1544 stg_exit(EXIT_FAILURE);
1545 }
1546
1547 return val;
1548 }
1549
1550 #if defined(TRACING)
1551 static void read_trace_flags(char *arg)
1552 {
1553 char *c;
1554 rtsBool enabled = rtsTrue;
1555 /* Syntax for tracing flags currently looks like:
1556 *
1557 * -l To turn on eventlog tracing with default trace classes
1558 * -lx Turn on class 'x' (for some class listed below)
1559 * -l-x Turn off class 'x'
1560 * -la Turn on all classes
1561 * -l-a Turn off all classes
1562 *
1563 * This lets users say things like:
1564 * -la-p "all but sparks"
1565 * -l-ap "only sparks"
1566 */
1567
1568 /* Start by turning on the default tracing flags.
1569 *
1570 * Currently this is all the trace classes, except full-detail sparks.
1571 * Similarly, in future we might default to slightly less verbose
1572 * scheduler or GC tracing.
1573 */
1574 RtsFlags.TraceFlags.scheduler = rtsTrue;
1575 RtsFlags.TraceFlags.gc = rtsTrue;
1576 RtsFlags.TraceFlags.sparks_sampled = rtsTrue;
1577 RtsFlags.TraceFlags.user = rtsTrue;
1578
1579 for (c = arg; *c != '\0'; c++) {
1580 switch(*c) {
1581 case '\0':
1582 break;
1583 case '-':
1584 enabled = rtsFalse;
1585 break;
1586 case 'a':
1587 RtsFlags.TraceFlags.scheduler = enabled;
1588 RtsFlags.TraceFlags.gc = enabled;
1589 RtsFlags.TraceFlags.sparks_sampled = enabled;
1590 RtsFlags.TraceFlags.sparks_full = enabled;
1591 RtsFlags.TraceFlags.user = enabled;
1592 enabled = rtsTrue;
1593 break;
1594
1595 case 's':
1596 RtsFlags.TraceFlags.scheduler = enabled;
1597 enabled = rtsTrue;
1598 break;
1599 case 'p':
1600 RtsFlags.TraceFlags.sparks_sampled = enabled;
1601 enabled = rtsTrue;
1602 break;
1603 case 'f':
1604 RtsFlags.TraceFlags.sparks_full = enabled;
1605 enabled = rtsTrue;
1606 break;
1607 case 't':
1608 RtsFlags.TraceFlags.timestamp = enabled;
1609 enabled = rtsTrue;
1610 break;
1611 case 'g':
1612 RtsFlags.TraceFlags.gc = enabled;
1613 enabled = rtsTrue;
1614 break;
1615 case 'u':
1616 RtsFlags.TraceFlags.user = enabled;
1617 enabled = rtsTrue;
1618 break;
1619 default:
1620 errorBelch("unknown trace option: %c",*c);
1621 break;
1622 }
1623 }
1624 }
1625 #endif
1626
1627 static void GNU_ATTRIBUTE(__noreturn__)
1628 bad_option(const char *s)
1629 {
1630 errorBelch("bad RTS option: %s", s);
1631 stg_exit(EXIT_FAILURE);
1632 }
1633
1634 /* ----------------------------------------------------------------------------
1635 Copying and freeing argc/argv
1636 ------------------------------------------------------------------------- */
1637
1638 static char * copyArg(char *arg)
1639 {
1640 char *new_arg = stgMallocBytes(strlen(arg) + 1, "copyArg");
1641 strcpy(new_arg, arg);
1642 return new_arg;
1643 }
1644
1645 static char ** copyArgv(int argc, char *argv[])
1646 {
1647 int i;
1648 char **new_argv;
1649
1650 new_argv = stgCallocBytes(argc + 1, sizeof (char *), "copyArgv 1");
1651 for (i = 0; i < argc; i++) {
1652 new_argv[i] = copyArg(argv[i]);
1653 }
1654 new_argv[argc] = NULL;
1655 return new_argv;
1656 }
1657
1658 static void freeArgv(int argc, char *argv[])
1659 {
1660 int i;
1661 if (argv != NULL) {
1662 for (i = 0; i < argc; i++) {
1663 stgFree(argv[i]);
1664 }
1665 stgFree(argv);
1666 }
1667 }
1668
1669 /* -----------------------------------------------------------------------------
1670 Getting/Setting the program's arguments.
1671
1672 These are used by System.Environment, and parts of the RTS.
1673 -------------------------------------------------------------------------- */
1674
1675 void
1676 setProgName(char *argv[])
1677 {
1678 char *last_slash;
1679
1680 if (argv[0] == NULL) { // #7037
1681 prog_name = "";
1682 return;
1683 }
1684
1685 /* Remove directory from argv[0] -- default files in current directory */
1686 #if !defined(mingw32_HOST_OS)
1687 if ( (last_slash = (char *) strrchr(argv[0], '/')) != NULL ) {
1688 prog_name = last_slash+1;
1689 } else {
1690 prog_name = argv[0];
1691 }
1692 #else
1693 last_slash = argv[0] + (strlen(argv[0]) - 1);
1694 while ( last_slash > argv[0] ) {
1695 if ( *last_slash == '/' || *last_slash == '\\' ) {
1696 prog_name = last_slash+1;
1697 return;
1698 }
1699 last_slash--;
1700 }
1701 prog_name = argv[0];
1702 #endif
1703 }
1704
1705 void
1706 getProgArgv(int *argc, char **argv[])
1707 {
1708 if (argc) { *argc = prog_argc; }
1709 if (argv) { *argv = prog_argv; }
1710 }
1711
1712 void
1713 setProgArgv(int argc, char *argv[])
1714 {
1715 prog_argc = argc;
1716 prog_argv = copyArgv(argc,argv);
1717 setProgName(prog_argv);
1718 }
1719
1720 static void
1721 freeProgArgv(void)
1722 {
1723 freeArgv(prog_argc,prog_argv);
1724 prog_argc = 0;
1725 prog_argv = NULL;
1726 }
1727
1728 /* ----------------------------------------------------------------------------
1729 The full argv - a copy of the original program's argc/argv
1730 ------------------------------------------------------------------------- */
1731
1732 void
1733 setFullProgArgv(int argc, char *argv[])
1734 {
1735 full_prog_argc = argc;
1736 full_prog_argv = copyArgv(argc,argv);
1737 }
1738
1739 /* These functions record and recall the full arguments, including the
1740 +RTS ... -RTS options. The reason for adding them was so that the
1741 ghc-inplace program can pass /all/ the arguments on to the real ghc. */
1742 void
1743 getFullProgArgv(int *argc, char **argv[])
1744 {
1745 if (argc) { *argc = full_prog_argc; }
1746 if (argv) { *argv = full_prog_argv; }
1747 }
1748
1749 void
1750 freeFullProgArgv (void)
1751 {
1752 freeArgv(full_prog_argc, full_prog_argv);
1753 full_prog_argc = 0;
1754 full_prog_argv = NULL;
1755 }
1756
1757 /* ----------------------------------------------------------------------------
1758 The Win32 argv
1759 ------------------------------------------------------------------------- */
1760
1761 #if defined(mingw32_HOST_OS)
1762 void freeWin32ProgArgv (void);
1763
1764 void
1765 freeWin32ProgArgv (void)
1766 {
1767 int i;
1768
1769 if (win32_prog_argv != NULL) {
1770 for (i = 0; i < win32_prog_argc; i++) {
1771 stgFree(win32_prog_argv[i]);
1772 }
1773 stgFree(win32_prog_argv);
1774 }
1775
1776 win32_prog_argc = 0;
1777 win32_prog_argv = NULL;
1778 }
1779
1780 void
1781 getWin32ProgArgv(int *argc, wchar_t **argv[])
1782 {
1783 *argc = win32_prog_argc;
1784 *argv = win32_prog_argv;
1785 }
1786
1787 void
1788 setWin32ProgArgv(int argc, wchar_t *argv[])
1789 {
1790 int i;
1791
1792 freeWin32ProgArgv();
1793
1794 win32_prog_argc = argc;
1795 if (argv == NULL) {
1796 win32_prog_argv = NULL;
1797 return;
1798 }
1799
1800 win32_prog_argv = stgCallocBytes(argc + 1, sizeof (wchar_t *),
1801 "setWin32ProgArgv 1");
1802 for (i = 0; i < argc; i++) {
1803 win32_prog_argv[i] = stgMallocBytes((wcslen(argv[i]) + 1) * sizeof(wchar_t),
1804 "setWin32ProgArgv 2");
1805 wcscpy(win32_prog_argv[i], argv[i]);
1806 }
1807 win32_prog_argv[argc] = NULL;
1808 }
1809 #endif
1810
1811 /* ----------------------------------------------------------------------------
1812 The RTS argv
1813 ------------------------------------------------------------------------- */
1814
1815 static void
1816 freeRtsArgv(void)
1817 {
1818 freeArgv(rts_argc,rts_argv);
1819 rts_argc = 0;
1820 rts_argv = NULL;
1821 rts_argv_size = 0;
1822 }
1823
1824 /* ----------------------------------------------------------------------------
1825 All argvs
1826 ------------------------------------------------------------------------- */
1827
1828 void freeRtsArgs(void)
1829 {
1830 #if defined(mingw32_HOST_OS)
1831 freeWin32ProgArgv();
1832 #endif
1833 freeFullProgArgv();
1834 freeProgArgv();
1835 freeRtsArgv();
1836 }