diff libgomp/env.c @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents f6334be47118
children 84e7813d76e9
line wrap: on
line diff
--- a/libgomp/env.c	Sun Aug 21 07:07:55 2011 +0900
+++ b/libgomp/env.c	Fri Oct 27 22:46:09 2017 +0900
@@ -1,8 +1,8 @@
-/* Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010
-   Free Software Foundation, Inc.
+/* Copyright (C) 2005-2017 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
-   This file is part of the GNU OpenMP Library (libgomp).
+   This file is part of the GNU Offloading and Multi Processing Library
+   (libgomp).
 
    Libgomp is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
@@ -23,13 +23,22 @@
    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
    <http://www.gnu.org/licenses/>.  */
 
-/* This file defines the OpenMP internal control variables, and arranges
+/* This file defines the OpenMP internal control variables and arranges
    for them to be initialized from environment variables at startup.  */
 
+#define _GNU_SOURCE
 #include "libgomp.h"
+#include "gomp-constants.h"
+#include <limits.h>
+#ifndef LIBGOMP_OFFLOADED_ONLY
 #include "libgomp_f.h"
+#include "oacc-int.h"
 #include <ctype.h>
 #include <stdlib.h>
+#include <stdio.h>
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>	/* For PRIu64.  */
+#endif
 #ifdef STRING_WITH_STRINGS
 # include <string.h>
 # include <strings.h>
@@ -42,31 +51,47 @@
 #  endif
 # endif
 #endif
-#include <limits.h>
 #include <errno.h>
+#include "thread-stacksize.h"
 
 #ifndef HAVE_STRTOULL
 # define strtoull(ptr, eptr, base) strtoul (ptr, eptr, base)
 #endif
+#endif /* LIBGOMP_OFFLOADED_ONLY */
+
+#include "secure_getenv.h"
 
 struct gomp_task_icv gomp_global_icv = {
   .nthreads_var = 1,
+  .thread_limit_var = UINT_MAX,
   .run_sched_var = GFS_DYNAMIC,
-  .run_sched_modifier = 1,
+  .run_sched_chunk_size = 1,
+  .default_device_var = 0,
   .dyn_var = false,
-  .nest_var = false
+  .nest_var = false,
+  .bind_var = omp_proc_bind_false,
+  .target_data = NULL
 };
 
-unsigned short *gomp_cpu_affinity;
-size_t gomp_cpu_affinity_len;
 unsigned long gomp_max_active_levels_var = INT_MAX;
-unsigned long gomp_thread_limit_var = ULONG_MAX;
-unsigned long gomp_remaining_threads_count;
+bool gomp_cancel_var = false;
+int gomp_max_task_priority_var = 0;
 #ifndef HAVE_SYNC_BUILTINS
-gomp_mutex_t gomp_remaining_threads_lock;
+gomp_mutex_t gomp_managed_threads_lock;
 #endif
 unsigned long gomp_available_cpus = 1, gomp_managed_threads = 1;
 unsigned long long gomp_spin_count_var, gomp_throttled_spin_count_var;
+unsigned long *gomp_nthreads_var_list, gomp_nthreads_var_list_len;
+char *gomp_bind_var_list;
+unsigned long gomp_bind_var_list_len;
+void **gomp_places_list;
+unsigned long gomp_places_list_len;
+int gomp_debug_var;
+unsigned int gomp_num_teams_var;
+char *goacc_device_type;
+int goacc_device_num;
+
+#ifndef LIBGOMP_OFFLOADED_ONLY
 
 /* Parse the OMP_SCHEDULE environment variable.  */
 
@@ -108,7 +133,11 @@
   while (isspace ((unsigned char) *env))
     ++env;
   if (*env == '\0')
-    return;
+    {
+      gomp_global_icv.run_sched_chunk_size
+	= gomp_global_icv.run_sched_var != GFS_STATIC;
+      return;
+    }
   if (*env++ != ',')
     goto unknown;
   while (isspace ((unsigned char) *env))
@@ -129,7 +158,9 @@
   if ((int)value != value)
     goto invalid;
 
-  gomp_global_icv.run_sched_modifier = value;
+  if (value == 0 && gomp_global_icv.run_sched_var != GFS_STATIC)
+    value = 1;
+  gomp_global_icv.run_sched_chunk_size = value;
   return;
 
  unknown:
@@ -143,15 +174,17 @@
 }
 
 /* Parse an unsigned long environment variable.  Return true if one was
-   present and it was successfully parsed.  */
+   present and it was successfully parsed.  If SECURE, use secure_getenv to the
+   environment variable.  */
 
 static bool
