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