Free full_prog_argv at exit, closing a memory leak
[ghc-hetmet.git] / rts / RtsFlags.c
index 397ea8b..19954f8 100644 (file)
@@ -51,7 +51,7 @@ open_stats_file (
     const char *FILENAME_FMT,
     FILE **file_ret);
 
-static I_ decode(const char *s);
+static StgWord64 decodeSize(const char *flag, nat offset, StgWord64 min, StgWord64 max);
 static void bad_option(const char *s);
 
 /* -----------------------------------------------------------------------------
@@ -70,6 +70,7 @@ void initRtsFlagsDefaults(void)
     RtsFlags.GcFlags.minOldGenSize      = (1024 * 1024)       / BLOCK_SIZE;
     RtsFlags.GcFlags.maxHeapSize       = 0;    /* off by default */
     RtsFlags.GcFlags.heapSizeSuggestion        = 0;    /* none */
+    RtsFlags.GcFlags.heapSizeSuggestionAuto = rtsFalse;
     RtsFlags.GcFlags.pcFreeHeap                = 3;    /* 3% */
     RtsFlags.GcFlags.oldGenFactor       = 2;
     RtsFlags.GcFlags.generations        = 2;
@@ -135,7 +136,7 @@ void initRtsFlagsDefaults(void)
 #endif
 
 #ifdef TRACING
-    RtsFlags.TraceFlags.trace_stderr  = rtsFalse;
+    RtsFlags.TraceFlags.tracing       = TRACE_NONE;
     RtsFlags.TraceFlags.timestamp     = rtsFalse;
     RtsFlags.TraceFlags.scheduler     = rtsFalse;
 #endif
@@ -531,12 +532,10 @@ error = rtsTrue;
                   }
                  break;
              case 'A':
-               RtsFlags.GcFlags.minAllocAreaSize
-                 = decode(rts_argv[arg]+2) / BLOCK_SIZE;
-               if (RtsFlags.GcFlags.minAllocAreaSize <= 0) {
-                 bad_option(rts_argv[arg]);
-               }
-               break;
+                  RtsFlags.GcFlags.minAllocAreaSize
+                      = decodeSize(rts_argv[arg], 2, BLOCK_SIZE, HS_INT_MAX)
+                           / BLOCK_SIZE;
+                  break;
 
 #ifdef USE_PAPI
              case 'a':
@@ -652,63 +651,53 @@ error = rtsTrue;
                  }
                   // -Dx also turns on -v.  Use -l to direct trace
                   // events to the .eventlog file instead.
-                  RtsFlags.TraceFlags.trace_stderr = rtsTrue;
+                  RtsFlags.TraceFlags.tracing = TRACE_STDERR;
                  break;
              }
 #endif
 
              case 'K':
-               RtsFlags.GcFlags.maxStkSize = 
-                 decode(rts_argv[arg]+2) / sizeof(W_);
-
-               if (RtsFlags.GcFlags.maxStkSize == 0) 
-                 bad_option( rts_argv[arg] );
-               break;
+                  RtsFlags.GcFlags.maxStkSize =
+                      decodeSize(rts_argv[arg], 2, 1, HS_WORD_MAX) / sizeof(W_);
+                  break;
 
              case 'k':
-               RtsFlags.GcFlags.initialStkSize = 
-                 decode(rts_argv[arg]+2) / sizeof(W_);
-
-               if (RtsFlags.GcFlags.initialStkSize == 0) 
-                 bad_option( rts_argv[arg] );
-               break;
+                  RtsFlags.GcFlags.initialStkSize =
+                      decodeSize(rts_argv[arg], 2, 1, HS_WORD_MAX) / sizeof(W_);
+                  break;
 
              case 'M':
-               RtsFlags.GcFlags.maxHeapSize = 
-                 decode(rts_argv[arg]+2) / BLOCK_SIZE;
-               /* user give size in *bytes* but "maxHeapSize" is in *blocks* */
-
-               if (RtsFlags.GcFlags.maxHeapSize <= 0) {
-                 bad_option(rts_argv[arg]);
-               }
-               break;
+                  RtsFlags.GcFlags.maxHeapSize =
+                      decodeSize(rts_argv[arg], 2, BLOCK_SIZE, HS_WORD_MAX) / BLOCK_SIZE;
+                  /* user give size in *bytes* but "maxHeapSize" is in *blocks* */
+                  break;
 
              case 'm':
-               RtsFlags.GcFlags.pcFreeHeap = atof(rts_argv[arg]+2);
+                  RtsFlags.GcFlags.pcFreeHeap = atof(rts_argv[arg]+2);
 
-               if (RtsFlags.GcFlags.pcFreeHeap < 0 || 
-                   RtsFlags.GcFlags.pcFreeHeap > 100)
-                 bad_option( rts_argv[arg] );
-               break;
+                  if (RtsFlags.GcFlags.pcFreeHeap < 0 ||
+                      RtsFlags.GcFlags.pcFreeHeap > 100)
+                      bad_option( rts_argv[arg] );
+                  break;
 
              case 'G':
