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