xref: /dragonfly/contrib/gcc-8.0/libgomp/env.c (revision 38fd149817dfbff97799f62fcb70be98c4e32523)
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
parse_schedule(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
parse_unsigned_long_1(const char * name,unsigned long * pvalue,bool allow_zero,bool secure)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
parse_unsigned_long(const char * name,unsigned long * pvalue,bool allow_zero)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
parse_int_1(const char * name,int * pvalue,bool allow_zero,bool secure)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
parse_int(const char * name,int * pvalue,bool allow_zero)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
parse_int_secure(const char * name,int * pvalue,bool allow_zero)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
parse_unsigned_long_list(const char * name,unsigned long * p1stvalue,unsigned long ** pvalues,unsigned long * pnvalues)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
parse_bind_var(const char * name,char * p1stvalue,char ** pvalues,unsigned long * pnvalues)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
parse_one_place(char ** envp,bool * negatep,unsigned long * lenp,long * stridep)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
parse_places_var(const char * name,bool ignore)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
parse_stacksize(const char * name,unsigned long * pvalue)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
parse_spincount(const char * name,unsigned long long * pvalue)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
parse_boolean(const char * name,bool * value)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
parse_wait_policy(void)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
parse_affinity(bool ignore)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
parse_acc_device_type(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
handle_omp_display_env(unsigned long stacksize,int wait_policy)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))
initialize_env(void)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