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