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