-parse_unsigned_long (const char *name, unsigned long *pvalue, bool allow_zero)
+parse_unsigned_long_1 (const char *name, unsigned long *pvalue, bool allow_zero,
+		       bool secure)
 {
   char *env, *end;
   unsigned long value;
 
-  env = getenv (name);
+  env = (secure ? secure_getenv (name) : getenv (name));
   if (env == NULL)
     return false;
 
@@ -178,6 +211,548 @@
   return false;
 }
 
+/* As parse_unsigned_long_1, but always use getenv.  */
+
+static bool
+parse_unsigned_long (const char *name, unsigned long *pvalue, bool allow_zero)
+{
+  return parse_unsigned_long_1 (name, pvalue, allow_zero, false);
+}
+
+/* Parse a positive int environment variable.  Return true if one was
+   present and it was successfully parsed.  If SECURE, use secure_getenv to the
+   environment variable.  */
+
+static bool
+parse_int_1 (const char *name, int *pvalue, bool allow_zero, bool secure)
+{
+  unsigned long value;
+  if (!parse_unsigned_long_1 (name, &value, allow_zero, secure))
+    return false;
+  if (value > INT_MAX)
+    {
+      gomp_error ("Invalid value for environment variable %s", name);
+      return false;
+    }
+  *pvalue = (int) value;
+  return true;
+}
+
+/* As parse_int_1, but use getenv.  */
+
+static bool
+parse_int (const char *name, int *pvalue, bool allow_zero)
+{
+  return parse_int_1 (name, pvalue, allow_zero, false);
+}
+
+/* As parse_int_1, but use getenv_secure.  */
+
+static bool
+parse_int_secure (const char *name, int *pvalue, bool allow_zero)
+{
+  return parse_int_1 (name, pvalue, allow_zero, true);
+}
+
+/* Parse an unsigned long list environment variable.  Return true if one was
+   present and it was successfully parsed.  */
+
+static bool
+parse_unsigned_long_list (const char *name, unsigned long *p1stvalue,
+			  unsigned long **pvalues,
+			  unsigned long *pnvalues)
+{
+  char *env, *end;
+  unsigned long value, *values = NULL;
+
+  env = getenv (name);
+  if (env == NULL)
+    return false;
+
+  while (isspace ((unsigned char) *env))
+    ++env;
+  if (*env == '\0')
+    goto invalid;
+
+  errno = 0;
+  value = strtoul (env, &end, 10);
+  if (errno || (long) value <= 0)
+    goto invalid;
+
+  while (isspace ((unsigned char) *end))
+    ++end;
+  if (*end != '\0')
+    {
+      if (*end == ',')
+	{
+	  unsigned long nvalues = 0, nalloced = 0;
+
+	  do
+	    {
+	      env = end + 1;
+	      if (nvalues == nalloced)
+		{
+		  unsigned long *n;
+		  nalloced = nalloced ? nalloced * 2 : 16;
+		  n = realloc (values, nalloced * sizeof (unsigned long));
+		  if (n == NULL)
+		    {
+		      free (values);
+		      gomp_error ("Out of memory while trying to parse"
+				  " environment variable %s", name);
+		      return false;
+		    }
+		  values = n;
+		  if (nvalues == 0)
+		    values[nvalues++] = value;
+		}
+
+	      while (isspace ((unsigned char) *env))
+		++env;
+	      if (*env == '\0')
+		goto invalid;
+
+	      errno = 0;
+	      value = strtoul (env, &end, 10);
+	      if (errno || (long) value <= 0)
+		goto invalid;
+
+	      values[nvalues++] = value;
+	      while (isspace ((unsigned char) *end))
+		++end;
+	      if (*end == '\0')
+		break;
+	      if (*end != ',')
+		goto invalid;
+	    }
+	  while (1);
+	  *p1stvalue = values[0];
+	  *pvalues = values;
+	  *pnvalues = nvalues;
+	  return true;
+	}
+      goto invalid;
+    }
+
+  *p1stvalue = value;
+  return true;
+
+ invalid:
+  free (values);
+  gomp_error ("Invalid value for environment variable %s", name);
+  return false;
+}
+
+/* Parse environment variable set to a boolean or list of omp_proc_bind_t
+   enum values.  Return true if one was present and it was successfully
+   parsed.  */
+
+static bool
+parse_bind_var (const char *name, char *p1stvalue,
+		char **pvalues, unsigned long *pnvalues)
+{
+  char *env;
+  char value = omp_proc_bind_false, *values = NULL;
+  int i;
+  static struct proc_bind_kinds
+  {
+    const char name[7];
+    const char len;
+    omp_proc_bind_t kind;
+  } kinds[] =
+  {
+    { "false", 5, omp_proc_bind_false },
+    { "true", 4, omp_proc_bind_true },
+    { "master", 6, omp_proc_bind_master },
+    { "close", 5, omp_proc_bind_close },
+    { "spread", 6, omp_proc_bind_spread }
+  };
+
+  env = getenv (name);
+  if (env == NULL)
+    return false;
+
+  while (isspace ((unsigned char) *env))
+    ++env;
+  if (*env == '\0')
+    goto invalid;
+
+  for (i = 0; i < 5; i++)
+    if (strncasecmp (env, kinds[i].name, kinds[i].len) == 0)
+      {
+	value = kinds[i].kind;
+	env += kinds[i].len;
+	break;
+      }
+  if (i == 5)
+    goto invalid;
+
+  while (isspace ((unsigned char) *env))
+    ++env;
+  if (*env != '\0')
+    {
+      if (*env == ',')
+	{
+	  unsigned long nvalues = 0, nalloced = 0;
+
+	  if (value == omp_proc_bind_false
+	      || value == omp_proc_bind_true)
+	    goto invalid;
+
+	  do
+	    {
+	      env++;
+	      if (nvalues == nalloced)
+		{
+		  char *n;
+		  nalloced = nalloced ? nalloced * 2 : 16;
+		  n = realloc (values, nalloced);
+		  if (n == NULL)
+		    {
+		      free (values);
+		      gomp_error ("Out of memory while trying to parse"
+				  " environment variable %s", name);
+		      return false;
+		    }
+		  values = n;
+		  if (nvalues == 0)
+		    values[nvalues++] = value;
+		}
+
+	      while (isspace ((unsigned char) *env))
+		++env;
+	      if (*env == '\0')
+		goto invalid;
+
+	      for (i = 2; i < 5; i++)
+		if (strncasecmp (env, kinds[i].name, kinds[i].len) == 0)
+		  {
+		    value = kinds[i].kind;
+		    env += kinds[i].len;
+		    break;
+		  }
+	      if (i == 5)
+		goto invalid;
+
+	      values[nvalues++] = value;
+	      while (isspace ((unsigned char) *env))
+		++env;
+	      if (*env == '\0')
+		break;
+	      if (*env != ',')
+		goto invalid;
+	    }
+	  while (1);
+	  *p1stvalue = values[0];
+	  *pvalues = values;
+	  *pnvalues = nvalues;
+	  return true;
+	}
+      goto invalid;
+    }
+
+  *p1stvalue = value;
+  return true;
+
+ invalid:
+  free (values);
+  gomp_error ("Invalid value for environment variable %s", name);
+  return false;
+}
+
+static bool
+parse_one_place (char **envp, bool *negatep, unsigned long *lenp,
+		 long *stridep)
+{
+  char *env = *envp, *start;
+  void *p = gomp_places_list ? gomp_places_list[gomp_places_list_len] : NULL;
+  unsigned long len = 1;
+  long stride = 1;
+  int pass;
+  bool any_negate = false;
+  *negatep = false;
+  while (isspace ((unsigned char) *env))
+    ++env;
+  if (*env == '!')
+    {
+      *negatep = true;
+      ++env;
+      while (isspace ((unsigned char) *env))
+	++env;
+    }
+  if (*env != '{')
+    return false;
+  ++env;
+  while (isspace ((unsigned char) *env))
+    ++env;
+  start = env;
+  for (pass = 0; pass < (any_negate ? 2 : 1); pass++)
+    {
+      env = start;
+      do
+	{
+	  unsigned long this_num, this_len = 1;
+	  long this_stride = 1;
+	  bool this_negate = (*env == '!');
+	  if (this_negate)
+	    {
+	      if (gomp_places_list)
+		any_negate = true;
+	      ++env;
+	      while (isspace ((unsigned char) *env))
+		++env;
+	    }
+
+	  errno = 0;
+	  this_num = strtoul (env, &env, 10);
+	  if (errno)
+	    return false;
+	  while (isspace ((unsigned char) *env))
+	    ++env;
+	  if (*env == ':')
+	    {
+	      ++env;
+	      while (isspace ((unsigned char) *env))
+		++env;
+	      errno = 0;
+	      this_len = strtoul (env, &env, 10);
+	      if (errno || this_len == 0)
+		return false;
+	      while (isspace ((unsigned char) *env))
+		++env;
+	      if (*env == ':')
+		{
+		  ++env;
+		  while (isspace ((unsigned char) *env))
+		    ++env;
+		  errno = 0;
+		  this_stride = strtol (env, &env, 10);
+		  if (errno)
+		    return false;
+		  while (isspace ((unsigned char) *env))
+		    ++env;
+		}
+	    }
+	  if (this_negate && this_len != 1)
+	    return false;
+	  if (gomp_places_list && pass == this_negate)
+	    {
+	      if (this_negate)
+		{
+		  if (!gomp_affinity_remove_cpu (p, this_num))
+		    return false;
+		}
+	      else if (!gomp_affinity_add_cpus (p, this_num, this_len,
+						this_stride, false))
+		return false;
+	    }
+	  if (*env == '}')
+	    break;
+	  if (*env != ',')
+	    return false;
+	  ++env;
+	}
+      while (1);
+    }
+
+  ++env;
+  while (isspace ((unsigned char) *env))
+    ++env;
+  if (*env == ':')
+    {
+      ++env;
+      while (isspace ((unsigned char) *env))
+	++env;
+      errno = 0;
+      len = strtoul (env, &env, 10);
+      if (errno || len == 0 || len >= 65536)
+	return false;
+      while (isspace ((unsigned char) *env))
+	++env;
+      if (*env == ':')
+	{
+	  ++env;
+	  while (isspace ((unsigned char) *env))
+	    ++env;
+	  errno = 0;
+	  stride = strtol (env, &env, 10);
+	  if (errno)
+	    return false;
+	  while (isspace ((unsigned char) *env))
+	    ++env;
+	}
+    }
+  if (*negatep && len != 1)
+    return false;
+  *envp = env;
+  *lenp = len;
+  *stridep = stride;
+  return true;
+}
+
+static bool
+parse_places_var (const char *name, bool ignore)
+{
+  char *env = getenv (name), *end;
+  bool any_negate = false;
+  int level = 0;
+  unsigned long count = 0;
+  if (env == NULL)
+    return false;
+
+  while (isspace ((unsigned char) *env))
+    ++env;
+  if (*env == '\0')
+    goto invalid;
+
+  if (strncasecmp (env, "threads", 7) == 0)
+    {
+      env += 7;
+      level = 1;
+    }
+  else if (strncasecmp (env, "cores", 5) == 0)
+    {
+      env += 5;
+      level = 2;
+    }
+  else if (strncasecmp (env, "sockets", 7) == 0)
+    {
+      env += 7;
+      level = 3;
+    }
+  if (level)
+    {
+      count = ULONG_MAX;
+      while (isspace ((unsigned char) *env))
+	++env;
+      if (*env != '\0')
+	{
+	  if (*env++ != '(')
+	    goto invalid;
+	  while (isspace ((unsigned char) *env))
+	    ++env;
+
+	  errno = 0;
+	  count = strtoul (env, &end, 10);
+	  if (errno)
+	    goto invalid;
+	  env = end;
+	  while (isspace ((unsigned char) *env))
+	    ++env;
+	  if (*env != ')')
+	    goto invalid;
+	  ++env;
+	  while (isspace ((unsigned char) *env))
+	    ++env;
+	  if (*env != '\0')
+	    goto invalid;
+	}
+
+      if (ignore)
+	return false;
+
+      return gomp_affinity_init_level (level, count, false);
+    }
+
+  count = 0;
+  end = env;
+  do
+    {
+      bool negate;
+      unsigned long len;
+      long stride;
+      if (!parse_one_place (&end, &negate, &len, &stride))
+	goto invalid;
+      if (negate)
+	{
+	  if (!any_negate)
+	    count++;
+	  any_negate = true;
+	}
+      else
+	count += len;
+      if (count > 65536)
+	goto invalid;
+      if (*end == '\0')
+	break;
+      if (*end != ',')
+	goto invalid;
+      end++;
+    }
+  while (1);
+
+  if (ignore)
+    return false;
+
+  gomp_places_list_len = 0;
+  gomp_places_list = gomp_affinity_alloc (count, false);
+  if (gomp_places_list == NULL)
+    return false;
+
+  do
+    {
+      bool negate;
+      unsigned long len;
+      long stride;
+      gomp_affinity_init_place (gomp_places_list[gomp_places_list_len]);
+      if (!parse_one_place (&env, &negate, &len, &stride))
+	goto invalid;
+      if (negate)
+	{
+	  void *p;
+	  for (count = 0; count < gomp_places_list_len; count++)
+	    if (gomp_affinity_same_place
+			(gomp_places_list[count],
+			 gomp_places_list[gomp_places_list_len]))
+	      break;
+	  if (count == gomp_places_list_len)
+	    {
+	      gomp_error ("Trying to remove a non-existing place from list "
+			  "of places");
+	      goto invalid;
+	    }
+	  p = gomp_places_list[count];
+	  memmove (&gomp_places_list[count],
+		   &gomp_places_list[count + 1],
+		   (gomp_places_list_len - count - 1) * sizeof (void *));
+	  --gomp_places_list_len;
+	  gomp_places_list[gomp_places_list_len] = p;
+	}
+      else if (len == 1)
+	++gomp_places_list_len;
+      else
+	{
+	  for (count = 0; count < len - 1; count++)
+	    if (!gomp_affinity_copy_place
+			(gomp_places_list[gomp_places_list_len + count + 1],
+			 gomp_places_list[gomp_places_list_len + count],
+			 stride))
+	      goto invalid;
+	  gomp_places_list_len += len;
+	}
+      if (*env == '\0')
+	break;
+      env++;
+    }
+  while (1);
+
+  if (gomp_places_list_len == 0)
+    {
+      gomp_error ("All places have been removed");
+      goto invalid;
+    }
+  if (!gomp_affinity_finalize_place_list (false))
+    goto invalid;
+  return true;
+
+ invalid:
+  free (gomp_places_list);
+  gomp_places_list = NULL;
+  gomp_places_list_len = 0;
+  gomp_error ("Invalid value for environment variable %s", name);
+  return false;
+}
+
 /* Parse the OMP_STACKSIZE environment varible.  Return true if one was
    present and it was successfully parsed.  */
 
