1/* Copyright (C) 2005-2020 Free Software Foundation, Inc.
2   Contributed by Richard Henderson <rth@redhat.com>.
3
4   This file is part of the GNU Offloading and Multi Processing Library
5   (libgomp).
6
7   Libgomp is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 3, or (at your option)
10   any later version.
11
12   Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
13   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14   FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15   more details.
16
17   Under Section 7 of GPL version 3, you are granted additional
18   permissions described in the GCC Runtime Library Exception, version
19   3.1, as published by the Free Software Foundation.
20
21   You should have received a copy of the GNU General Public License and
22   a copy of the GCC Runtime Library Exception along with this program;
23   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24   <http://www.gnu.org/licenses/>.  */
25
26/* This file defines the OpenMP internal control variables and arranges
27   for them to be initialized from environment variables at startup.  */
28
29#define _GNU_SOURCE
30#include "libgomp.h"
31#include "gomp-constants.h"
32#include <limits.h>
33#ifndef LIBGOMP_OFFLOADED_ONLY
34#include "libgomp_f.h"
35#include "oacc-int.h"
36#include <ctype.h>
37#include <stdlib.h>
38#include <stdio.h>
39#ifdef HAVE_INTTYPES_H
40# include <inttypes.h>	/* For PRIu64.  */
41#endif
42#ifdef STRING_WITH_STRINGS
43# include <string.h>
44# include <strings.h>
45#else
46# ifdef HAVE_STRING_H
47#  include <string.h>
48# else
49#  ifdef HAVE_STRINGS_H
50#   include <strings.h>
51#  endif
52# endif
53#endif
54#include <errno.h>
55#include "thread-stacksize.h"
56
57#ifndef HAVE_STRTOULL
58# define strtoull(ptr, eptr, base) strtoul (ptr, eptr, base)
59#endif
60#endif /* LIBGOMP_OFFLOADED_ONLY */
61
62#include "secure_getenv.h"
63
64struct gomp_task_icv gomp_global_icv = {
65  .nthreads_var = 1,
66  .thread_limit_var = UINT_MAX,
67  .run_sched_var = GFS_DYNAMIC,
68  .run_sched_chunk_size = 1,
69  .default_device_var = 0,
70  .dyn_var = false,
71  .nest_var = false,
72  .bind_var = omp_proc_bind_false,
73  .target_data = NULL
74};
75
76unsigned long gomp_max_active_levels_var = INT_MAX;
77bool gomp_cancel_var = false;
78int gomp_max_task_priority_var = 0;
79#ifndef HAVE_SYNC_BUILTINS
80gomp_mutex_t gomp_managed_threads_lock;
81#endif
82unsigned long gomp_available_cpus = 1, gomp_managed_threads = 1;
83unsigned long long gomp_spin_count_var, gomp_throttled_spin_count_var;
84unsigned long *gomp_nthreads_var_list, gomp_nthreads_var_list_len;
85char *gomp_bind_var_list;
86unsigned long gomp_bind_var_list_len;
87void **gomp_places_list;
88unsigned long gomp_places_list_len;
89int gomp_debug_var;
90unsigned int gomp_num_teams_var;
91bool gomp_display_affinity_var;
92char *gomp_affinity_format_var = "level %L thread %i affinity %A";
93size_t gomp_affinity_format_len;
94char *goacc_device_type;
95int goacc_device_num;
96int goacc_default_dims[GOMP_DIM_MAX];
97
98#ifndef LIBGOMP_OFFLOADED_ONLY
99
100/* Parse the OMP_SCHEDULE environment variable.  */
101
102static void
103parse_schedule (void)
104{
105  char *env, *end;
106  unsigned long value;
107  int monotonic = 0;
108
109  env = getenv ("OMP_SCHEDULE");
110  if (env == NULL)
111    return;
112
113  while (isspace ((unsigned char) *env))
114    ++env;
115  if (strncasecmp (env, "monotonic", 9) == 0)
116    {
117      monotonic = 1;
118      env += 9;
119    }
120  else if (strncasecmp (env, "nonmonotonic", 12) == 0)
121    {
122      monotonic = -1;
123      env += 12;
124    }
125  if (monotonic)
126    {
127      while (isspace ((unsigned char) *env))
128	++env;
129      if (*env != ':')
130	goto unknown;
131      ++env;
132      while (isspace ((unsigned char) *env))
133	++env;
134    }
135  if (strncasecmp (env, "static", 6) == 0)
136    {
137      gomp_global_icv.run_sched_var = GFS_STATIC;
138      env += 6;
139    }
140  else if (strncasecmp (env, "dynamic", 7) == 0)
141    {
142      gomp_global_icv.run_sched_var = GFS_DYNAMIC;
143      env += 7;
144    }
145  else if (strncasecmp (env, "guided", 6) == 0)
146    {
147      gomp_global_icv.run_sched_var = GFS_GUIDED;
148      env += 6;
149    }
150  else if (strncasecmp (env, "auto", 4) == 0)
151    {
152      gomp_global_icv.run_sched_var = GFS_AUTO;
153      env += 4;
154    }
155  else
156    goto unknown;
157
158  if (monotonic == 1
159      || (monotonic == 0 && gomp_global_icv.run_sched_var == GFS_STATIC))
160    gomp_global_icv.run_sched_var |= GFS_MONOTONIC;
161
162  while (isspace ((unsigned char) *env))
163    ++env;
164  if (*env == '\0')
165    {
166      gomp_global_icv.run_sched_chunk_size
167	= (gomp_global_icv.run_sched_var & ~GFS_MONOTONIC) != GFS_STATIC;
168      return;
169    }
170  if (*env++ != ',')
171    goto unknown;
172  while (isspace ((unsigned char) *env))
173    ++env;
174  if (*env == '\0')
175    goto invalid;
176
177  errno = 0;
178  value = strtoul (env, &end, 10);
179  if (errno)
180    goto invalid;
181
182  while (isspace ((unsigned char) *end))
183    ++end;
184  if (*end != '\0')
185    goto invalid;
186
187  if ((int)value != value)
188    goto invalid;
189
190  if (value == 0
191      && (gomp_global_icv.run_sched_var & ~GFS_MONOTONIC) != GFS_STATIC)
192    value = 1;
193  gomp_global_icv.run_sched_chunk_size = value;
194  return;
195
196 unknown:
197  gomp_error ("Unknown value for environment variable OMP_SCHEDULE");
198  return;
199
200 invalid:
201  gomp_error ("Invalid value for chunk size in "
202	      "environment variable OMP_SCHEDULE");
203  return;
204}
205
206/* Parse an unsigned long environment variable.  Return true if one was
207   present and it was successfully parsed.  If SECURE, use secure_getenv to the
208   environment variable.  */
209
210static bool
211parse_unsigned_long_1 (const char *name, unsigned long *pvalue, bool allow_zero,
212		       bool secure)
213{
214  char *env, *end;
215  unsigned long value;
216
217  env = (secure ? secure_getenv (name) : getenv (name));
218  if (env == NULL)
219    return false;
220
221  while (isspace ((unsigned char) *env))
222    ++env;
223  if (*env == '\0')
224    goto invalid;
225
226  errno = 0;
227  value = strtoul (env, &end, 10);
228  if (errno || (long) value <= 0 - allow_zero)
229    goto invalid;
230
231  while (isspace ((unsigned char) *end))
232    ++end;
233  if (*end != '\0')
234    goto invalid;
235
236  *pvalue = value;
237  return true;
238
239 invalid:
240  gomp_error ("Invalid value for environment variable %s", name);
241  return false;
242}
243
244/* As parse_unsigned_long_1, but always use getenv.  */
245
246static bool
247parse_unsigned_long (const char *name, unsigned long *pvalue, bool allow_zero)
248{
249  return parse_unsigned_long_1 (name, pvalue, allow_zero, false);
250}
251
252/* Parse a positive int environment variable.  Return true if one was
253   present and it was successfully parsed.  If SECURE, use secure_getenv to the
254   environment variable.  */
255
256static bool
257parse_int_1 (const char *name, int *pvalue, bool allow_zero, bool secure)
258{
259  unsigned long value;
260  if (!parse_unsigned_long_1 (name, &value, allow_zero, secure))
261    return false;
262  if (value > INT_MAX)
263    {
264      gomp_error ("Invalid value for environment variable %s", name);
265      return false;
266    }
267  *pvalue = (int) value;
268  return true;
269}
270
271/* As parse_int_1, but use getenv.  */
272
273static bool
274parse_int (const char *name, int *pvalue, bool allow_zero)
275{
276  return parse_int_1 (name, pvalue, allow_zero, false);
277}
278
279/* As parse_int_1, but use getenv_secure.  */
280
281static bool
282parse_int_secure (const char *name, int *pvalue, bool allow_zero)
283{
284  return parse_int_1 (name, pvalue, allow_zero, true);
285}
286
287/* Parse an unsigned long list environment variable.  Return true if one was
288   present and it was successfully parsed.  */
289
290static bool
291parse_unsigned_long_list (const char *name, unsigned long *p1stvalue,
292			  unsigned long **pvalues,
293			  unsigned long *pnvalues)
294{
295  char *env, *end;
296  unsigned long value, *values = NULL;
297
298  env = getenv (name);
299  if (env == NULL)
300    return false;
301
302  while (isspace ((unsigned char) *env))
303    ++env;
304  if (*env == '\0')
305    goto invalid;
306
307  errno = 0;
308  value = strtoul (env, &end, 10);
309  if (errno || (long) value <= 0)
310    goto invalid;
311
312  while (isspace ((unsigned char) *end))
313    ++end;
314  if (*end != '\0')
315    {
316      if (*end == ',')
317	{
318	  unsigned long nvalues = 0, nalloced = 0;
319
320	  do
321	    {
322	      env = end + 1;
323	      if (nvalues == nalloced)
324		{
325		  unsigned long *n;
326		  nalloced = nalloced ? nalloced * 2 : 16;
327		  n = realloc (values, nalloced * sizeof (unsigned long));
328		  if (n == NULL)
329		    {
330		      free (values);
331		      gomp_error ("Out of memory while trying to parse"
332				  " environment variable %s", name);
333		      return false;
334		    }
335		  values = n;
336		  if (nvalues == 0)
337		    values[nvalues++] = value;
338		}
339
340	      while (isspace ((unsigned char) *env))
341		++env;
342	      if (*env == '\0')
343		goto invalid;
344
345	      errno = 0;
346	      value = strtoul (env, &end, 10);
347	      if (errno || (long) value <= 0)
348		goto invalid;
349
350	      values[nvalues++] = value;
351	      while (isspace ((unsigned char) *end))
352		++end;
353	      if (*end == '\0')
354		break;
355	      if (*end != ',')
356		goto invalid;
357	    }
358	  while (1);
359	  *p1stvalue = values[0];
360	  *pvalues = values;
361	  *pnvalues = nvalues;
362	  return true;
363	}
364      goto invalid;
365    }
366
367  *p1stvalue = value;
368  return true;
369
370 invalid:
371  free (values);
372  gomp_error ("Invalid value for environment variable %s", name);
373  return false;
374}
375
376/* Parse environment variable set to a boolean or list of omp_proc_bind_t
377   enum values.  Return true if one was present and it was successfully
378   parsed.  */
379
380static bool
381parse_bind_var (const char *name, char *p1stvalue,
382		char **pvalues, unsigned long *pnvalues)
383{
384  char *env;
385  char value = omp_proc_bind_false, *values = NULL;
386  int i;
387  static struct proc_bind_kinds
388  {
389    const char name[7];
390    const char len;
391    omp_proc_bind_t kind;
392  } kinds[] =
393  {
394    { "false", 5, omp_proc_bind_false },
395    { "true", 4, omp_proc_bind_true },
396    { "master", 6, omp_proc_bind_master },
397    { "close", 5, omp_proc_bind_close },
398    { "spread", 6, omp_proc_bind_spread }
399  };
400
401  env = getenv (name);
402  if (env == NULL)
403    return false;
404
405  while (isspace ((unsigned char) *env))
406    ++env;
407  if (*env == '\0')
408    goto invalid;
409
410  for (i = 0; i < 5; i++)
411    if (strncasecmp (env, kinds[i].name, kinds[i].len) == 0)
412      {
413	value = kinds[i].kind;
414	env += kinds[i].len;
415	break;
416      }
417  if (i == 5)
418    goto invalid;
419
420  while (isspace ((unsigned char) *env))
421    ++env;
422  if (*env != '\0')
423    {
424      if (*env == ',')
425	{
426	  unsigned long nvalues = 0, nalloced = 0;
427
428	  if (value == omp_proc_bind_false
429	      || value == omp_proc_bind_true)
430	    goto invalid;
431
432	  do
433	    {
434	      env++;
435	      if (nvalues == nalloced)
436		{
437		  char *n;
438		  nalloced = nalloced ? nalloced * 2 : 16;
439		  n = realloc (values, nalloced);
440		  if (n == NULL)
441		    {
442		      free (values);
443		      gomp_error ("Out of memory while trying to parse"
444				  " environment variable %s", name);
445		      return false;
446		    }
447		  values = n;
448		  if (nvalues == 0)
449		    values[nvalues++] = value;
450		}
451
452	      while (isspace ((unsigned char) *env))
453		++env;
454	      if (*env == '\0')
455		goto invalid;
456
457	      for (i = 2; i < 5; i++)
458		if (strncasecmp (env, kinds[i].name, kinds[i].len) == 0)
459		  {
460		    value = kinds[i].kind;
461		    env += kinds[i].len;
462		    break;
463		  }
464	      if (i == 5)
465		goto invalid;
466
467	      values[nvalues++] = value;
468	      while (isspace ((unsigned char) *env))
469		++env;
470	      if (*env == '\0')
471		break;
472	      if (*env != ',')
473		goto invalid;
474	    }
475	  while (1);
476	  *p1stvalue = values[0];
477	  *pvalues = values;
478	  *pnvalues = nvalues;
479	  return true;
480	}
481      goto invalid;
482    }
483
484  *p1stvalue = value;
485  return true;
486
487 invalid:
488  free (values);
489  gomp_error ("Invalid value for environment variable %s", name);
490  return false;
491}
492
493static bool
494parse_one_place (char **envp, bool *negatep, unsigned long *lenp,
495		 long *stridep)
496{
497  char *env = *envp, *start;
498  void *p = gomp_places_list ? gomp_places_list[gomp_places_list_len] : NULL;
499  unsigned long len = 1;
500  long stride = 1;
501  int pass;
502  bool any_negate = false;
503  *negatep = false;
504  while (isspace ((unsigned char) *env))
505    ++env;
506  if (*env == '!')
507    {
508      *negatep = true;
509      ++env;
510      while (isspace ((unsigned char) *env))
511	++env;
512    }
513  if (*env != '{')
514    return false;
515  ++env;
516  while (isspace ((unsigned char) *env))
517    ++env;
518  start = env;
519  for (pass = 0; pass < (any_negate ? 2 : 1); pass++)
520    {
521      env = start;
522      do
523	{
524	  unsigned long this_num, this_len = 1;
525	  long this_stride = 1;
526	  bool this_negate = (*env == '!');
527	  if (this_negate)
528	    {
529	      if (gomp_places_list)
530		any_negate = true;
531	      ++env;
532	      while (isspace ((unsigned char) *env))
533		++env;
534	    }
535
536	  errno = 0;
537	  this_num = strtoul (env, &env, 10);
538	  if (errno)
539	    return false;
540	  while (isspace ((unsigned char) *env))
541	    ++env;
542	  if (*env == ':')
543	    {
544	      ++env;
545	      while (isspace ((unsigned char) *env))
546		++env;
547	      errno = 0;
548	      this_len = strtoul (env, &env, 10);
549	      if (errno || this_len == 0)
550		return false;
551	      while (isspace ((unsigned char) *env))
552		++env;
553	      if (*env == ':')
554		{
555		  ++env;
556		  while (isspace ((unsigned char) *env))
557		    ++env;
558		  errno = 0;
559		  this_stride = strtol (env, &env, 10);
560		  if (errno)
561		    return false;
562		  while (isspace ((unsigned char) *env))
563		    ++env;
564		}
565	    }
566	  if (this_negate && this_len != 1)
567	    return false;
568	  if (gomp_places_list && pass == this_negate)
569	    {
570	      if (this_negate)
571		{
572		  if (!gomp_affinity_remove_cpu (p, this_num))
573		    return false;
574		}
575	      else if (!gomp_affinity_add_cpus (p, this_num, this_len,
576						this_stride, false))
577		return false;
578	    }
579	  if (*env == '}')
580	    break;
581	  if (*env != ',')
582	    return false;
583	  ++env;
584	}
585      while (1);
586    }
587
588  ++env;
589  while (isspace ((unsigned char) *env))
590    ++env;
591  if (*env == ':')
592    {
593      ++env;
594      while (isspace ((unsigned char) *env))
595	++env;
596      errno = 0;
597      len = strtoul (env, &env, 10);
598      if (errno || len == 0 || len >= 65536)
599	return false;
600      while (isspace ((unsigned char) *env))
601	++env;
602      if (*env == ':')
603	{
604	  ++env;
605	  while (isspace ((unsigned char) *env))
606	    ++env;
607	  errno = 0;
608	  stride = strtol (env, &env, 10);
609	  if (errno)
610	    return false;
611	  while (isspace ((unsigned char) *env))
612	    ++env;
613	}
614    }
615  if (*negatep && len != 1)
616    return false;
617  *envp = env;
618  *lenp = len;
619  *stridep = stride;
620  return true;
621}
622
623static bool
624parse_places_var (const char *name, bool ignore)
625{
626  char *env = getenv (name), *end;
627  bool any_negate = false;
628  int level = 0;
629  unsigned long count = 0;
630  if (env == NULL)
631    return false;
632
633  while (isspace ((unsigned char) *env))
634    ++env;
635  if (*env == '\0')
636    goto invalid;
637
638  if (strncasecmp (env, "threads", 7) == 0)
639    {
640      env += 7;
641      level = 1;
642    }
643  else if (strncasecmp (env, "cores", 5) == 0)
644    {
645      env += 5;
646      level = 2;
647    }
648  else if (strncasecmp (env, "sockets", 7) == 0)
649    {
650      env += 7;
651      level = 3;
652    }
653  if (level)
654    {
655      count = ULONG_MAX;
656      while (isspace ((unsigned char) *env))
657	++env;
658      if (*env != '\0')
659	{
660	  if (*env++ != '(')
661	    goto invalid;
662	  while (isspace ((unsigned char) *env))
663	    ++env;
664
665	  errno = 0;
666	  count = strtoul (env, &end, 10);
667	  if (errno)
668	    goto invalid;
669	  env = end;
670	  while (isspace ((unsigned char) *env))
671	    ++env;
672	  if (*env != ')')
673	    goto invalid;
674	  ++env;
675	  while (isspace ((unsigned char) *env))
676	    ++env;
677	  if (*env != '\0')
678	    goto invalid;
679	}
680
681      if (ignore)
682	return false;
683
684      return gomp_affinity_init_level (level, count, false);
685    }
686
687  count = 0;
688  end = env;
689  do
690    {
691      bool negate;
692      unsigned long len;
693      long stride;
694      if (!parse_one_place (&end, &negate, &len, &stride))
695	goto invalid;
696      if (negate)
697	{
698	  if (!any_negate)
699	    count++;
700	  any_negate = true;
701	}
702      else
703	count += len;
704      if (count > 65536)
705	goto invalid;
706      if (*end == '\0')
707	break;
708      if (*end != ',')
709	goto invalid;
710      end++;
711    }
712  while (1);
713
714  if (ignore)
715    return false;
716
717  gomp_places_list_len = 0;
718  gomp_places_list = gomp_affinity_alloc (count, false);
719  if (gomp_places_list == NULL)
720    return false;
721
722  do
723    {
724      bool negate;
725      unsigned long len;
726      long stride;
727      gomp_affinity_init_place (gomp_places_list[gomp_places_list_len]);
728      if (!parse_one_place (&env, &negate, &len, &stride))
729	goto invalid;
730      if (negate)
731	{
732	  void *p;
733	  for (count = 0; count < gomp_places_list_len; count++)
734	    if (gomp_affinity_same_place
735			(gomp_places_list[count],
736			 gomp_places_list[gomp_places_list_len]))
737	      break;
738	  if (count == gomp_places_list_len)
739	    {
740	      gomp_error ("Trying to remove a non-existing place from list "
741			  "of places");
742	      goto invalid;
743	    }
744	  p = gomp_places_list[count];
745	  memmove (&gomp_places_list[count],
746		   &gomp_places_list[count + 1],
747		   (gomp_places_list_len - count - 1) * sizeof (void *));
748	  --gomp_places_list_len;
749	  gomp_places_list[gomp_places_list_len] = p;
750	}
751      else if (len == 1)
752	++gomp_places_list_len;
753      else
754	{
755	  for (count = 0; count < len - 1; count++)
756	    if (!gomp_affinity_copy_place
757			(gomp_places_list[gomp_places_list_len + count + 1],
758			 gomp_places_list[gomp_places_list_len + count],
759			 stride))
760	      goto invalid;
761	  gomp_places_list_len += len;
762	}
763      if (*env == '\0')
764	break;
765      env++;
766    }
767  while (1);
768
769  if (gomp_places_list_len == 0)
770    {
771      gomp_error ("All places have been removed");
772      goto invalid;
773    }
774  if (!gomp_affinity_finalize_place_list (false))
775    goto invalid;
776  return true;
777
778 invalid:
779  free (gomp_places_list);
780  gomp_places_list = NULL;
781  gomp_places_list_len = 0;
782  gomp_error ("Invalid value for environment variable %s", name);
783  return false;
784}
785
786/* Parse the OMP_STACKSIZE environment varible.  Return true if one was
787   present and it was successfully parsed.  */
788
789static bool
790parse_stacksize (const char *name, unsigned long *pvalue)
791{
792  char *env, *end;
793  unsigned long value, shift = 10;
794
795  env = getenv (name);
796  if (env == NULL)
797    return false;
798
799  while (isspace ((unsigned char) *env))
800    ++env;
801  if (*env == '\0')
802    goto invalid;
803
804  errno = 0;
805  value = strtoul (env, &end, 10);
806  if (errno)
807    goto invalid;
808
809  while (isspace ((unsigned char) *end))
810    ++end;
811  if (*end != '\0')
812    {
813      switch (tolower ((unsigned char) *end))
814	{
815	case 'b':
816	  shift = 0;
817	  break;
818	case 'k':
819	  break;
820	case 'm':
821	  shift = 20;
822	  break;
823	case 'g':
824	  shift = 30;
825	  break;
826	default:
827	  goto invalid;
828	}
829      ++end;
830      while (isspace ((unsigned char) *end))
831	++end;
832      if (*end != '\0')
833	goto invalid;
834    }
835
836  if (((value << shift) >> shift) != value)
837    goto invalid;
838
839  *pvalue = value << shift;
840  return true;
841
842 invalid:
843  gomp_error ("Invalid value for environment variable %s", name);
844  return false;
845}
846
847/* Parse the GOMP_SPINCOUNT environment varible.  Return true if one was
848   present and it was successfully parsed.  */
849
850static bool
851parse_spincount (const char *name, unsigned long long *pvalue)
852{
853  char *env, *end;
854  unsigned long long value, mult = 1;
855
856  env = getenv (name);
857  if (env == NULL)
858    return false;
859
860  while (isspace ((unsigned char) *env))
861    ++env;
862  if (*env == '\0')
863    goto invalid;
864
865  if (strncasecmp (env, "infinite", 8) == 0
866      || strncasecmp (env, "infinity", 8) == 0)
867    {
868      value = ~0ULL;
869      end = env + 8;
870      goto check_tail;
871    }
872
873  errno = 0;
874  value = strtoull (env, &end, 10);
875  if (errno)
876    goto invalid;
877
878  while (isspace ((unsigned char) *end))
879    ++end;
880  if (*end != '\0')
881    {
882      switch (tolower ((unsigned char) *end))
883	{
884	case 'k':
885	  mult = 1000LL;
886	  break;
887	case 'm':
888	  mult = 1000LL * 1000LL;
889	  break;
890	case 'g':
891	  mult = 1000LL * 1000LL * 1000LL;
892	  break;
893	case 't':
894	  mult = 1000LL * 1000LL * 1000LL * 1000LL;
895	  break;
896	default:
897	  goto invalid;
898	}
899      ++end;
900     check_tail:
901      while (isspace ((unsigned char) *end))
902	++end;
903      if (*end != '\0')
904	goto invalid;
905    }
906
907  if (value > ~0ULL / mult)
908    value = ~0ULL;
909  else
910    value *= mult;
911
912  *pvalue = value;
913  return true;
914
915 invalid:
916  gomp_error ("Invalid value for environment variable %s", name);
917  return false;
918}
919
920/* Parse a boolean value for environment variable NAME and store the
921   result in VALUE.  */
922
923static void
924parse_boolean (const char *name, bool *value)
925{
926  const char *env;
927
928  env = getenv (name);
929  if (env == NULL)
930    return;
931
932  while (isspace ((unsigned char) *env))
933    ++env;
934  if (strncasecmp (env, "true", 4) == 0)
935    {
936      *value = true;
937      env += 4;
938    }
939  else if (strncasecmp (env, "false", 5) == 0)
940    {
941      *value = false;
942      env += 5;
943    }
944  else
945    env = "X";
946  while (isspace ((unsigned char) *env))
947    ++env;
948  if (*env != '\0')
949    gomp_error ("Invalid value for environment variable %s", name);
950}
951
952/* Parse the OMP_WAIT_POLICY environment variable and store the
953   result in gomp_active_wait_policy.  */
954
955static int
956parse_wait_policy (void)
957{
958  const char *env;
959  int ret = -1;
960
961  env = getenv ("OMP_WAIT_POLICY");
962  if (env == NULL)
963    return -1;
964
965  while (isspace ((unsigned char) *env))
966    ++env;
967  if (strncasecmp (env, "active", 6) == 0)
968    {
969      ret = 1;
970      env += 6;
971    }
972  else if (strncasecmp (env, "passive", 7) == 0)
973    {
974      ret = 0;
975      env += 7;
976    }
977  else
978    env = "X";
979  while (isspace ((unsigned char) *env))
980    ++env;
981  if (*env == '\0')
982    return ret;
983  gomp_error ("Invalid value for environment variable OMP_WAIT_POLICY");
984  return -1;
985}
986
987/* Parse the GOMP_CPU_AFFINITY environment varible.  Return true if one was
988   present and it was successfully parsed.  */
989
990static bool
991parse_affinity (bool ignore)
992{
993  char *env, *end, *start;
994  int pass;
995  unsigned long cpu_beg, cpu_end, cpu_stride;
996  size_t count = 0, needed;
997
998  env = getenv ("GOMP_CPU_AFFINITY");
999  if (env == NULL)
1000    return false;
1001
1002  start = env;
1003  for (pass = 0; pass < 2; pass++)
1004    {
1005      env = start;
1006      if (pass == 1)
1007	{
1008	  if (ignore)
1009	    return false;
1010
1011	  gomp_places_list_len = 0;
1012	  gomp_places_list = gomp_affinity_alloc (count, true);
1013	  if (gomp_places_list == NULL)
1014	    return false;
1015	}
1016      do
1017	{
1018	  while (isspace ((unsigned char) *env))
1019	    ++env;
1020
1021	  errno = 0;
1022	  cpu_beg = strtoul (env, &end, 0);
1023	  if (errno || cpu_beg >= 65536)
1024	    goto invalid;
1025	  cpu_end = cpu_beg;
1026	  cpu_stride = 1;
1027
1028	  env = end;
1029	  if (*env == '-')
1030	    {
1031	      errno = 0;
1032	      cpu_end = strtoul (++env, &end, 0);
1033	      if (errno || cpu_end >= 65536 || cpu_end < cpu_beg)
1034		goto invalid;
1035
1036	      env = end;
1037	      if (*env == ':')
1038		{
1039		  errno = 0;
1040		  cpu_stride = strtoul (++env, &end, 0);
1041		  if (errno || cpu_stride == 0 || cpu_stride >= 65536)
1042		    goto invalid;
1043
1044		  env = end;
1045		}
1046	    }
1047
1048	  needed = (cpu_end - cpu_beg) / cpu_stride + 1;
1049	  if (pass == 0)
1050	    count += needed;
1051	  else
1052	    {
1053	      while (needed--)
1054		{
1055		  void *p = gomp_places_list[gomp_places_list_len];
1056		  gomp_affinity_init_place (p);
1057		  if (gomp_affinity_add_cpus (p, cpu_beg, 1, 0, true))
1058		    ++gomp_places_list_len;
1059		  cpu_beg += cpu_stride;
1060		}
1061	    }
1062
1063	  while (isspace ((unsigned char) *env))
1064	    ++env;
1065
1066	  if (*env == ',')
1067	    env++;
1068	  else if (*env == '\0')
1069	    break;
1070	}
1071      while (1);
1072    }
1073
1074  if (gomp_places_list_len == 0)
1075    {
1076      free (gomp_places_list);
1077      gomp_places_list = NULL;
1078      return false;
1079    }
1080  return true;
1081
1082 invalid:
1083  gomp_error ("Invalid value for enviroment variable GOMP_CPU_AFFINITY");
1084  return false;
1085}
1086
1087static void
1088parse_acc_device_type (void)
1089{
1090  const char *env = getenv ("ACC_DEVICE_TYPE");
1091
1092  if (env && *env != '\0')
1093    goacc_device_type = strdup (env);
1094  else
1095    goacc_device_type = NULL;
1096}
1097
1098static void
1099parse_gomp_openacc_dim (void)
1100{
1101  /* The syntax is the same as for the -fopenacc-dim compilation option.  */
1102  const char *var_name = "GOMP_OPENACC_DIM";
1103  const char *env_var = getenv (var_name);
1104  if (!env_var)
1105    return;
1106
1107  const char *pos = env_var;
1108  int i;
1109  for (i = 0; *pos && i != GOMP_DIM_MAX; i++)
1110    {
1111      if (i && *pos++ != ':')
1112	break;
1113
1114      if (*pos == ':')
1115	continue;
1116
1117      const char *eptr;
1118      errno = 0;
1119      long val = strtol (pos, (char **)&eptr, 10);
1120      if (errno || val < 0 || (unsigned)val != val)
1121	break;
1122
1123      goacc_default_dims[i] = (int)val;
1124      pos = eptr;
1125    }
1126}
1127
1128static void
1129handle_omp_display_env (unsigned long stacksize, int wait_policy)
1130{
1131  const char *env;
1132  bool display = false;
1133  bool verbose = false;
1134  int i;
1135
1136  env = getenv ("OMP_DISPLAY_ENV");
1137  if (env == NULL)
1138    return;
1139
1140  while (isspace ((unsigned char) *env))
1141    ++env;
1142  if (strncasecmp (env, "true", 4) == 0)
1143    {
1144      display = true;
1145      env += 4;
1146    }
1147  else if (strncasecmp (env, "false", 5) == 0)
1148    {
1149      display = false;
1150      env += 5;
1151    }
1152  else if (strncasecmp (env, "verbose", 7) == 0)
1153    {
1154      display = true;
1155      verbose = true;
1156      env += 7;
1157    }
1158  else
1159    env = "X";
1160  while (isspace ((unsigned char) *env))
1161    ++env;
1162  if (*env != '\0')
1163    gomp_error ("Invalid value for environment variable OMP_DISPLAY_ENV");
1164
1165  if (!display)
1166    return;
1167
1168  fputs ("\nOPENMP DISPLAY ENVIRONMENT BEGIN\n", stderr);
1169
1170  fputs ("  _OPENMP = '201511'\n", stderr);
1171  fprintf (stderr, "  OMP_DYNAMIC = '%s'\n",
1172	   gomp_global_icv.dyn_var ? "TRUE" : "FALSE");
1173  fprintf (stderr, "  OMP_NESTED = '%s'\n",
1174	   gomp_global_icv.nest_var ? "TRUE" : "FALSE");
1175
1176  fprintf (stderr, "  OMP_NUM_THREADS = '%lu", gomp_global_icv.nthreads_var);
1177  for (i = 1; i < gomp_nthreads_var_list_len; i++)
1178    fprintf (stderr, ",%lu", gomp_nthreads_var_list[i]);
1179  fputs ("'\n", stderr);
1180
1181  fprintf (stderr, "  OMP_SCHEDULE = '");
1182  if ((gomp_global_icv.run_sched_var & GFS_MONOTONIC))
1183    {
1184      if (gomp_global_icv.run_sched_var != (GFS_MONOTONIC | GFS_STATIC))
1185	fputs ("MONOTONIC:", stderr);
1186    }
1187  else if (gomp_global_icv.run_sched_var == GFS_STATIC)
1188    fputs ("NONMONOTONIC:", stderr);
1189  switch (gomp_global_icv.run_sched_var & ~GFS_MONOTONIC)
1190    {
1191    case GFS_RUNTIME:
1192      fputs ("RUNTIME", stderr);
1193      if (gomp_global_icv.run_sched_chunk_size != 1)
1194	fprintf (stderr, ",%d", gomp_global_icv.run_sched_chunk_size);
1195      break;
1196    case GFS_STATIC:
1197      fputs ("STATIC", stderr);
1198      if (gomp_global_icv.run_sched_chunk_size != 0)
1199	fprintf (stderr, ",%d", gomp_global_icv.run_sched_chunk_size);
1200      break;
1201    case GFS_DYNAMIC:
1202      fputs ("DYNAMIC", stderr);
1203      if (gomp_global_icv.run_sched_chunk_size != 1)
1204	fprintf (stderr, ",%d", gomp_global_icv.run_sched_chunk_size);
1205      break;
1206    case GFS_GUIDED:
1207      fputs ("GUIDED", stderr);
1208      if (gomp_global_icv.run_sched_chunk_size != 1)
1209	fprintf (stderr, ",%d", gomp_global_icv.run_sched_chunk_size);
1210      break;
1211    case GFS_AUTO:
1212      fputs ("AUTO", stderr);
1213      break;
1214    }
1215  fputs ("'\n", stderr);
1216
1217  fputs ("  OMP_PROC_BIND = '", stderr);
1218  switch (gomp_global_icv.bind_var)
1219    {
1220    case omp_proc_bind_false:
1221      fputs ("FALSE", stderr);
1222      break;
1223    case omp_proc_bind_true:
1224      fputs ("TRUE", stderr);
1225      break;
1226    case omp_proc_bind_master:
1227      fputs ("MASTER", stderr);
1228      break;
1229    case omp_proc_bind_close:
1230      fputs ("CLOSE", stderr);
1231      break;
1232    case omp_proc_bind_spread:
1233      fputs ("SPREAD", stderr);
1234      break;
1235    }
1236  for (i = 1; i < gomp_bind_var_list_len; i++)
1237    switch (gomp_bind_var_list[i])
1238      {
1239      case omp_proc_bind_master:
1240	fputs (",MASTER", stderr);
1241	break;
1242      case omp_proc_bind_close:
1243	fputs (",CLOSE", stderr);
1244	break;
1245      case omp_proc_bind_spread:
1246	fputs (",SPREAD", stderr);
1247	break;
1248      }
1249  fputs ("'\n", stderr);
1250  fputs ("  OMP_PLACES = '", stderr);
1251  for (i = 0; i < gomp_places_list_len; i++)
1252    {
1253      fputs ("{", stderr);
1254      gomp_affinity_print_place (gomp_places_list[i]);
1255      fputs (i + 1 == gomp_places_list_len ? "}" : "},", stderr);
1256    }
1257  fputs ("'\n", stderr);
1258
1259  fprintf (stderr, "  OMP_STACKSIZE = '%lu'\n", stacksize);
1260
1261  /* GOMP's default value is actually neither active nor passive.  */
1262  fprintf (stderr, "  OMP_WAIT_POLICY = '%s'\n",
1263	   wait_policy > 0 ? "ACTIVE" : "PASSIVE");
1264  fprintf (stderr, "  OMP_THREAD_LIMIT = '%u'\n",
1265	   gomp_global_icv.thread_limit_var);
1266  fprintf (stderr, "  OMP_MAX_ACTIVE_LEVELS = '%lu'\n",
1267	   gomp_max_active_levels_var);
1268
1269  fprintf (stderr, "  OMP_CANCELLATION = '%s'\n",
1270	   gomp_cancel_var ? "TRUE" : "FALSE");
1271  fprintf (stderr, "  OMP_DEFAULT_DEVICE = '%d'\n",
1272	   gomp_global_icv.default_device_var);
1273  fprintf (stderr, "  OMP_MAX_TASK_PRIORITY = '%d'\n",
1274	   gomp_max_task_priority_var);
1275  fprintf (stderr, "  OMP_DISPLAY_AFFINITY = '%s'\n",
1276	   gomp_display_affinity_var ? "TRUE" : "FALSE");
1277  fprintf (stderr, "  OMP_AFFINITY_FORMAT = '%s'\n",
1278	   gomp_affinity_format_var);
1279
1280  if (verbose)
1281    {
1282      fputs ("  GOMP_CPU_AFFINITY = ''\n", stderr);
1283      fprintf (stderr, "  GOMP_STACKSIZE = '%lu'\n", stacksize);
1284#ifdef HAVE_INTTYPES_H
1285      fprintf (stderr, "  GOMP_SPINCOUNT = '%"PRIu64"'\n",
1286	       (uint64_t) gomp_spin_count_var);
1287#else
1288      fprintf (stderr, "  GOMP_SPINCOUNT = '%lu'\n",
1289	       (unsigned long) gomp_spin_count_var);
1290#endif
1291    }
1292
1293  fputs ("OPENMP DISPLAY ENVIRONMENT END\n", stderr);
1294}
1295
1296
1297static void __attribute__((constructor))
1298initialize_env (void)
1299{
1300  unsigned long thread_limit_var, stacksize = GOMP_DEFAULT_STACKSIZE;
1301  int wait_policy;
1302
1303  /* Do a compile time check that mkomp_h.pl did good job.  */
1304  omp_check_defines ();
1305
1306  parse_schedule ();
1307  parse_boolean ("OMP_DYNAMIC", &gomp_global_icv.dyn_var);
1308  parse_boolean ("OMP_NESTED", &gomp_global_icv.nest_var);
1309  parse_boolean ("OMP_CANCELLATION", &gomp_cancel_var);
1310  parse_boolean ("OMP_DISPLAY_AFFINITY", &gomp_display_affinity_var);
1311  parse_int ("OMP_DEFAULT_DEVICE", &gomp_global_icv.default_device_var, true);
1312  parse_int ("OMP_MAX_TASK_PRIORITY", &gomp_max_task_priority_var, true);
1313  parse_unsigned_long ("OMP_MAX_ACTIVE_LEVELS", &gomp_max_active_levels_var,
1314		       true);
1315  if (parse_unsigned_long ("OMP_THREAD_LIMIT", &thread_limit_var, false))
1316    {
1317      gomp_global_icv.thread_limit_var
1318	= thread_limit_var > INT_MAX ? UINT_MAX : thread_limit_var;
1319    }
1320  parse_int_secure ("GOMP_DEBUG", &gomp_debug_var, true);
1321#ifndef HAVE_SYNC_BUILTINS
1322  gomp_mutex_init (&gomp_managed_threads_lock);
1323#endif
1324  gomp_init_num_threads ();
1325  gomp_available_cpus = gomp_global_icv.nthreads_var;
1326  if (!parse_unsigned_long_list ("OMP_NUM_THREADS",
1327				 &gomp_global_icv.nthreads_var,
1328				 &gomp_nthreads_var_list,
1329				 &gomp_nthreads_var_list_len))
1330    gomp_global_icv.nthreads_var = gomp_available_cpus;
1331  bool ignore = false;
1332  if (parse_bind_var ("OMP_PROC_BIND",
1333		      &gomp_global_icv.bind_var,
1334		      &gomp_bind_var_list,
1335		      &gomp_bind_var_list_len)
1336      && gomp_global_icv.bind_var == omp_proc_bind_false)
1337    ignore = true;
1338  /* Make sure OMP_PLACES and GOMP_CPU_AFFINITY env vars are always
1339     parsed if present in the environment.  If OMP_PROC_BIND was set
1340     explicitly to false, don't populate places list though.  If places
1341     list was successfully set from OMP_PLACES, only parse but don't process
1342     GOMP_CPU_AFFINITY.  If OMP_PROC_BIND was not set in the environment,
1343     default to OMP_PROC_BIND=true if OMP_PLACES or GOMP_CPU_AFFINITY
1344     was successfully parsed into a places list, otherwise to
1345     OMP_PROC_BIND=false.  */
1346  if (parse_places_var ("OMP_PLACES", ignore))
1347    {
1348      if (gomp_global_icv.bind_var == omp_proc_bind_false)
1349	gomp_global_icv.bind_var = true;
1350      ignore = true;
1351    }
1352  if (parse_affinity (ignore))
1353    {
1354      if (gomp_global_icv.bind_var == omp_proc_bind_false)
1355	gomp_global_icv.bind_var = true;
1356      ignore = true;
1357    }
1358  if (gomp_global_icv.bind_var != omp_proc_bind_false)
1359    gomp_init_affinity ();
1360
1361  {
1362    const char *env = getenv ("OMP_AFFINITY_FORMAT");
1363    if (env != NULL)
1364      gomp_set_affinity_format (env, strlen (env));
1365  }
1366
1367  wait_policy = parse_wait_policy ();
1368  if (!parse_spincount ("GOMP_SPINCOUNT", &gomp_spin_count_var))
1369    {
1370      /* Using a rough estimation of 100000 spins per msec,
1371	 use 5 min blocking for OMP_WAIT_POLICY=active,
1372	 3 msec blocking when OMP_WAIT_POLICY is not specificed
1373	 and 0 when OMP_WAIT_POLICY=passive.
1374	 Depending on the CPU speed, this can be e.g. 5 times longer
1375	 or 5 times shorter.  */
1376      if (wait_policy > 0)
1377	gomp_spin_count_var = 30000000000LL;
1378      else if (wait_policy < 0)
1379	gomp_spin_count_var = 300000LL;
1380    }
1381  /* gomp_throttled_spin_count_var is used when there are more libgomp
1382     managed threads than available CPUs.  Use very short spinning.  */
1383  if (wait_policy > 0)
1384    gomp_throttled_spin_count_var = 1000LL;
1385  else if (wait_policy < 0)
1386    gomp_throttled_spin_count_var = 100LL;
1387  if (gomp_throttled_spin_count_var > gomp_spin_count_var)
1388    gomp_throttled_spin_count_var = gomp_spin_count_var;
1389
1390  /* Not strictly environment related, but ordering constructors is tricky.  */
1391  pthread_attr_init (&gomp_thread_attr);
1392
1393  if (parse_stacksize ("OMP_STACKSIZE", &stacksize)
1394      || parse_stacksize ("GOMP_STACKSIZE", &stacksize)
1395      || GOMP_DEFAULT_STACKSIZE)
1396    {
1397      int err;
1398
1399      err = pthread_attr_setstacksize (&gomp_thread_attr, stacksize);
1400
1401#ifdef PTHREAD_STACK_MIN
1402      if (err == EINVAL)
1403	{
1404	  if (stacksize < PTHREAD_STACK_MIN)
1405	    gomp_error ("Stack size less than minimum of %luk",
1406			PTHREAD_STACK_MIN / 1024ul
1407			+ (PTHREAD_STACK_MIN % 1024 != 0));
1408	  else
1409	    gomp_error ("Stack size larger than system limit");
1410	}
1411      else
1412#endif
1413      if (err != 0)
1414	gomp_error ("Stack size change failed: %s", strerror (err));
1415    }
1416
1417  handle_omp_display_env (stacksize, wait_policy);
1418
1419  /* OpenACC.  */
1420
1421  if (!parse_int ("ACC_DEVICE_NUM", &goacc_device_num, true))
1422    goacc_device_num = 0;
1423
1424  parse_acc_device_type ();
1425  parse_gomp_openacc_dim ();
1426
1427  goacc_runtime_initialize ();
1428
1429  goacc_profiling_initialize ();
1430}
1431#endif /* LIBGOMP_OFFLOADED_ONLY */
1432