1 /* Copyright (C) 2005-2019 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 bool gomp_display_affinity_var;
92 char *gomp_affinity_format_var = "level %L thread %i affinity %A";
93 size_t gomp_affinity_format_len;
94 char *goacc_device_type;
95 int goacc_device_num;
96 int goacc_default_dims[GOMP_DIM_MAX];
97 
98 #ifndef LIBGOMP_OFFLOADED_ONLY
99 
100 /* Parse the OMP_SCHEDULE environment variable.  */
101 
102 static void
parse_schedule(void)103 parse_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 
210 static bool
parse_unsigned_long_1(const char * name,unsigned long * pvalue,bool allow_zero,bool secure)211 parse_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 
246 static bool
parse_unsigned_long(const char * name,unsigned long * pvalue,bool allow_zero)247 parse_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 
256 static bool
parse_int_1(const char * name,int * pvalue,bool allow_zero,bool secure)257 parse_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 
273 static bool
parse_int(const char * name,int * pvalue,bool allow_zero)274 parse_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 
281 static bool
parse_int_secure(const char * name,int * pvalue,bool allow_zero)282 parse_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 
290 static bool
parse_unsigned_long_list(const char * name,unsigned long * p1stvalue,unsigned long ** pvalues,unsigned long * pnvalues)291 parse_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 
380 static bool
parse_bind_var(const char * name,char * p1stvalue,char ** pvalues,unsigned long * pnvalues)381 parse_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 
493 static bool
parse_one_place(char ** envp,bool * negatep,unsigned long * lenp,long * stridep)494 parse_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 
623 static bool
parse_places_var(const char * name,bool ignore)624 parse_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 
789 static bool
parse_stacksize(const char * name,unsigned long * pvalue)790 parse_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 
850 static bool
parse_spincount(const char * name,unsigned long long * pvalue)851 parse_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 
923 static void
parse_boolean(const char * name,bool * value)924 parse_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 
955 static int
parse_wait_policy(void)956 parse_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 
990 static bool
parse_affinity(bool ignore)991 parse_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 
1087 static void
parse_acc_device_type(void)1088 parse_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 
1098 static void
parse_gomp_openacc_dim(void)1099 parse_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 
1128 static void
handle_omp_display_env(unsigned long stacksize,int wait_policy)1129 handle_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 
1297 static void __attribute__((constructor))
initialize_env(void)1298 initialize_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      explictly 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 #endif /* LIBGOMP_OFFLOADED_ONLY */
1430