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