@@ -383,86 +958,95 @@
    present and it was successfully parsed.  */
 
 static bool
-parse_affinity (void)
+parse_affinity (bool ignore)
 {
-  char *env, *end;
+  char *env, *end, *start;
+  int pass;
   unsigned long cpu_beg, cpu_end, cpu_stride;
-  unsigned short *cpus = NULL;
-  size_t allocated = 0, used = 0, needed;
+  size_t count = 0, needed;
 
   env = getenv ("GOMP_CPU_AFFINITY");
   if (env == NULL)
     return false;
 
-  do
+  start = env;
+  for (pass = 0; pass < 2; pass++)
     {
-      while (*env == ' ' || *env == '\t')
-	env++;
+      env = start;
+      if (pass == 1)
+	{
+	  if (ignore)
+	    return false;
 
-      cpu_beg = strtoul (env, &end, 0);
-      cpu_end = cpu_beg;
-      cpu_stride = 1;
-      if (env == end || cpu_beg >= 65536)
-	goto invalid;
+	  gomp_places_list_len = 0;
+	  gomp_places_list = gomp_affinity_alloc (count, true);
+	  if (gomp_places_list == NULL)
+	    return false;
+	}
+      do
+	{
+	  while (isspace ((unsigned char) *env))
+	    ++env;
 
-      env = end;
-      if (*env == '-')
-	{
-	  cpu_end = strtoul (++env, &end, 0);
-	  if (env == end || cpu_end >= 65536 || cpu_end < cpu_beg)
+	  errno = 0;
+	  cpu_beg = strtoul (env, &end, 0);
+	  if (errno || cpu_beg >= 65536)
 	    goto invalid;
+	  cpu_end = cpu_beg;
+	  cpu_stride = 1;
 
 	  env = end;
-	  if (*env == ':')
+	  if (*env == '-')
 	    {
-	      cpu_stride = strtoul (++env, &end, 0);
-	      if (env == end || cpu_stride == 0 || cpu_stride >= 65536)
+	      errno = 0;
+	      cpu_end = strtoul (++env, &end, 0);
+	      if (errno || cpu_end >= 65536 || cpu_end < cpu_beg)
 		goto invalid;
 
 	      env = end;
-	    }
-	}
-
-      needed = (cpu_end - cpu_beg) / cpu_stride + 1;
-      if (used + needed >= allocated)
-	{
-	  unsigned short *new_cpus;
+	      if (*env == ':')
+		{
+		  errno = 0;
+		  cpu_stride = strtoul (++env, &end, 0);
+		  if (errno || cpu_stride == 0 || cpu_stride >= 65536)
+		    goto invalid;
 
-	  if (allocated < 64)
-	    allocated = 64;
-	  if (allocated > needed)
-	    allocated <<= 1;
-	  else
-	    allocated += 2 * needed;
-	  new_cpus = realloc (cpus, allocated * sizeof (unsigned short));
-	  if (new_cpus == NULL)
-	    {
-	      free (cpus);
-	      gomp_error ("not enough memory to store GOMP_CPU_AFFINITY list");
-	      return false;
+		  env = end;
+		}
 	    }
 
-	  cpus = new_cpus;
-	}
-
-      while (needed--)
-	{
-	  cpus[used++] = cpu_beg;
-	  cpu_beg += cpu_stride;
-	}
+	  needed = (cpu_end - cpu_beg) / cpu_stride + 1;
+	  if (pass == 0)
+	    count += needed;
+	  else
+	    {
+	      while (needed--)
+		{
+		  void *p = gomp_places_list[gomp_places_list_len];
+		  gomp_affinity_init_place (p);
+		  if (gomp_affinity_add_cpus (p, cpu_beg, 1, 0, true))
+		    ++gomp_places_list_len;
+		  cpu_beg += cpu_stride;
+		}
+	    }
 
-      while (*env == ' ' || *env == '\t')
-	env++;
+	  while (isspace ((unsigned char) *env))
+	    ++env;
 
-      if (*env == ',')
-	env++;
-      else if (*env == '\0')
-	break;
+	  if (*env == ',')
+	    env++;
+	  else if (*env == '\0')
+	    break;
+	}
+      while (1);
     }
-  while (1);
 
-  gomp_cpu_affinity = cpus;
-  gomp_cpu_affinity_len = used;
+  if (gomp_places_list_len == 0)
+    {
+      free (gomp_places_list);
+      gomp_places_list = NULL;
+      return false;
+    }
   return true;
 
  invalid:
@@ -470,10 +1054,171 @@
   return false;
 }
 