-               RtsFlags.GcFlags.generations = decode(rts_argv[arg]+2);
-               if (RtsFlags.GcFlags.generations < 1) {
-                 bad_option(rts_argv[arg]);
-               }
-               break;
+                  RtsFlags.GcFlags.generations =
+                      decodeSize(rts_argv[arg], 2, 1, HS_INT_MAX);
+                  break;
 
-             case 'T':
-               RtsFlags.GcFlags.steps = decode(rts_argv[arg]+2);
-               if (RtsFlags.GcFlags.steps < 1) {
-                 bad_option(rts_argv[arg]);
-               }
+              case 'T':
+                  RtsFlags.GcFlags.steps =
+                      decodeSize(rts_argv[arg], 2, 1, HS_INT_MAX);
                break;
 
              case 'H':
-               RtsFlags.GcFlags.heapSizeSuggestion = 
-                 decode(rts_argv[arg]+2) / BLOCK_SIZE;
-               break;
+                  if (rts_argv[arg][2] == '\0') {
+                      RtsFlags.GcFlags.heapSizeSuggestionAuto = rtsTrue;
+                  } else {
+                      RtsFlags.GcFlags.heapSizeSuggestion =
+                          (nat)(decodeSize(rts_argv[arg], 2, BLOCK_SIZE, HS_WORD_MAX) / BLOCK_SIZE);
+                  }
+                  break;
 
 #ifdef RTS_GTK_FRONTPANEL
              case 'f':
@@ -760,20 +749,21 @@ error = rtsTrue;
 #ifdef TRACING
                 switch(rts_argv[arg][2]) {
                case '\0':
-                  RtsFlags.TraceFlags.trace_stderr = rtsFalse;
-                  break;
+                    RtsFlags.TraceFlags.tracing = TRACE_EVENTLOG;
+                    break;
                 case 's':
-                  RtsFlags.TraceFlags.scheduler = rtsTrue;
-                  break;
+                    RtsFlags.TraceFlags.tracing = TRACE_EVENTLOG;
+                    RtsFlags.TraceFlags.scheduler = rtsTrue;
+                    break;
                default:
                    errorBelch("unknown RTS option: %s",rts_argv[arg]);
                    error = rtsTrue;
                    break;
                 }
 #else
-                  errorBelch("not built for: -eventlog");
+                errorBelch("not built for: -eventlog");
 #endif
-                  break;
+                break;
 
              case 'P': /* detailed cost centre profiling (time/alloc) */
              case 'p': /* cost centre profiling (time/alloc) */
@@ -1080,7 +1070,7 @@ error = rtsTrue;
                 switch(rts_argv[arg][2]) {
 #ifdef TRACING
                 case '\0':
-                    RtsFlags.TraceFlags.trace_stderr = rtsTrue;
+                    RtsFlags.TraceFlags.tracing = TRACE_STDERR;
                     break;
                case 't':
                    RtsFlags.TraceFlags.timestamp = rtsTrue;
@@ -1277,28 +1267,44 @@ open_stats_file (
 
 
 
-static I_
-decode(const char *s)
+static StgWord64
+decodeSize(const char *flag, nat offset, StgWord64 min, StgWord64 max)
 {
-    I_ c;
+    char c;
+    const char *s;
     StgDouble m;
+    StgWord64 val;
+
+    s = flag + offset;
 
     if (!*s)
-       return 0;
+    {
+        m = 0;
+    }
+    else
+    {
+        m = atof(s);
+        c = s[strlen(s)-1];
+
+        if (c == 'g' || c == 'G') 
+            m *= 1024*1024*1024;
+        else if (c == 'm' || c == 'M')
+            m *= 1024*1024;
+        else if (c == 'k' || c == 'K')
+            m *= 1024;
+        else if (c == 'w' || c == 'W')
+            m *= sizeof(W_);
+    }
 
-    m = atof(s);
-    c = s[strlen(s)-1];
+    val = (StgWord64)m;
 
-    if (c == 'g' || c == 'G')
-       m *= 1000*1000*1000;    /* UNchecked! */
-    else if (c == 'm' || c == 'M')
-       m *= 1000*1000;                 /* We do not use powers of 2 (1024) */
-    else if (c == 'k' || c == 'K')     /* to avoid possible bad effects on */
-       m *= 1000;                      /* a direct-mapped cache.           */ 
-    else if (c == 'w' || c == 'W')
-       m *= sizeof(W_);
+    if (m < 0 || val < min || val > max) {
+        errorBelch("error in RTS option %s: size outside allowed range (%" FMT_Word64 " - %" FMT_Word64 ")", 
+                   flag, min, max);
+        stg_exit(EXIT_FAILURE);
+    }
 
-    return (I_)m;
+    return val;
 }
 
 static void GNU_ATTRIBUTE(__noreturn__)
@@ -1383,3 +1389,18 @@ setFullProgArgv(int argc, char *argv[])
     full_prog_argv[argc] = NULL;
 }
 
+void
+freeFullProgArgv (void)
+{
+    int i;
+
+    if (full_prog_argv != NULL) {
+        for (i = 0; i < full_prog_argc; i++) {
+            stgFree(full_prog_argv[i]);
+        }
+        stgFree(full_prog_argv);
+    }
+
+    full_prog_argc = 0;
+    full_prog_argv = NULL;
+}