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