+static void
+parse_acc_device_type (void)
+{
+  const char *env = getenv ("ACC_DEVICE_TYPE");
+
+  if (env && *env != '\0')
+    goacc_device_type = strdup (env);
+  else
+    goacc_device_type = NULL;
+}
+
+static void
+handle_omp_display_env (unsigned long stacksize, int wait_policy)
+{
+  const char *env;
+  bool display = false;
+  bool verbose = false;
+  int i;
+
+  env = getenv ("OMP_DISPLAY_ENV");
+  if (env == NULL)
+    return;
+
+  while (isspace ((unsigned char) *env))
+    ++env;
+  if (strncasecmp (env, "true", 4) == 0)
+    {
+      display = true;
+      env += 4;
+    }
+  else if (strncasecmp (env, "false", 5) == 0)
+    {
+      display = false;
+      env += 5;
+    }
+  else if (strncasecmp (env, "verbose", 7) == 0)
+    {
+      display = true;
+      verbose = true;
+      env += 7;
+    }
+  else
+    env = "X";
+  while (isspace ((unsigned char) *env))
+    ++env;
+  if (*env != '\0')
+    gomp_error ("Invalid value for environment variable OMP_DISPLAY_ENV");
+
+  if (!display)
+    return;
+
+  fputs ("\nOPENMP DISPLAY ENVIRONMENT BEGIN\n", stderr);
+
+  fputs ("  _OPENMP = '201511'\n", stderr);
+  fprintf (stderr, "  OMP_DYNAMIC = '%s'\n",
+	   gomp_global_icv.dyn_var ? "TRUE" : "FALSE");
+  fprintf (stderr, "  OMP_NESTED = '%s'\n",
+	   gomp_global_icv.nest_var ? "TRUE" : "FALSE");
+
+  fprintf (stderr, "  OMP_NUM_THREADS = '%lu", gomp_global_icv.nthreads_var);
+  for (i = 1; i < gomp_nthreads_var_list_len; i++)
+    fprintf (stderr, ",%lu", gomp_nthreads_var_list[i]);
+  fputs ("'\n", stderr);
+
+  fprintf (stderr, "  OMP_SCHEDULE = '");
+  switch (gomp_global_icv.run_sched_var)
+    {
+    case GFS_RUNTIME:
+      fputs ("RUNTIME", stderr);
+      break;
+    case GFS_STATIC:
+      fputs ("STATIC", stderr);
+      break;
+    case GFS_DYNAMIC:
+      fputs ("DYNAMIC", stderr);
+      break;
+    case GFS_GUIDED:
+      fputs ("GUIDED", stderr);
+      break;
+    case GFS_AUTO:
+      fputs ("AUTO", stderr);
+      break;
+    }
+  fputs ("'\n", stderr);
+
+  fputs ("  OMP_PROC_BIND = '", stderr);
+  switch (gomp_global_icv.bind_var)
+    {
+    case omp_proc_bind_false:
+      fputs ("FALSE", stderr);
+      break;
+    case omp_proc_bind_true:
+      fputs ("TRUE", stderr);
+      break;
+    case omp_proc_bind_master:
+      fputs ("MASTER", stderr);
+      break;
+    case omp_proc_bind_close:
+      fputs ("CLOSE", stderr);
+      break;
+    case omp_proc_bind_spread:
+      fputs ("SPREAD", stderr);
+      break;
+    }
+  for (i = 1; i < gomp_bind_var_list_len; i++)
+    switch (gomp_bind_var_list[i])
+      {
+      case omp_proc_bind_master:
+	fputs (",MASTER", stderr);
+	break;
+      case omp_proc_bind_close:
+	fputs (",CLOSE", stderr);
+	break;
+      case omp_proc_bind_spread:
+	fputs (",SPREAD", stderr);
+	break;
+      }
+  fputs ("'\n", stderr);
+  fputs ("  OMP_PLACES = '", stderr);
+  for (i = 0; i < gomp_places_list_len; i++)
+    {
+      fputs ("{", stderr);
+      gomp_affinity_print_place (gomp_places_list[i]);
+      fputs (i + 1 == gomp_places_list_len ? "}" : "},", stderr);
+    }
+  fputs ("'\n", stderr);
+
+  fprintf (stderr, "  OMP_STACKSIZE = '%lu'\n", stacksize);
+
+  /* GOMP's default value is actually neither active nor passive.  */
+  fprintf (stderr, "  OMP_WAIT_POLICY = '%s'\n",
+	   wait_policy > 0 ? "ACTIVE" : "PASSIVE");
+  fprintf (stderr, "  OMP_THREAD_LIMIT = '%u'\n",
+	   gomp_global_icv.thread_limit_var);
+  fprintf (stderr, "  OMP_MAX_ACTIVE_LEVELS = '%lu'\n",
+	   gomp_max_active_levels_var);
+
+  fprintf (stderr, "  OMP_CANCELLATION = '%s'\n",
+	   gomp_cancel_var ? "TRUE" : "FALSE");
+  fprintf (stderr, "  OMP_DEFAULT_DEVICE = '%d'\n",
+	   gomp_global_icv.default_device_var);
+  fprintf (stderr, "  OMP_MAX_TASK_PRIORITY = '%d'\n",
+	   gomp_max_task_priority_var);
+
+  if (verbose)
+    {
+      fputs ("  GOMP_CPU_AFFINITY = ''\n", stderr);
+      fprintf (stderr, "  GOMP_STACKSIZE = '%lu'\n", stacksize);
+#ifdef HAVE_INTTYPES_H
+      fprintf (stderr, "  GOMP_SPINCOUNT = '%"PRIu64"'\n",
+	       (uint64_t) gomp_spin_count_var);
+#else
+      fprintf (stderr, "  GOMP_SPINCOUNT = '%lu'\n",
+	       (unsigned long) gomp_spin_count_var);
+#endif
+    }
+
+  fputs ("OPENMP DISPLAY ENVIRONMENT END\n", stderr);
+}
+
+
 static void __attribute__((constructor))
 initialize_env (void)
 {
-  unsigned long stacksize;
+  unsigned long thread_limit_var, stacksize = GOMP_DEFAULT_STACKSIZE;
   int wait_policy;
 
   /* Do a compile time check that mkomp_h.pl did good job.  */
@@ -482,20 +1227,55 @@
   parse_schedule ();
   parse_boolean ("OMP_DYNAMIC", &gomp_global_icv.dyn_var);
   parse_boolean ("OMP_NESTED", &gomp_global_icv.nest_var);
+  parse_boolean ("OMP_CANCELLATION", &gomp_cancel_var);
+  parse_int ("OMP_DEFAULT_DEVICE", &gomp_global_icv.default_device_var, true);
+  parse_int ("OMP_MAX_TASK_PRIORITY", &gomp_max_task_priority_var, true);
   parse_unsigned_long ("OMP_MAX_ACTIVE_LEVELS", &gomp_max_active_levels_var,
 		       true);
-  parse_unsigned_long ("OMP_THREAD_LIMIT", &gomp_thread_limit_var, false);
-  if (gomp_thread_limit_var != ULONG_MAX)
-    gomp_remaining_threads_count = gomp_thread_limit_var - 1;
+  if (parse_unsigned_long ("OMP_THREAD_LIMIT", &thread_limit_var, false))
+    {
+      gomp_global_icv.thread_limit_var
+	= thread_limit_var > INT_MAX ? UINT_MAX : thread_limit_var;
+    }
+  parse_int_secure ("GOMP_DEBUG", &gomp_debug_var, true);
 #ifndef HAVE_SYNC_BUILTINS
-  gomp_mutex_init (&gomp_remaining_threads_lock);
+  gomp_mutex_init (&gomp_managed_threads_lock);
 #endif
   gomp_init_num_threads ();
   gomp_available_cpus = gomp_global_icv.nthreads_var;
-  if (!parse_unsigned_long ("OMP_NUM_THREADS", &gomp_global_icv.nthreads_var,
-			    false))
+  if (!parse_unsigned_long_list ("OMP_NUM_THREADS",
+				 &gomp_global_icv.nthreads_var,
+				 &gomp_nthreads_var_list,
+				 &gomp_nthreads_var_list_len))
     gomp_global_icv.nthreads_var = gomp_available_cpus;
-  if (parse_affinity ())
+  bool ignore = false;
+  if (parse_bind_var ("OMP_PROC_BIND",
+		      &gomp_global_icv.bind_var,
+		      &gomp_bind_var_list,
+		      &gomp_bind_var_list_len)
+      && gomp_global_icv.bind_var == omp_proc_bind_false)
+    ignore = true;
+  /* Make sure OMP_PLACES and GOMP_CPU_AFFINITY env vars are always
+     parsed if present in the environment.  If OMP_PROC_BIND was set
+     explictly to false, don't populate places list though.  If places
+     list was successfully set from OMP_PLACES, only parse but don't process
+     GOMP_CPU_AFFINITY.  If OMP_PROC_BIND was not set in the environment,
+     default to OMP_PROC_BIND=true if OMP_PLACES or GOMP_CPU_AFFINITY
+     was successfully parsed into a places list, otherwise to
+     OMP_PROC_BIND=false.  */
+  if (parse_places_var ("OMP_PLACES", ignore))
+    {
+      if (gomp_global_icv.bind_var == omp_proc_bind_false)
+	gomp_global_icv.bind_var = true;
+      ignore = true;
+    }
+  if (parse_affinity (ignore))
+    {
+      if (gomp_global_icv.bind_var == omp_proc_bind_false)
+	gomp_global_icv.bind_var = true;
+      ignore = true;
+    }
+  if (gomp_global_icv.bind_var != omp_proc_bind_false)
     gomp_init_affinity ();
   wait_policy = parse_wait_policy ();
   if (!parse_spincount ("GOMP_SPINCOUNT", &gomp_spin_count_var))
@@ -525,7 +1305,8 @@
   pthread_attr_setdetachstate (&gomp_thread_attr, PTHREAD_CREATE_DETACHED);
 
   if (parse_stacksize ("OMP_STACKSIZE", &stacksize)
-      || parse_stacksize ("GOMP_STACKSIZE", &stacksize))
+      || parse_stacksize ("GOMP_STACKSIZE", &stacksize)
+      || GOMP_DEFAULT_STACKSIZE)
     {
       int err;
 
@@ -546,113 +1327,16 @@
       if (err != 0)
 	gomp_error ("Stack size change failed: %s", strerror (err));
     }
