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