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