-}
-
-
-/* The public OpenMP API routines that access these variables.  */
-
-void
-omp_set_num_threads (int n)
-{
-  struct gomp_task_icv *icv = gomp_icv (true);
-  icv->nthreads_var = (n > 0 ? n : 1);
-}
-
-void
-omp_set_dynamic (int val)
-{
-  struct gomp_task_icv *icv = gomp_icv (true);
-  icv->dyn_var = val;
-}
 
-int
-omp_get_dynamic (void)
-{
-  struct gomp_task_icv *icv = gomp_icv (false);
-  return icv->dyn_var;
-}
+  handle_omp_display_env (stacksize, wait_policy);
 
-void
-omp_set_nested (int val)
-{
-  struct gomp_task_icv *icv = gomp_icv (true);
-  icv->nest_var = val;
-}
-
-int
-omp_get_nested (void)
-{
-  struct gomp_task_icv *icv = gomp_icv (false);
-  return icv->nest_var;
-}
+  /* OpenACC.  */
 
-void
-omp_set_schedule (omp_sched_t kind, int modifier)
-{
-  struct gomp_task_icv *icv = gomp_icv (true);
-  switch (kind)
-    {
-    case omp_sched_static:
-      if (modifier < 1)
-	modifier = 0;
-      icv->run_sched_modifier = modifier;
-      break;
-    case omp_sched_dynamic:
-    case omp_sched_guided:
-      if (modifier < 1)
-	modifier = 1;
-      icv->run_sched_modifier = modifier;
-      break;
-    case omp_sched_auto:
-      break;
-    default:
-      return;
-    }
-  icv->run_sched_var = kind;
-}
-
-void
-omp_get_schedule (omp_sched_t *kind, int *modifier)
-{
-  struct gomp_task_icv *icv = gomp_icv (false);
-  *kind = icv->run_sched_var;
-  *modifier = icv->run_sched_modifier;
-}
+  if (!parse_int ("ACC_DEVICE_NUM", &goacc_device_num, true))
+    goacc_device_num = 0;
 
-int
-omp_get_max_threads (void)
-{
-  struct gomp_task_icv *icv = gomp_icv (false);
-  return icv->nthreads_var;
-}
+  parse_acc_device_type ();
 
-int
-omp_get_thread_limit (void)
-{
-  return gomp_thread_limit_var > INT_MAX ? INT_MAX : gomp_thread_limit_var;
-}
-
-void
-omp_set_max_active_levels (int max_levels)
-{
-  if (max_levels >= 0)
-    gomp_max_active_levels_var = max_levels;
+  goacc_runtime_initialize ();
 }
-
-int
-omp_get_max_active_levels (void)
-{
-  return gomp_max_active_levels_var;
-}
-
-ialias (omp_set_dynamic)
-ialias (omp_set_nested)
-ialias (omp_set_num_threads)
-ialias (omp_get_dynamic)
-ialias (omp_get_nested)
-ialias (omp_set_schedule)
-ialias (omp_get_schedule)
-ialias (omp_get_max_threads)
-ialias (omp_get_thread_limit)
-ialias (omp_set_max_active_levels)
-ialias (omp_get_max_active_levels)
+#endif /* LIBGOMP_OFFLOADED_ONLY */