remove unused files
[platform/upstream/gcc48.git] / libgomp / env.c
1 /* Copyright (C) 2005-2013 Free Software Foundation, Inc.
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
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.
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
13    FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14    more details.
15
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.
19
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/>.  */
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"
30 #include <ctype.h>
31 #include <stdlib.h>
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
44 #include <limits.h>
45 #include <errno.h>
46
47 #ifndef HAVE_STRTOULL
48 # define strtoull(ptr, eptr, base) strtoul (ptr, eptr, base)
49 #endif
50
51 struct 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
59 unsigned short *gomp_cpu_affinity;
60 size_t gomp_cpu_affinity_len;
61 unsigned long gomp_max_active_levels_var = INT_MAX;
62 unsigned long gomp_thread_limit_var = ULONG_MAX;
63 unsigned long gomp_remaining_threads_count;
64 #ifndef HAVE_SYNC_BUILTINS
65 gomp_mutex_t gomp_remaining_threads_lock;
66 #endif
67 unsigned long gomp_available_cpus = 1, gomp_managed_threads = 1;
68 unsigned long long gomp_spin_count_var, gomp_throttled_spin_count_var;
69 unsigned long *gomp_nthreads_var_list, gomp_nthreads_var_list_len;
70
71 /* Parse the OMP_SCHEDULE environment variable.  */
72
73 static void
74 parse_schedule (void)
75 {
76   char *env, *end;
77   unsigned long value;
78
79   env = getenv ("OMP_SCHEDULE");
80   if (env == NULL)
81     return;
82
83   while (isspace ((unsigned char) *env))
84     ++env;
85   if (strncasecmp (env, "static", 6) == 0)
86     {
87       gomp_global_icv.run_sched_var = GFS_STATIC;
88       env += 6;
89     }
90   else if (strncasecmp (env, "dynamic", 7) == 0)
91     {
92       gomp_global_icv.run_sched_var = GFS_DYNAMIC;
93       env += 7;
94     }
95   else if (strncasecmp (env, "guided", 6) == 0)
96     {
97       gomp_global_icv.run_sched_var = GFS_GUIDED;
98       env += 6;
99     }
100   else if (strncasecmp (env, "auto", 4) == 0)
101     {
102       gomp_global_icv.run_sched_var = GFS_AUTO;
103       env += 4;
104     }
105   else
106     goto unknown;
107
108   while (isspace ((unsigned char) *env))
109     ++env;
110   if (*env == '\0')
111     {
112       gomp_global_icv.run_sched_modifier
113         = gomp_global_icv.run_sched_var != GFS_STATIC;
114       return;
115     }
116   if (*env++ != ',')
117     goto unknown;
118   while (isspace ((unsigned char) *env))
119     ++env;
120   if (*env == '\0')
121     goto invalid;
122
123   errno = 0;
124   value = strtoul (env, &end, 10);
125   if (errno)
126     goto invalid;
127
128   while (isspace ((unsigned char) *end))
129     ++end;
130   if (*end != '\0')
131     goto invalid;
132
133   if ((int)value != value)
134     goto invalid;
135
136   if (value == 0 && gomp_global_icv.run_sched_var != GFS_STATIC)
137     value = 1;
138   gomp_global_icv.run_sched_modifier = value;
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");
148   return;
149 }
150
151 /* Parse an unsigned long environment variable.  Return true if one was
152    present and it was successfully parsed.  */
153
154 static bool
155 parse_unsigned_long (const char *name, unsigned long *pvalue, bool allow_zero)
156 {
157   char *env, *end;
158   unsigned long value;
159
160   env = getenv (name);
161   if (env == NULL)
162     return false;
163
164   while (isspace ((unsigned char) *env))
165     ++env;
166   if (*env == '\0')
167     goto invalid;
168
169   errno = 0;
170   value = strtoul (env, &end, 10);
171   if (errno || (long) value <= 0 - allow_zero)
172     goto invalid;
173
174   while (isspace ((unsigned char) *end))
175     ++end;
176   if (*end != '\0')
177     goto invalid;
178
179   *pvalue = value;
180   return true;
181
182  invalid:
183   gomp_error ("Invalid value for environment variable %s", name);
184   return false;
185 }
186
187 /* Parse an unsigned long list environment variable.  Return true if one was
188    present and it was successfully parsed.  */
189
190 static bool
191 parse_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
276 /* Parse the OMP_STACKSIZE environment varible.  Return true if one was
277    present and it was successfully parsed.  */
278
279 static bool
280 parse_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     {
303       switch (tolower ((unsigned char) *end))
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
340 static bool
341 parse_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     {
372       switch (tolower ((unsigned char) *end))
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
411    result in VALUE.  */
412
413 static void
414 parse_boolean (const char *name, bool *value)
415 {
416   const char *env;
417
418   env = getenv (name);
419   if (env == NULL)
420     return;
421
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     }
434   else
435     env = "X";
436   while (isspace ((unsigned char) *env))
437     ++env;
438   if (*env != '\0')
439     gomp_error ("Invalid value for environment variable %s", name);
440 }
441
442 /* Parse the OMP_WAIT_POLICY environment variable and store the
443    result in gomp_active_wait_policy.  */
444
445 static int
446 parse_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
477 /* Parse the GOMP_CPU_AFFINITY environment varible.  Return true if one was
478    present and it was successfully parsed.  */
479
480 static bool
481 parse_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
568 static void __attribute__((constructor))
569 initialize_env (void)
570 {
571   unsigned long stacksize;
572   int wait_policy;
573   bool bind_var = false;
574
575   /* Do a compile time check that mkomp_h.pl did good job.  */
576   omp_check_defines ();
577
578   parse_schedule ();
579   parse_boolean ("OMP_DYNAMIC", &gomp_global_icv.dyn_var);
580   parse_boolean ("OMP_NESTED", &gomp_global_icv.nest_var);
581   parse_boolean ("OMP_PROC_BIND", &bind_var);
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);
585   if (gomp_thread_limit_var != ULONG_MAX)
586     gomp_remaining_threads_count = gomp_thread_limit_var - 1;
587 #ifndef HAVE_SYNC_BUILTINS
588   gomp_mutex_init (&gomp_remaining_threads_lock);
589 #endif
590   gomp_init_num_threads ();
591   gomp_available_cpus = gomp_global_icv.nthreads_var;
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))
596     gomp_global_icv.nthreads_var = gomp_available_cpus;
597   if (parse_affinity () || bind_var)
598     gomp_init_affinity ();
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,
604          3 msec blocking when OMP_WAIT_POLICY is not specificed
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)
611         gomp_spin_count_var = 300000LL;
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;
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
626   if (parse_stacksize ("OMP_STACKSIZE", &stacksize)
627       || parse_stacksize ("GOMP_STACKSIZE", &stacksize))
628     {
629       int err;
630
631       err = pthread_attr_setstacksize (&gomp_thread_attr, stacksize);
632
633 #ifdef PTHREAD_STACK_MIN
634       if (err == EINVAL)
635         {
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
641             gomp_error ("Stack size larger than system limit");
642         }
643       else
644 #endif
645       if (err != 0)
646         gomp_error ("Stack size change failed: %s", strerror (err));
647     }
648 }
649
650 \f
651 /* The public OpenMP API routines that access these variables.  */
652
653 void
654 omp_set_num_threads (int n)
655 {
656   struct gomp_task_icv *icv = gomp_icv (true);
657   icv->nthreads_var = (n > 0 ? n : 1);
658 }
659
660 void
661 omp_set_dynamic (int val)
662 {
663   struct gomp_task_icv *icv = gomp_icv (true);
664   icv->dyn_var = val;
665 }
666
667 int
668 omp_get_dynamic (void)
669 {
670   struct gomp_task_icv *icv = gomp_icv (false);
671   return icv->dyn_var;
672 }
673
674 void
675 omp_set_nested (int val)
676 {
677   struct gomp_task_icv *icv = gomp_icv (true);
678   icv->nest_var = val;
679 }
680
681 int
682 omp_get_nested (void)
683 {
684   struct gomp_task_icv *icv = gomp_icv (false);
685   return icv->nest_var;
686 }
687
688 void
689 omp_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
713 void
714 omp_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
721 int
722 omp_get_max_threads (void)
723 {
724   struct gomp_task_icv *icv = gomp_icv (false);
725   return icv->nthreads_var;
726 }
727
728 int
729 omp_get_thread_limit (void)
730 {
731   return gomp_thread_limit_var > INT_MAX ? INT_MAX : gomp_thread_limit_var;
732 }
733
734 void
735 omp_set_max_active_levels (int max_levels)
736 {
737   if (max_levels >= 0)
738     gomp_max_active_levels_var = max_levels;
739 }
740
741 int
742 omp_get_max_active_levels (void)
743 {
744   return gomp_max_active_levels_var;
745 }
746
747 ialias (omp_set_dynamic)
748 ialias (omp_set_nested)
749 ialias (omp_set_num_threads)
750 ialias (omp_get_dynamic)
751 ialias (omp_get_nested)
752 ialias (omp_set_schedule)
753 ialias (omp_get_schedule)
754 ialias (omp_get_max_threads)
755 ialias (omp_get_thread_limit)
756 ialias (omp_set_max_active_levels)
757 ialias (omp_get_max_active_levels)