1169695Skan/* Copyright (C) 2005, 2006 Free Software Foundation, Inc.
2169695Skan   Contributed by Richard Henderson <rth@redhat.com>.
3169695Skan
4169695Skan   This file is part of the GNU OpenMP Library (libgomp).
5169695Skan
6169695Skan   Libgomp is free software; you can redistribute it and/or modify it
7169695Skan   under the terms of the GNU Lesser General Public License as published by
8169695Skan   the Free Software Foundation; either version 2.1 of the License, or
9169695Skan   (at your option) any later version.
10169695Skan
11169695Skan   Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
12169695Skan   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13169695Skan   FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
14169695Skan   more details.
15169695Skan
16169695Skan   You should have received a copy of the GNU Lesser General Public License
17169695Skan   along with libgomp; see the file COPYING.LIB.  If not, write to the
18169695Skan   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19169695Skan   MA 02110-1301, USA.  */
20169695Skan
21169695Skan/* As a special exception, if you link this library with other files, some
22169695Skan   of which are compiled with GCC, to produce an executable, this library
23169695Skan   does not by itself cause the resulting executable to be covered by the
24169695Skan   GNU General Public License.  This exception does not however invalidate
25169695Skan   any other reasons why the executable file might be covered by the GNU
26169695Skan   General Public License.  */
27169695Skan
28169695Skan/* This file defines the OpenMP internal control variables, and arranges
29169695Skan   for them to be initialized from environment variables at startup.  */
30169695Skan
31169695Skan#include "libgomp.h"
32169695Skan#include "libgomp_f.h"
33169695Skan#include <ctype.h>
34169695Skan#include <stdlib.h>
35169695Skan#include <string.h>
36169695Skan#include <limits.h>
37169695Skan#include <errno.h>
38169695Skan
39169695Skan
40169695Skanunsigned long gomp_nthreads_var = 1;
41169695Skanbool gomp_dyn_var = false;
42169695Skanbool gomp_nest_var = false;
43169695Skanenum gomp_schedule_type gomp_run_sched_var = GFS_DYNAMIC;
44169695Skanunsigned long gomp_run_sched_chunk = 1;
45169695Skan
46169695Skan/* Parse the OMP_SCHEDULE environment variable.  */
47169695Skan
48169695Skanstatic void
49169695Skanparse_schedule (void)
50169695Skan{
51169695Skan  char *env, *end;
52169695Skan  unsigned long value;
53169695Skan
54169695Skan  env = getenv ("OMP_SCHEDULE");
55169695Skan  if (env == NULL)
56169695Skan    return;
57169695Skan
58169695Skan  while (isspace ((unsigned char) *env))
59169695Skan    ++env;
60169695Skan  if (strncasecmp (env, "static", 6) == 0)
61169695Skan    {
62169695Skan      gomp_run_sched_var = GFS_STATIC;
63169695Skan      env += 6;
64169695Skan    }
65169695Skan  else if (strncasecmp (env, "dynamic", 7) == 0)
66169695Skan    {
67169695Skan      gomp_run_sched_var = GFS_DYNAMIC;
68169695Skan      env += 7;
69169695Skan    }
70169695Skan  else if (strncasecmp (env, "guided", 6) == 0)
71169695Skan    {
72169695Skan      gomp_run_sched_var = GFS_GUIDED;
73169695Skan      env += 6;
74169695Skan    }
75169695Skan  else
76169695Skan    goto unknown;
77169695Skan
78169695Skan  while (isspace ((unsigned char) *env))
79169695Skan    ++env;
80169695Skan  if (*env == '\0')
81169695Skan    return;
82169695Skan  if (*env++ != ',')
83169695Skan    goto unknown;
84169695Skan  while (isspace ((unsigned char) *env))
85169695Skan    ++env;
86169695Skan  if (*env == '\0')
87169695Skan    goto invalid;
88169695Skan
89169695Skan  errno = 0;
90169695Skan  value = strtoul (env, &end, 10);
91169695Skan  if (errno)
92169695Skan    goto invalid;
93169695Skan
94169695Skan  while (isspace ((unsigned char) *end))
95169695Skan    ++end;
96169695Skan  if (*end != '\0')
97169695Skan    goto invalid;
98169695Skan
99169695Skan  gomp_run_sched_chunk = value;
100169695Skan  return;
101169695Skan
102169695Skan unknown:
103169695Skan  gomp_error ("Unknown value for environment variable OMP_SCHEDULE");
104169695Skan  return;
105169695Skan
106169695Skan invalid:
107169695Skan  gomp_error ("Invalid value for chunk size in "
108169695Skan	      "environment variable OMP_SCHEDULE");
109169695Skan  return;
110169695Skan}
111169695Skan
112169695Skan/* Parse an unsigned long environment varible.  Return true if one was
113169695Skan   present and it was successfully parsed.  */
114169695Skan
115169695Skanstatic bool
116169695Skanparse_unsigned_long (const char *name, unsigned long *pvalue)
117169695Skan{
118169695Skan  char *env, *end;
119169695Skan  unsigned long value;
120169695Skan
121169695Skan  env = getenv (name);
122169695Skan  if (env == NULL)
123169695Skan    return false;
124169695Skan
125169695Skan  while (isspace ((unsigned char) *env))
126169695Skan    ++env;
127169695Skan  if (*env == '\0')
128169695Skan    goto invalid;
129169695Skan
130169695Skan  errno = 0;
131169695Skan  value = strtoul (env, &end, 10);
132169695Skan  if (errno || (long) value <= 0)
133169695Skan    goto invalid;
134169695Skan
135169695Skan  while (isspace ((unsigned char) *end))
136169695Skan    ++end;
137169695Skan  if (*end != '\0')
138169695Skan    goto invalid;
139169695Skan
140169695Skan  *pvalue = value;
141169695Skan  return true;
142169695Skan
143169695Skan invalid:
144169695Skan  gomp_error ("Invalid value for environment variable %s", name);
145169695Skan  return false;
146169695Skan}
147169695Skan
148169695Skan/* Parse a boolean value for environment variable NAME and store the
149169695Skan   result in VALUE.  */
150169695Skan
151169695Skanstatic void
152169695Skanparse_boolean (const char *name, bool *value)
153169695Skan{
154169695Skan  const char *env;
155169695Skan
156169695Skan  env = getenv (name);
157169695Skan  if (env == NULL)
158169695Skan    return;
159169695Skan
160169695Skan  while (isspace ((unsigned char) *env))
161169695Skan    ++env;
162169695Skan  if (strncasecmp (env, "true", 4) == 0)
163169695Skan    {
164169695Skan      *value = true;
165169695Skan      env += 4;
166169695Skan    }
167169695Skan  else if (strncasecmp (env, "false", 5) == 0)
168169695Skan    {
169169695Skan      *value = false;
170169695Skan      env += 5;
171169695Skan    }
172169695Skan  else
173169695Skan    env = "X";
174169695Skan  while (isspace ((unsigned char) *env))
175169695Skan    ++env;
176169695Skan  if (*env != '\0')
177169695Skan    gomp_error ("Invalid value for environment variable %s", name);
178169695Skan}
179169695Skan
180169695Skanstatic void __attribute__((constructor))
181169695Skaninitialize_env (void)
182169695Skan{
183169695Skan  unsigned long stacksize;
184169695Skan
185169695Skan  /* Do a compile time check that mkomp_h.pl did good job.  */
186169695Skan  omp_check_defines ();
187169695Skan
188169695Skan  parse_schedule ();
189169695Skan  parse_boolean ("OMP_DYNAMIC", &gomp_dyn_var);
190169695Skan  parse_boolean ("OMP_NESTED", &gomp_nest_var);
191169695Skan  if (!parse_unsigned_long ("OMP_NUM_THREADS", &gomp_nthreads_var))
192169695Skan    gomp_init_num_threads ();
193169695Skan
194169695Skan  /* Not strictly environment related, but ordering constructors is tricky.  */
195169695Skan  pthread_attr_init (&gomp_thread_attr);
196169695Skan  pthread_attr_setdetachstate (&gomp_thread_attr, PTHREAD_CREATE_DETACHED);
197169695Skan
198169695Skan  if (parse_unsigned_long ("GOMP_STACKSIZE", &stacksize))
199169695Skan    {
200169695Skan      int err;
201169695Skan
202169695Skan      stacksize *= 1024;
203169695Skan      err = pthread_attr_setstacksize (&gomp_thread_attr, stacksize);
204169695Skan
205169695Skan#ifdef PTHREAD_STACK_MIN
206169695Skan      if (err == EINVAL)
207169695Skan	{
208169695Skan	  if (stacksize < PTHREAD_STACK_MIN)
209169695Skan	    gomp_error ("Stack size less than minimum of %luk",
210169695Skan			PTHREAD_STACK_MIN / 1024ul
211169695Skan			+ (PTHREAD_STACK_MIN % 1024 != 0));
212169695Skan	  else
213169695Skan	    gomp_error ("Stack size larger than system limit");
214169695Skan	}
215169695Skan      else
216169695Skan#endif
217169695Skan      if (err != 0)
218169695Skan	gomp_error ("Stack size change failed: %s", strerror (err));
219169695Skan    }
220169695Skan}
221169695Skan
222169695Skan
223169695Skan/* The public OpenMP API routines that access these variables.  */
224169695Skan
225169695Skanvoid
226169695Skanomp_set_num_threads (int n)
227169695Skan{
228169695Skan  gomp_nthreads_var = (n > 0 ? n : 1);
229169695Skan}
230169695Skan
231169695Skanvoid
232169695Skanomp_set_dynamic (int val)
233169695Skan{
234169695Skan  gomp_dyn_var = val;
235169695Skan}
236169695Skan
237169695Skanint
238169695Skanomp_get_dynamic (void)
239169695Skan{
240169695Skan  return gomp_dyn_var;
241169695Skan}
242169695Skan
243169695Skanvoid
244169695Skanomp_set_nested (int val)
245169695Skan{
246169695Skan  gomp_nest_var = val;
247169695Skan}
248169695Skan
249169695Skanint
250169695Skanomp_get_nested (void)
251169695Skan{
252169695Skan  return gomp_nest_var;
253169695Skan}
254169695Skan
255169695Skanialias (omp_set_dynamic)
256169695Skanialias (omp_set_nested)
257169695Skanialias (omp_set_num_threads)
258169695Skanialias (omp_get_dynamic)
259169695Skanialias (omp_get_nested)
260