1/* Copyright (C) 2005, 2006 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;
45
46/* Parse the OMP_SCHEDULE environment variable.  */
47
48static void
49parse_schedule (void)
50{
51  char *env, *end;
52  unsigned long value;
53
54  env = getenv ("OMP_SCHEDULE");
55  if (env == NULL)
56    return;
57
58  while (isspace ((unsigned char) *env))
59    ++env;
60  if (strncasecmp (env, "static", 6) == 0)
61    {
62      gomp_run_sched_var = GFS_STATIC;
63      env += 6;
64    }
65  else if (strncasecmp (env, "dynamic", 7) == 0)
66    {
67      gomp_run_sched_var = GFS_DYNAMIC;
68      env += 7;
69    }
70  else if (strncasecmp (env, "guided", 6) == 0)
71    {
72      gomp_run_sched_var = GFS_GUIDED;
73      env += 6;
74    }
75  else
76    goto unknown;
77
78  while (isspace ((unsigned char) *env))
79    ++env;
80  if (*env == '\0')
81    return;
82  if (*env++ != ',')
83    goto unknown;
84  while (isspace ((unsigned char) *env))
85    ++env;
86  if (*env == '\0')
87    goto invalid;
88
89  errno = 0;
90  value = strtoul (env, &end, 10);
91  if (errno)
92    goto invalid;
93
94  while (isspace ((unsigned char) *end))
95    ++end;
96  if (*end != '\0')
97    goto invalid;
98
99  gomp_run_sched_chunk = value;
100  return;
101
102 unknown:
103  gomp_error ("Unknown value for environment variable OMP_SCHEDULE");
104  return;
105
106 invalid:
107  gomp_error ("Invalid value for chunk size in "
108	      "environment variable OMP_SCHEDULE");
109  return;
110}
111
112/* Parse an unsigned long environment varible.  Return true if one was
113   present and it was successfully parsed.  */
114
115static bool
116parse_unsigned_long (const char *name, unsigned long *pvalue)
117{
118  char *env, *end;
119  unsigned long value;
120
121  env = getenv (name);
122  if (env == NULL)
123    return false;
124
125  while (isspace ((unsigned char) *env))
126    ++env;
127  if (*env == '\0')
128    goto invalid;
129
130  errno = 0;
131  value = strtoul (env, &end, 10);
132  if (errno || (long) value <= 0)
133    goto invalid;
134
135  while (isspace ((unsigned char) *end))
136    ++end;
137  if (*end != '\0')
138    goto invalid;
139
140  *pvalue = value;
141  return true;
142
143 invalid:
144  gomp_error ("Invalid value for environment variable %s", name);
145  return false;
146}
147
148/* Parse a boolean value for environment variable NAME and store the
149   result in VALUE.  */
150
151static void
152parse_boolean (const char *name, bool *value)
153{
154  const char *env;
155
156  env = getenv (name);
157  if (env == NULL)
158    return;
159
160  while (isspace ((unsigned char) *env))
161    ++env;
162  if (strncasecmp (env, "true", 4) == 0)
163    {
164      *value = true;
165      env += 4;
166    }
167  else if (strncasecmp (env, "false", 5) == 0)
168    {
169      *value = false;
170      env += 5;
171    }
172  else
173    env = "X";
174  while (isspace ((unsigned char) *env))
175    ++env;
176  if (*env != '\0')
177    gomp_error ("Invalid value for environment variable %s", name);
178}
179
180static void __attribute__((constructor))
181initialize_env (void)
182{
183  unsigned long stacksize;
184
185  /* Do a compile time check that mkomp_h.pl did good job.  */
186  omp_check_defines ();
187
188  parse_schedule ();
189  parse_boolean ("OMP_DYNAMIC", &gomp_dyn_var);
190  parse_boolean ("OMP_NESTED", &gomp_nest_var);
191  if (!parse_unsigned_long ("OMP_NUM_THREADS", &gomp_nthreads_var))
192    gomp_init_num_threads ();
193
194  /* Not strictly environment related, but ordering constructors is tricky.  */
195  pthread_attr_init (&gomp_thread_attr);
196  pthread_attr_setdetachstate (&gomp_thread_attr, PTHREAD_CREATE_DETACHED);
197
198  if (parse_unsigned_long ("GOMP_STACKSIZE", &stacksize))
199    {
200      int err;
201
202      stacksize *= 1024;
203      err = pthread_attr_setstacksize (&gomp_thread_attr, stacksize);
204
205#ifdef PTHREAD_STACK_MIN
206      if (err == EINVAL)
207	{
208	  if (stacksize < PTHREAD_STACK_MIN)
209	    gomp_error ("Stack size less than minimum of %luk",
210			PTHREAD_STACK_MIN / 1024ul
211			+ (PTHREAD_STACK_MIN % 1024 != 0));
212	  else
213	    gomp_error ("Stack size larger than system limit");
214	}
215      else
216#endif
217      if (err != 0)
218	gomp_error ("Stack size change failed: %s", strerror (err));
219    }
220}
221
222
223/* The public OpenMP API routines that access these variables.  */
224
225void
226omp_set_num_threads (int n)
227{
228  gomp_nthreads_var = (n > 0 ? n : 1);
229}
230
231void
232omp_set_dynamic (int val)
233{
234  gomp_dyn_var = val;
235}
236
237int
238omp_get_dynamic (void)
239{
240  return gomp_dyn_var;
241}
242
243void
244omp_set_nested (int val)
245{
246  gomp_nest_var = val;
247}
248
249int
250omp_get_nested (void)
251{
252  return gomp_nest_var;
253}
254
255ialias (omp_set_dynamic)
256ialias (omp_set_nested)
257ialias (omp_set_num_threads)
258ialias (omp_get_dynamic)
259ialias (omp_get_nested)
260