re PR libgomp/33131 (libgomp/env.c:60: warning: implicit declaration of function...
[platform/upstream/gcc.git] / libgomp / env.c
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 #ifdef STRING_WITH_STRINGS
36 # include <string.h>
37 # include <strings.h>
38 #else
39 # ifdef HAVE_STRING_H
40 #  include <string.h>
41 # else
42 #  ifdef HAVE_STRINGS_H
43 #   include <strings.h>
44 #  endif
45 # endif
46 #endif
47 #include <limits.h>
48 #include <errno.h>
49
50
51 unsigned long gomp_nthreads_var = 1;
52 bool gomp_dyn_var = false;
53 bool gomp_nest_var = false;
54 enum gomp_schedule_type gomp_run_sched_var = GFS_DYNAMIC;
55 unsigned long gomp_run_sched_chunk = 1;
56 unsigned short *gomp_cpu_affinity;
57 size_t gomp_cpu_affinity_len;
58
59 /* Parse the OMP_SCHEDULE environment variable.  */
60
61 static void
62 parse_schedule (void)
63 {
64   char *env, *end;
65   unsigned long value;
66
67   env = getenv ("OMP_SCHEDULE");
68   if (env == NULL)
69     return;
70
71   while (isspace ((unsigned char) *env))
72     ++env;
73   if (strncasecmp (env, "static", 6) == 0)
74     {
75       gomp_run_sched_var = GFS_STATIC;
76       env += 6;
77     }
78   else if (strncasecmp (env, "dynamic", 7) == 0)
79     {
80       gomp_run_sched_var = GFS_DYNAMIC;
81       env += 7;
82     }
83   else if (strncasecmp (env, "guided", 6) == 0)
84     {
85       gomp_run_sched_var = GFS_GUIDED;
86       env += 6;
87     }
88   else
89     goto unknown;
90
91   while (isspace ((unsigned char) *env))
92     ++env;
93   if (*env == '\0')
94     return;
95   if (*env++ != ',')
96     goto unknown;
97   while (isspace ((unsigned char) *env))
98     ++env;
99   if (*env == '\0')
100     goto invalid;
101
102   errno = 0;
103   value = strtoul (env, &end, 10);
104   if (errno)
105     goto invalid;
106
107   while (isspace ((unsigned char) *end))
108     ++end;
109   if (*end != '\0')
110     goto invalid;
111
112   gomp_run_sched_chunk = value;
113   return;
114
115  unknown:
116   gomp_error ("Unknown value for environment variable OMP_SCHEDULE");
117   return;
118
119  invalid:
120   gomp_error ("Invalid value for chunk size in "
121               "environment variable OMP_SCHEDULE");
122   return;
123 }
124
125 /* Parse an unsigned long environment varible.  Return true if one was
126    present and it was successfully parsed.  */
127
128 static bool
129 parse_unsigned_long (const char *name, unsigned long *pvalue)
130 {
131   char *env, *end;
132   unsigned long value;
133
134   env = getenv (name);
135   if (env == NULL)
136     return false;
137
138   while (isspace ((unsigned char) *env))
139     ++env;
140   if (*env == '\0')
141     goto invalid;
142
143   errno = 0;
144   value = strtoul (env, &end, 10);
145   if (errno || (long) value <= 0)
146     goto invalid;
147
148   while (isspace ((unsigned char) *end))
149     ++end;
150   if (*end != '\0')
151     goto invalid;
152
153   *pvalue = value;
154   return true;
155
156  invalid:
157   gomp_error ("Invalid value for environment variable %s", name);
158   return false;
159 }
160
161 /* Parse a boolean value for environment variable NAME and store the 
162    result in VALUE.  */
163
164 static void
165 parse_boolean (const char *name, bool *value)
166 {
167   const char *env;
168
169   env = getenv (name);
170   if (env == NULL)
171     return;
172
173   while (isspace ((unsigned char) *env))
174     ++env;
175   if (strncasecmp (env, "true", 4) == 0)
176     {
177       *value = true;
178       env += 4;
179     }
180   else if (strncasecmp (env, "false", 5) == 0)
181     {
182       *value = false;
183       env += 5;
184     }
185   else
186     env = "X";
187   while (isspace ((unsigned char) *env))
188     ++env;
189   if (*env != '\0')
190     gomp_error ("Invalid value for environment variable %s", name);
191 }
192
193 /* Parse the GOMP_CPU_AFFINITY environment varible.  Return true if one was
194    present and it was successfully parsed.  */
195
196 static bool
197 parse_affinity (void)
198 {
199   char *env, *end;
200   unsigned long cpu_beg, cpu_end, cpu_stride;
201   unsigned short *cpus = NULL;
202   size_t allocated = 0, used = 0, needed;
203
204   env = getenv ("GOMP_CPU_AFFINITY");
205   if (env == NULL)
206     return false;
207
208   do
209     {
210       while (*env == ' ' || *env == '\t')
211         env++;
212
213       cpu_beg = strtoul (env, &end, 0);
214       cpu_end = cpu_beg;
215       cpu_stride = 1;
216       if (env == end || cpu_beg >= 65536)
217         goto invalid;
218
219       env = end;
220       if (*env == '-')
221         {
222           cpu_end = strtoul (++env, &end, 0);
223           if (env == end || cpu_end >= 65536 || cpu_end < cpu_beg)
224             goto invalid;
225
226           env = end;
227           if (*env == ':')
228             {
229               cpu_stride = strtoul (++env, &end, 0);
230               if (env == end || cpu_stride == 0 || cpu_stride >= 65536)
231                 goto invalid;
232
233               env = end;
234             }
235         }
236
237       needed = (cpu_end - cpu_beg) / cpu_stride + 1;
238       if (used + needed >= allocated)
239         {
240           unsigned short *new_cpus;
241
242           if (allocated < 64)
243             allocated = 64;
244           if (allocated > needed)
245             allocated <<= 1;
246           else
247             allocated += 2 * needed;
248           new_cpus = realloc (cpus, allocated * sizeof (unsigned short));
249           if (new_cpus == NULL)
250             {
251               free (cpus);
252               gomp_error ("not enough memory to store GOMP_CPU_AFFINITY list");
253               return false;
254             }
255
256           cpus = new_cpus;
257         }
258
259       while (needed--)
260         {
261           cpus[used++] = cpu_beg;
262           cpu_beg += cpu_stride;
263         }
264
265       while (*env == ' ' || *env == '\t')
266         env++;
267
268       if (*env == ',')
269         env++;
270       else if (*env == '\0')
271         break;
272     }
273   while (1);
274
275   gomp_cpu_affinity = cpus;
276   gomp_cpu_affinity_len = used;
277   return true;
278
279  invalid:
280   gomp_error ("Invalid value for enviroment variable GOMP_CPU_AFFINITY");
281   return false;
282 }
283
284 static void __attribute__((constructor))
285 initialize_env (void)
286 {
287   unsigned long stacksize;
288
289   /* Do a compile time check that mkomp_h.pl did good job.  */
290   omp_check_defines ();
291
292   parse_schedule ();
293   parse_boolean ("OMP_DYNAMIC", &gomp_dyn_var);
294   parse_boolean ("OMP_NESTED", &gomp_nest_var);
295   if (!parse_unsigned_long ("OMP_NUM_THREADS", &gomp_nthreads_var))
296     gomp_init_num_threads ();
297   if (parse_affinity ())
298     gomp_init_affinity ();
299
300   /* Not strictly environment related, but ordering constructors is tricky.  */
301   pthread_attr_init (&gomp_thread_attr);
302   pthread_attr_setdetachstate (&gomp_thread_attr, PTHREAD_CREATE_DETACHED);
303
304   if (parse_unsigned_long ("GOMP_STACKSIZE", &stacksize))
305     {
306       int err;
307
308       stacksize *= 1024;
309       err = pthread_attr_setstacksize (&gomp_thread_attr, stacksize);
310
311 #ifdef PTHREAD_STACK_MIN
312       if (err == EINVAL)
313         {
314           if (stacksize < PTHREAD_STACK_MIN)
315             gomp_error ("Stack size less than minimum of %luk",
316                         PTHREAD_STACK_MIN / 1024ul
317                         + (PTHREAD_STACK_MIN % 1024 != 0));
318           else
319             gomp_error ("Stack size larger than system limit");
320         }
321       else
322 #endif
323       if (err != 0)
324         gomp_error ("Stack size change failed: %s", strerror (err));
325     }
326 }
327
328 \f
329 /* The public OpenMP API routines that access these variables.  */
330
331 void
332 omp_set_num_threads (int n)
333 {
334   gomp_nthreads_var = (n > 0 ? n : 1);
335 }
336
337 void
338 omp_set_dynamic (int val)
339 {
340   gomp_dyn_var = val;
341 }
342
343 int
344 omp_get_dynamic (void)
345 {
346   return gomp_dyn_var;
347 }
348
349 void
350 omp_set_nested (int val)
351 {
352   gomp_nest_var = val;
353 }
354
355 int
356 omp_get_nested (void)
357 {
358   return gomp_nest_var;
359 }
360
361 ialias (omp_set_dynamic)
362 ialias (omp_set_nested)
363 ialias (omp_set_num_threads)
364 ialias (omp_get_dynamic)
365 ialias (omp_get_nested)