]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgomp/env.c
compiler: Use backend interface for function declarations.
[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>
a1b25e49
PG
32#ifdef STRING_WITH_STRINGS
33# include <string.h>
34# include <strings.h>
35#else
36# ifdef HAVE_STRING_H
37# include <string.h>
38# else
39# ifdef HAVE_STRINGS_H
40# include <strings.h>
41# endif
42# endif
43#endif
d0d1b24d
RH
44#include <limits.h>
45#include <errno.h>
953ff289 46
976e44e3
JJ
47#ifndef HAVE_STRTOULL
48# define strtoull(ptr, eptr, base) strtoul (ptr, eptr, base)
49#endif
953ff289 50
a68ab351
JJ
51struct gomp_task_icv gomp_global_icv = {
52 .nthreads_var = 1,
53 .run_sched_var = GFS_DYNAMIC,
54 .run_sched_modifier = 1,
55 .dyn_var = false,
56 .nest_var = false
57};
58
a0884cf0
JJ
59unsigned short *gomp_cpu_affinity;
60size_t gomp_cpu_affinity_len;
a68ab351
JJ
61unsigned long gomp_max_active_levels_var = INT_MAX;
62unsigned long gomp_thread_limit_var = ULONG_MAX;
63unsigned long gomp_remaining_threads_count;
64#ifndef HAVE_SYNC_BUILTINS
65gomp_mutex_t gomp_remaining_threads_lock;
66#endif
67unsigned long gomp_available_cpus = 1, gomp_managed_threads = 1;
68unsigned long long gomp_spin_count_var, gomp_throttled_spin_count_var;
20906c66 69unsigned long *gomp_nthreads_var_list, gomp_nthreads_var_list_len;
953ff289
DN
70
71/* Parse the OMP_SCHEDULE environment variable. */
72
73static void
74parse_schedule (void)
75{
76 char *env, *end;
6acf0b38 77 unsigned long value;
953ff289
DN
78
79 env = getenv ("OMP_SCHEDULE");
80 if (env == NULL)
81 return;
82
89b3e3cd
JJ
83 while (isspace ((unsigned char) *env))
84 ++env;
85 if (strncasecmp (env, "static", 6) == 0)
953ff289 86 {
a68ab351 87 gomp_global_icv.run_sched_var = GFS_STATIC;
953ff289
DN
88 env += 6;
89 }
89b3e3cd 90 else if (strncasecmp (env, "dynamic", 7) == 0)
953ff289 91 {
a68ab351 92 gomp_global_icv.run_sched_var = GFS_DYNAMIC;
953ff289
DN
93 env += 7;
94 }
89b3e3cd 95 else if (strncasecmp (env, "guided", 6) == 0)
953ff289 96 {
a68ab351 97 gomp_global_icv.run_sched_var = GFS_GUIDED;
953ff289
DN
98 env += 6;
99 }
a68ab351
JJ
100 else if (strncasecmp (env, "auto", 4) == 0)
101 {
102 gomp_global_icv.run_sched_var = GFS_AUTO;
103 env += 4;
104 }
953ff289
DN
105 else
106 goto unknown;
107
89b3e3cd
JJ
108 while (isspace ((unsigned char) *env))
109 ++env;
953ff289 110 if (*env == '\0')
fb79f500
JJ
111 {
112 gomp_global_icv.run_sched_modifier
113 = gomp_global_icv.run_sched_var != GFS_STATIC;
114 return;
115 }
89b3e3cd 116 if (*env++ != ',')
953ff289 117 goto unknown;
89b3e3cd
JJ
118 while (isspace ((unsigned char) *env))
119 ++env;
953ff289 120 if (*env == '\0')
953ff289
DN
121 goto invalid;
122
6acf0b38
UB
123 errno = 0;
124 value = strtoul (env, &end, 10);
125 if (errno)
126 goto invalid;
127
89b3e3cd
JJ
128 while (isspace ((unsigned char) *end))
129 ++end;
953ff289
DN
130 if (*end != '\0')
131 goto invalid;
6acf0b38 132
a68ab351
JJ
133 if ((int)value != value)
134 goto invalid;
135
fb79f500
JJ
136 if (value == 0 && gomp_global_icv.run_sched_var != GFS_STATIC)
137 value = 1;
a68ab351 138 gomp_global_icv.run_sched_modifier = value;
953ff289
DN
139 return;
140
141 unknown:
142 gomp_error ("Unknown value for environment variable OMP_SCHEDULE");
143 return;
144
145 invalid:
146 gomp_error ("Invalid value for chunk size in "
147 "environment variable OMP_SCHEDULE");
953ff289
DN
148 return;
149}
150
a68ab351 151/* Parse an unsigned long environment variable. Return true if one was
953ff289
DN
152 present and it was successfully parsed. */
153
154static bool
80f046cc 155parse_unsigned_long (const char *name, unsigned long *pvalue, bool allow_zero)
953ff289
DN
156{
157 char *env, *end;
d0d1b24d 158 unsigned long value;
953ff289 159
d0d1b24d 160 env = getenv (name);
953ff289
DN
161 if (env == NULL)
162 return false;
163
89b3e3cd
JJ
164 while (isspace ((unsigned char) *env))
165 ++env;
953ff289
DN
166 if (*env == '\0')
167 goto invalid;
168
6acf0b38 169 errno = 0;
d0d1b24d 170 value = strtoul (env, &end, 10);
80f046cc 171 if (errno || (long) value <= 0 - allow_zero)
6acf0b38
UB
172 goto invalid;
173
89b3e3cd
JJ
174 while (isspace ((unsigned char) *end))
175 ++end;
953ff289
DN
176 if (*end != '\0')
177 goto invalid;
d0d1b24d
RH
178
179 *pvalue = value;
953ff289
DN
180 return true;
181
182 invalid:
d0d1b24d 183 gomp_error ("Invalid value for environment variable %s", name);
953ff289
DN
184 return false;
185}
186
20906c66
JJ
187/* Parse an unsigned long list environment variable. Return true if one was
188 present and it was successfully parsed. */
189
190static bool
191parse_unsigned_long_list (const char *name, unsigned long *p1stvalue,
192 unsigned long **pvalues,
193 unsigned long *pnvalues)
194{
195 char *env, *end;
196 unsigned long value, *values = NULL;
197
198 env = getenv (name);
199 if (env == NULL)
200 return false;
201
202 while (isspace ((unsigned char) *env))
203 ++env;
204 if (*env == '\0')
205 goto invalid;
206
207 errno = 0;
208 value = strtoul (env, &end, 10);
209 if (errno || (long) value <= 0)
210 goto invalid;
211
212 while (isspace ((unsigned char) *end))
213 ++end;
214 if (*end != '\0')
215 {
216 if (*end == ',')
217 {
218 unsigned long nvalues = 0, nalloced = 0;
219
220 do
221 {
222 env = end + 1;
223 if (nvalues == nalloced)
224 {
225 unsigned long *n;
226 nalloced = nalloced ? nalloced * 2 : 16;
227 n = realloc (values, nalloced * sizeof (unsigned long));
228 if (n == NULL)
229 {
230 free (values);
231 gomp_error ("Out of memory while trying to parse"
232 " environment variable %s", name);
233 return false;
234 }
235 values = n;
236 if (nvalues == 0)
237 values[nvalues++] = value;
238 }
239
240 while (isspace ((unsigned char) *env))
241 ++env;
242 if (*env == '\0')
243 goto invalid;
244
245 errno = 0;
246 value = strtoul (env, &end, 10);
247 if (errno || (long) value <= 0)
248 goto invalid;
249
250 values[nvalues++] = value;
251 while (isspace ((unsigned char) *end))
252 ++end;
253 if (*end == '\0')
254 break;
255 if (*end != ',')
256 goto invalid;
257 }
258 while (1);
259 *p1stvalue = values[0];
260 *pvalues = values;
261 *pnvalues = nvalues;
262 return true;
263 }
264 goto invalid;
265 }
266
267 *p1stvalue = value;
268 return true;
269
270 invalid:
271 free (values);
272 gomp_error ("Invalid value for environment variable %s", name);
273 return false;
274}
275
a68ab351
JJ
276/* Parse the OMP_STACKSIZE environment varible. Return true if one was
277 present and it was successfully parsed. */
278
279static bool
280parse_stacksize (const char *name, unsigned long *pvalue)
281{
282 char *env, *end;
283 unsigned long value, shift = 10;
284
285 env = getenv (name);
286 if (env == NULL)
287 return false;
288
289 while (isspace ((unsigned char) *env))
290 ++env;
291 if (*env == '\0')
292 goto invalid;
293
294 errno = 0;
295 value = strtoul (env, &end, 10);
296 if (errno)
297 goto invalid;
298
299 while (isspace ((unsigned char) *end))
300 ++end;
301 if (*end != '\0')
302 {
323ff903 303 switch (tolower ((unsigned char) *end))
a68ab351
JJ
304 {
305 case 'b':
306 shift = 0;
307 break;
308 case 'k':
309 break;
310 case 'm':
311 shift = 20;
312 break;
313 case 'g':
314 shift = 30;
315 break;
316 default:
317 goto invalid;
318 }
319 ++end;
320 while (isspace ((unsigned char) *end))
321 ++end;
322 if (*end != '\0')
323 goto invalid;
324 }
325
326 if (((value << shift) >> shift) != value)
327 goto invalid;
328
329 *pvalue = value << shift;
330 return true;
331
332 invalid:
333 gomp_error ("Invalid value for environment variable %s", name);
334 return false;
335}
336
337/* Parse the GOMP_SPINCOUNT environment varible. Return true if one was
338 present and it was successfully parsed. */
339
340static bool
341parse_spincount (const char *name, unsigned long long *pvalue)
342{
343 char *env, *end;
344 unsigned long long value, mult = 1;
345
346 env = getenv (name);
347 if (env == NULL)
348 return false;
349
350 while (isspace ((unsigned char) *env))
351 ++env;
352 if (*env == '\0')
353 goto invalid;
354
355 if (strncasecmp (env, "infinite", 8) == 0
356 || strncasecmp (env, "infinity", 8) == 0)
357 {
358 value = ~0ULL;
359 end = env + 8;
360 goto check_tail;
361 }
362
363 errno = 0;
364 value = strtoull (env, &end, 10);
365 if (errno)
366 goto invalid;
367
368 while (isspace ((unsigned char) *end))
369 ++end;
370 if (*end != '\0')
371 {
323ff903 372 switch (tolower ((unsigned char) *end))
a68ab351
JJ
373 {
374 case 'k':
375 mult = 1000LL;
376 break;
377 case 'm':
378 mult = 1000LL * 1000LL;
379 break;
380 case 'g':
381 mult = 1000LL * 1000LL * 1000LL;
382 break;
383 case 't':
384 mult = 1000LL * 1000LL * 1000LL * 1000LL;
385 break;
386 default:
387 goto invalid;
388 }
389 ++end;
390 check_tail:
391 while (isspace ((unsigned char) *end))
392 ++end;
393 if (*end != '\0')
394 goto invalid;
395 }
396
397 if (value > ~0ULL / mult)
398 value = ~0ULL;
399 else
400 value *= mult;
401
402 *pvalue = value;
403 return true;
404
405 invalid:
406 gomp_error ("Invalid value for environment variable %s", name);
407 return false;
408}
409
410/* Parse a boolean value for environment variable NAME and store the
953ff289
DN
411 result in VALUE. */
412
413static void
414parse_boolean (const char *name, bool *value)
415{
416 const char *env;
417
418 env = getenv (name);
419 if (env == NULL)
420 return;
421
89b3e3cd
JJ
422 while (isspace ((unsigned char) *env))
423 ++env;
424 if (strncasecmp (env, "true", 4) == 0)
425 {
426 *value = true;
427 env += 4;
428 }
429 else if (strncasecmp (env, "false", 5) == 0)
430 {
431 *value = false;
432 env += 5;
433 }
953ff289 434 else
89b3e3cd
JJ
435 env = "X";
436 while (isspace ((unsigned char) *env))
437 ++env;
438 if (*env != '\0')
d0d1b24d 439 gomp_error ("Invalid value for environment variable %s", name);
953ff289
DN
440}
441
a68ab351
JJ
442/* Parse the OMP_WAIT_POLICY environment variable and store the
443 result in gomp_active_wait_policy. */
444
445static int
446parse_wait_policy (void)
447{
448 const char *env;
449 int ret = -1;
450
451 env = getenv ("OMP_WAIT_POLICY");
452 if (env == NULL)
453 return -1;
454
455 while (isspace ((unsigned char) *env))
456 ++env;
457 if (strncasecmp (env, "active", 6) == 0)
458 {
459 ret = 1;
460 env += 6;
461 }
462 else if (strncasecmp (env, "passive", 7) == 0)
463 {
464 ret = 0;
465 env += 7;
466 }
467 else
468 env = "X";
469 while (isspace ((unsigned char) *env))
470 ++env;
471 if (*env == '\0')
472 return ret;
473 gomp_error ("Invalid value for environment variable OMP_WAIT_POLICY");
474 return -1;
475}
476
a0884cf0
JJ
477/* Parse the GOMP_CPU_AFFINITY environment varible. Return true if one was
478 present and it was successfully parsed. */
479
480static bool
481parse_affinity (void)
482{
483 char *env, *end;
484 unsigned long cpu_beg, cpu_end, cpu_stride;
485 unsigned short *cpus = NULL;
486 size_t allocated = 0, used = 0, needed;
487
488 env = getenv ("GOMP_CPU_AFFINITY");
489 if (env == NULL)
490 return false;
491
492 do
493 {
494 while (*env == ' ' || *env == '\t')
495 env++;
496
497 cpu_beg = strtoul (env, &end, 0);
498 cpu_end = cpu_beg;
499 cpu_stride = 1;
500 if (env == end || cpu_beg >= 65536)
501 goto invalid;
502
503 env = end;
504 if (*env == '-')
505 {
506 cpu_end = strtoul (++env, &end, 0);
507 if (env == end || cpu_end >= 65536 || cpu_end < cpu_beg)
508 goto invalid;
509
510 env = end;
511 if (*env == ':')
512 {
513 cpu_stride = strtoul (++env, &end, 0);
514 if (env == end || cpu_stride == 0 || cpu_stride >= 65536)
515 goto invalid;
516
517 env = end;
518 }
519 }
520
521 needed = (cpu_end - cpu_beg) / cpu_stride + 1;
522 if (used + needed >= allocated)
523 {
524 unsigned short *new_cpus;
525
526 if (allocated < 64)
527 allocated = 64;
528 if (allocated > needed)
529 allocated <<= 1;
530 else
531 allocated += 2 * needed;
532 new_cpus = realloc (cpus, allocated * sizeof (unsigned short));
533 if (new_cpus == NULL)
534 {
535 free (cpus);
536 gomp_error ("not enough memory to store GOMP_CPU_AFFINITY list");
537 return false;
538 }
539
540 cpus = new_cpus;
541 }
542
543 while (needed--)
544 {
545 cpus[used++] = cpu_beg;
546 cpu_beg += cpu_stride;
547 }
548
549 while (*env == ' ' || *env == '\t')
550 env++;
551
552 if (*env == ',')
553 env++;
554 else if (*env == '\0')
555 break;
556 }
557 while (1);
558
559 gomp_cpu_affinity = cpus;
560 gomp_cpu_affinity_len = used;
561 return true;
562
563 invalid:
564 gomp_error ("Invalid value for enviroment variable GOMP_CPU_AFFINITY");
565 return false;
566}
567
953ff289
DN
568static void __attribute__((constructor))
569initialize_env (void)
570{
d0d1b24d 571 unsigned long stacksize;
a68ab351 572 int wait_policy;
20906c66 573 bool bind_var = false;
d0d1b24d 574
953ff289
DN
575 /* Do a compile time check that mkomp_h.pl did good job. */
576 omp_check_defines ();
577
578 parse_schedule ();
a68ab351
JJ
579 parse_boolean ("OMP_DYNAMIC", &gomp_global_icv.dyn_var);
580 parse_boolean ("OMP_NESTED", &gomp_global_icv.nest_var);
20906c66 581 parse_boolean ("OMP_PROC_BIND", &bind_var);
80f046cc
JJ
582 parse_unsigned_long ("OMP_MAX_ACTIVE_LEVELS", &gomp_max_active_levels_var,
583 true);
584 parse_unsigned_long ("OMP_THREAD_LIMIT", &gomp_thread_limit_var, false);
a68ab351 585 if (gomp_thread_limit_var != ULONG_MAX)
9c4e59e0 586 gomp_remaining_threads_count = gomp_thread_limit_var - 1;
a68ab351 587#ifndef HAVE_SYNC_BUILTINS
9c4e59e0 588 gomp_mutex_init (&gomp_remaining_threads_lock);
a68ab351 589#endif
a68ab351
JJ
590 gomp_init_num_threads ();
591 gomp_available_cpus = gomp_global_icv.nthreads_var;
20906c66
JJ
592 if (!parse_unsigned_long_list ("OMP_NUM_THREADS",
593 &gomp_global_icv.nthreads_var,
594 &gomp_nthreads_var_list,
595 &gomp_nthreads_var_list_len))
a68ab351 596 gomp_global_icv.nthreads_var = gomp_available_cpus;
20906c66 597 if (parse_affinity () || bind_var)
a0884cf0 598 gomp_init_affinity ();
a68ab351
JJ
599 wait_policy = parse_wait_policy ();
600 if (!parse_spincount ("GOMP_SPINCOUNT", &gomp_spin_count_var))
601 {
602 /* Using a rough estimation of 100000 spins per msec,
603 use 5 min blocking for OMP_WAIT_POLICY=active,
4c698cf8 604 3 msec blocking when OMP_WAIT_POLICY is not specificed
a68ab351
JJ
605 and 0 when OMP_WAIT_POLICY=passive.
606 Depending on the CPU speed, this can be e.g. 5 times longer
607 or 5 times shorter. */
608 if (wait_policy > 0)
609 gomp_spin_count_var = 30000000000LL;
610 else if (wait_policy < 0)
4c698cf8 611 gomp_spin_count_var = 300000LL;
a68ab351
JJ
612 }
613 /* gomp_throttled_spin_count_var is used when there are more libgomp
614 managed threads than available CPUs. Use very short spinning. */
615 if (wait_policy > 0)
616 gomp_throttled_spin_count_var = 1000LL;
617 else if (wait_policy < 0)
618 gomp_throttled_spin_count_var = 100LL;
619 if (gomp_throttled_spin_count_var > gomp_spin_count_var)
620 gomp_throttled_spin_count_var = gomp_spin_count_var;
d0d1b24d
RH
621
622 /* Not strictly environment related, but ordering constructors is tricky. */
623 pthread_attr_init (&gomp_thread_attr);
624 pthread_attr_setdetachstate (&gomp_thread_attr, PTHREAD_CREATE_DETACHED);
625
a68ab351
JJ
626 if (parse_stacksize ("OMP_STACKSIZE", &stacksize)
627 || parse_stacksize ("GOMP_STACKSIZE", &stacksize))
d0d1b24d 628 {
c3b11a40
RH
629 int err;
630
c3b11a40
RH
631 err = pthread_attr_setstacksize (&gomp_thread_attr, stacksize);
632
633#ifdef PTHREAD_STACK_MIN
634 if (err == EINVAL)
d0d1b24d 635 {
c3b11a40
RH
636 if (stacksize < PTHREAD_STACK_MIN)
637 gomp_error ("Stack size less than minimum of %luk",
638 PTHREAD_STACK_MIN / 1024ul
639 + (PTHREAD_STACK_MIN % 1024 != 0));
640 else
d0d1b24d 641 gomp_error ("Stack size larger than system limit");
d0d1b24d 642 }
c3b11a40
RH
643 else
644#endif
645 if (err != 0)
646 gomp_error ("Stack size change failed: %s", strerror (err));
d0d1b24d 647 }
953ff289
DN
648}
649
650\f
651/* The public OpenMP API routines that access these variables. */
652
653void
654omp_set_num_threads (int n)
655{
a68ab351
JJ
656 struct gomp_task_icv *icv = gomp_icv (true);
657 icv->nthreads_var = (n > 0 ? n : 1);
953ff289
DN
658}
659
660void
661omp_set_dynamic (int val)
662{
a68ab351
JJ
663 struct gomp_task_icv *icv = gomp_icv (true);
664 icv->dyn_var = val;
953ff289
DN
665}
666
667int
668omp_get_dynamic (void)
669{
a68ab351
JJ
670 struct gomp_task_icv *icv = gomp_icv (false);
671 return icv->dyn_var;
953ff289
DN
672}
673
674void
675omp_set_nested (int val)
676{
a68ab351
JJ
677 struct gomp_task_icv *icv = gomp_icv (true);
678 icv->nest_var = val;
953ff289
DN
679}
680
681int
682omp_get_nested (void)
683{
a68ab351
JJ
684 struct gomp_task_icv *icv = gomp_icv (false);
685 return icv->nest_var;
686}
687
688void
689omp_set_schedule (omp_sched_t kind, int modifier)
690{
691 struct gomp_task_icv *icv = gomp_icv (true);
692 switch (kind)
693 {
694 case omp_sched_static:
695 if (modifier < 1)
696 modifier = 0;
697 icv->run_sched_modifier = modifier;
698 break;
699 case omp_sched_dynamic:
700 case omp_sched_guided:
701 if (modifier < 1)
702 modifier = 1;
703 icv->run_sched_modifier = modifier;
704 break;
705 case omp_sched_auto:
706 break;
707 default:
708 return;
709 }
710 icv->run_sched_var = kind;
711}
712
713void
714omp_get_schedule (omp_sched_t *kind, int *modifier)
715{
716 struct gomp_task_icv *icv = gomp_icv (false);
717 *kind = icv->run_sched_var;
718 *modifier = icv->run_sched_modifier;
719}
720
721int
722omp_get_max_threads (void)
723{
724 struct gomp_task_icv *icv = gomp_icv (false);
725 return icv->nthreads_var;
726}
727
728int
729omp_get_thread_limit (void)
730{
731 return gomp_thread_limit_var > INT_MAX ? INT_MAX : gomp_thread_limit_var;
732}
733
734void
735omp_set_max_active_levels (int max_levels)
736{
80f046cc 737 if (max_levels >= 0)
a68ab351
JJ
738 gomp_max_active_levels_var = max_levels;
739}
740
741int
742omp_get_max_active_levels (void)
743{
744 return gomp_max_active_levels_var;
953ff289
DN
745}
746
747ialias (omp_set_dynamic)
748ialias (omp_set_nested)
749ialias (omp_set_num_threads)
750ialias (omp_get_dynamic)
751ialias (omp_get_nested)
a68ab351
JJ
752ialias (omp_set_schedule)
753ialias (omp_get_schedule)
754ialias (omp_get_max_threads)
755ialias (omp_get_thread_limit)
756ialias (omp_set_max_active_levels)
757ialias (omp_get_max_active_levels)