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