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