env.c revision 283010
1/* Copyright (C) 2005, 2006, 2007 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 Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) 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 Lesser General Public License for
14   more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with libgomp; see the file COPYING.LIB.  If not, write to the
18   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19   MA 02110-1301, USA.  */
20
21/* As a special exception, if you link this library with other files, some
22   of which are compiled with GCC, to produce an executable, this library
23   does not by itself cause the resulting executable to be covered by the
24   GNU General Public License.  This exception does not however invalidate
25   any other reasons why the executable file might be covered by the GNU
26   General Public License.  */
27
28/* This file defines the OpenMP internal control variables, and arranges
29   for them to be initialized from environment variables at startup.  */
30
31#include "libgomp.h"
32#include "libgomp_f.h"
33#include <ctype.h>
34#include <stdlib.h>
35#include <string.h>
36#include <limits.h>
37#include <errno.h>
38
39
40unsigned long gomp_nthreads_var = 1;
41bool gomp_dyn_var = false;
42bool gomp_nest_var = false;
43enum gomp_schedule_type gomp_run_sched_var = GFS_DYNAMIC;
44unsigned long gomp_run_sched_chunk = 1;
45unsigned short *gomp_cpu_affinity;
46size_t gomp_cpu_affinity_len;
47
48/* Parse the OMP_SCHEDULE environment variable.  */
49
50static void
51parse_schedule (void)
52{
53  char *env, *end;
54  unsigned long value;
55
56  env = getenv ("OMP_SCHEDULE");
57  if (env == NULL)
58    return;
59
60  while (isspace ((unsigned char) *env))
61    ++env;
62  if (strncasecmp (env, "static", 6) == 0)
63    {
64      gomp_run_sched_var = GFS_STATIC;
65      env += 6;
66    }
67  else if (strncasecmp (env, "dynamic", 7) == 0)
68    {
69      gomp_run_sched_var = GFS_DYNAMIC;
70      env += 7;
71    }
72  else if (strncasecmp (env, "guided", 6) == 0)
73    {
74      gomp_run_sched_var = GFS_GUIDED;
75      env += 6;
76    }
77  else
78    goto unknown;
79
80  while (isspace ((unsigned char) *env))
81    ++env;
82  if (*env == '\0')
83    return;
84  if (*env++ != ',')
85    goto unknown;
86  while (isspace ((unsigned char) *env))
87    ++env;
88  if (*env == '\0')
89    goto invalid;
90
91  errno = 0;
92  value = strtoul (env, &end, 10);
93  if (errno)
94    goto invalid;
95
96  while (isspace ((unsigned char) *end))
97    ++end;
98  if (*end != '\0')
99    goto invalid;
100
101  gomp_run_sched_chunk = value;
102  return;
103
104 unknown:
105  gomp_error ("Unknown value for environment variable OMP_SCHEDULE");
106  return;
107
108 invalid:
109  gomp_error ("Invalid value for chunk size in "
110	      "environment variable OMP_SCHEDULE");
111  return;
112}
113
114/* Parse an unsigned long environment varible.  Return true if one was
115   present and it was successfully parsed.  */
116
117static bool
118parse_unsigned_long (const char *name, unsigned long *pvalue)
119{
120  char *env, *end;
121  unsigned long value;
122
123  env = getenv (name);
124  if (env == NULL)
125    return false;
126
127  while (isspace ((unsigned char) *env))
128    ++env;
129  if (*env == '\0')
130    goto invalid;
131
132  errno = 0;
133  value = strtoul (env, &end, 10);
134  if (errno || (long) value <= 0)
135    goto invalid;
136
137  while (isspace ((unsigned char) *end))
138    ++end;
139  if (*end != '\0')
140    goto invalid;
141
142  *pvalue = value;
143  return true;
144
145 invalid:
146  gomp_error ("Invalid value for environment variable %s", name);
147  return false;
148}
149
150/* Parse a boolean value for environment variable NAME and store the
151   result in VALUE.  */
152
153static void
154parse_boolean (const char *name, bool *value)
155{
156  const char *env;
157
158  env = getenv (name);
159  if (env == NULL)
160    return;
161
162  while (isspace ((unsigned char) *env))
163    ++env;
164  if (strncasecmp (env, "true", 4) == 0)
165    {
166      *value = true;
167      env += 4;
168    }
169  else if (strncasecmp (env, "false", 5) == 0)
170    {
171      *value = false;
172      env += 5;
173    }
174  else
175    env = "X";
176  while (isspace ((unsigned char) *env))
177    ++env;
178  if (*env != '\0')
179    gomp_error ("Invalid value for environment variable %s", name);
180}
181
182/* Parse the GOMP_CPU_AFFINITY environment varible.  Return true if one was
183   present and it was successfully parsed.  */
184
185static bool
186parse_affinity (void)
187{
188  char *env, *end;
189  unsigned long cpu_beg, cpu_end, cpu_stride;
190  unsigned short *cpus = NULL;
191  size_t allocated = 0, used = 0, needed;
192
193  env = getenv ("GOMP_CPU_AFFINITY");
194  if (env == NULL)
195    return false;
196
197  do
198    {
199      while (*env == ' ' || *env == '\t')
200	env++;
201
202      cpu_beg = strtoul (env, &end, 0);
203      cpu_end = cpu_beg;
204      cpu_stride = 1;
205      if (env == end || cpu_beg >= 65536)
206	goto invalid;
207
208      env = end;
209      if (*env == '-')
210	{
211	  cpu_end = strtoul (++env, &end, 0);
212	  if (env == end || cpu_end >= 65536 || cpu_end < cpu_beg)
213	    goto invalid;
214
215	  env = end;
216	  if (*env == ':')
217	    {
218	      cpu_stride = strtoul (++env, &end, 0);
219	      if (env == end || cpu_stride == 0 || cpu_stride >= 65536)
220		goto invalid;
221
222	      env = end;
223	    }
224	}
225
226      needed = (cpu_end - cpu_beg) / cpu_stride + 1;
227      if (used + needed >= allocated)
228	{
229	  unsigned short *new_cpus;
230
231	  if (allocated < 64)
232	    allocated = 64;
233	  if (allocated > needed)
234	    allocated <<= 1;
235	  else
236	    allocated += 2 * needed;
237	  new_cpus = realloc (cpus, allocated * sizeof (unsigned short));
238	  if (new_cpus == NULL)
239	    {
240	      free (cpus);
241	      gomp_error ("not enough memory to store GOMP_CPU_AFFINITY list");
242	      return false;
243	    }
244
245	  cpus = new_cpus;
246	}
247
248      while (needed--)
249	{
250	  cpus[used++] = cpu_beg;
251	  cpu_beg += cpu_stride;
252	}
253
254      while (*env == ' ' || *env == '\t')
255	env++;
256
257      if (*env == ',')
258	env++;
259      else if (*env == '\0')
260	break;
261    }
262  while (1);
263
264  gomp_cpu_affinity = cpus;
265  gomp_cpu_affinity_len = used;
266  return true;
267
268 invalid:
269  gomp_error ("Invalid value for enviroment variable GOMP_CPU_AFFINITY");
270  return false;
271}
272
273static void __attribute__((constructor))
274initialize_env (void)
275{
276  unsigned long stacksize;
277
278  /* Do a compile time check that mkomp_h.pl did good job.  */
279  omp_check_defines ();
280
281  parse_schedule ();
282  parse_boolean ("OMP_DYNAMIC", &gomp_dyn_var);
283  parse_boolean ("OMP_NESTED", &gomp_nest_var);
284  if (!parse_unsigned_long ("OMP_NUM_THREADS", &gomp_nthreads_var))
285    gomp_init_num_threads ();
286  if (parse_affinity ())
287    gomp_init_affinity ();
288
289  /* Not strictly environment related, but ordering constructors is tricky.  */
290  pthread_attr_init (&gomp_thread_attr);
291  pthread_attr_setdetachstate (&gomp_thread_attr, PTHREAD_CREATE_DETACHED);
292
293  if (parse_unsigned_long ("GOMP_STACKSIZE", &stacksize))
294    {
295      int err;
296
297      stacksize *= 1024;
298      err = pthread_attr_setstacksize (&gomp_thread_attr, stacksize);
299
300#ifdef PTHREAD_STACK_MIN
301      if (err == EINVAL)
302	{
303	  if (stacksize < PTHREAD_STACK_MIN)
304	    gomp_error ("Stack size less than minimum of %luk",
305			PTHREAD_STACK_MIN / 1024ul
306			+ (PTHREAD_STACK_MIN % 1024 != 0));
307	  else
308	    gomp_error ("Stack size larger than system limit");
309	}
310      else
311#endif
312      if (err != 0)
313	gomp_error ("Stack size change failed: %s", strerror (err));
314    }
315}
316
317
318/* The public OpenMP API routines that access these variables.  */
319
320void
321omp_set_num_threads (int n)
322{
323  gomp_nthreads_var = (n > 0 ? n : 1);
324}
325
326void
327omp_set_dynamic (int val)
328{
329  gomp_dyn_var = val;
330}
331
332int
333omp_get_dynamic (void)
334{
335  return gomp_dyn_var;
336}
337
338void
339omp_set_nested (int val)
340{
341  gomp_nest_var = val;
342}
343
344int
345omp_get_nested (void)
346{
347  return gomp_nest_var;
348}
349
350ialias (omp_set_dynamic)
351ialias (omp_set_nested)
352ialias (omp_set_num_threads)
353ialias (omp_get_dynamic)
354ialias (omp_get_nested)
355