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