1282115Spfg/* Copyright (C) 2005, 2006, 2007 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; 45282115Spfgunsigned short *gomp_cpu_affinity; 46282115Spfgsize_t gomp_cpu_affinity_len; 47169695Skan 48169695Skan/* Parse the OMP_SCHEDULE environment variable. */ 49169695Skan 50169695Skanstatic void 51169695Skanparse_schedule (void) 52169695Skan{ 53169695Skan char *env, *end; 54169695Skan unsigned long value; 55169695Skan 56169695Skan env = getenv ("OMP_SCHEDULE"); 57169695Skan if (env == NULL) 58169695Skan return; 59169695Skan 60169695Skan while (isspace ((unsigned char) *env)) 61169695Skan ++env; 62169695Skan if (strncasecmp (env, "static", 6) == 0) 63169695Skan { 64169695Skan gomp_run_sched_var = GFS_STATIC; 65169695Skan env += 6; 66169695Skan } 67169695Skan else if (strncasecmp (env, "dynamic", 7) == 0) 68169695Skan { 69169695Skan gomp_run_sched_var = GFS_DYNAMIC; 70169695Skan env += 7; 71169695Skan } 72169695Skan else if (strncasecmp (env, "guided", 6) == 0) 73169695Skan { 74169695Skan gomp_run_sched_var = GFS_GUIDED; 75169695Skan env += 6; 76169695Skan } 77169695Skan else 78169695Skan goto unknown; 79169695Skan 80169695Skan while (isspace ((unsigned char) *env)) 81169695Skan ++env; 82169695Skan if (*env == '\0') 83169695Skan return; 84169695Skan if (*env++ != ',') 85169695Skan goto unknown; 86169695Skan while (isspace ((unsigned char) *env)) 87169695Skan ++env; 88169695Skan if (*env == '\0') 89169695Skan goto invalid; 90169695Skan 91169695Skan errno = 0; 92169695Skan value = strtoul (env, &end, 10); 93169695Skan if (errno) 94169695Skan goto invalid; 95169695Skan 96169695Skan while (isspace ((unsigned char) *end)) 97169695Skan ++end; 98169695Skan if (*end != '\0') 99169695Skan goto invalid; 100169695Skan 101169695Skan gomp_run_sched_chunk = value; 102169695Skan return; 103169695Skan 104169695Skan unknown: 105169695Skan gomp_error ("Unknown value for environment variable OMP_SCHEDULE"); 106169695Skan return; 107169695Skan 108169695Skan invalid: 109169695Skan gomp_error ("Invalid value for chunk size in " 110169695Skan "environment variable OMP_SCHEDULE"); 111169695Skan return; 112169695Skan} 113169695Skan 114169695Skan/* Parse an unsigned long environment varible. Return true if one was 115169695Skan present and it was successfully parsed. */ 116169695Skan 117169695Skanstatic bool 118169695Skanparse_unsigned_long (const char *name, unsigned long *pvalue) 119169695Skan{ 120169695Skan char *env, *end; 121169695Skan unsigned long value; 122169695Skan 123169695Skan env = getenv (name); 124169695Skan if (env == NULL) 125169695Skan return false; 126169695Skan 127169695Skan while (isspace ((unsigned char) *env)) 128169695Skan ++env; 129169695Skan if (*env == '\0') 130169695Skan goto invalid; 131169695Skan 132169695Skan errno = 0; 133169695Skan value = strtoul (env, &end, 10); 134169695Skan if (errno || (long) value <= 0) 135169695Skan goto invalid; 136169695Skan 137169695Skan while (isspace ((unsigned char) *end)) 138169695Skan ++end; 139169695Skan if (*end != '\0') 140169695Skan goto invalid; 141169695Skan 142169695Skan *pvalue = value; 143169695Skan return true; 144169695Skan 145169695Skan invalid: 146169695Skan gomp_error ("Invalid value for environment variable %s", name); 147169695Skan return false; 148169695Skan} 149169695Skan 150169695Skan/* Parse a boolean value for environment variable NAME and store the 151169695Skan result in VALUE. */ 152169695Skan 153169695Skanstatic void 154169695Skanparse_boolean (const char *name, bool *value) 155169695Skan{ 156169695Skan const char *env; 157169695Skan 158169695Skan env = getenv (name); 159169695Skan if (env == NULL) 160169695Skan return; 161169695Skan 162169695Skan while (isspace ((unsigned char) *env)) 163169695Skan ++env; 164169695Skan if (strncasecmp (env, "true", 4) == 0) 165169695Skan { 166169695Skan *value = true; 167169695Skan env += 4; 168169695Skan } 169169695Skan else if (strncasecmp (env, "false", 5) == 0) 170169695Skan { 171169695Skan *value = false; 172169695Skan env += 5; 173169695Skan } 174169695Skan else 175169695Skan env = "X"; 176169695Skan while (isspace ((unsigned char) *env)) 177169695Skan ++env; 178169695Skan if (*env != '\0') 179169695Skan gomp_error ("Invalid value for environment variable %s", name); 180169695Skan} 181169695Skan 182282115Spfg/* Parse the GOMP_CPU_AFFINITY environment varible. Return true if one was 183282115Spfg present and it was successfully parsed. */ 184282115Spfg 185282115Spfgstatic bool 186282115Spfgparse_affinity (void) 187282115Spfg{ 188282115Spfg char *env, *end; 189282115Spfg unsigned long cpu_beg, cpu_end, cpu_stride; 190282115Spfg unsigned short *cpus = NULL; 191282115Spfg size_t allocated = 0, used = 0, needed; 192282115Spfg 193282115Spfg env = getenv ("GOMP_CPU_AFFINITY"); 194282115Spfg if (env == NULL) 195282115Spfg return false; 196282115Spfg 197282115Spfg do 198282115Spfg { 199282115Spfg while (*env == ' ' || *env == '\t') 200282115Spfg env++; 201282115Spfg 202282115Spfg cpu_beg = strtoul (env, &end, 0); 203282115Spfg cpu_end = cpu_beg; 204282115Spfg cpu_stride = 1; 205282115Spfg if (env == end || cpu_beg >= 65536) 206282115Spfg goto invalid; 207282115Spfg 208282115Spfg env = end; 209282115Spfg if (*env == '-') 210282115Spfg { 211282115Spfg cpu_end = strtoul (++env, &end, 0); 212282115Spfg if (env == end || cpu_end >= 65536 || cpu_end < cpu_beg) 213282115Spfg goto invalid; 214282115Spfg 215282115Spfg env = end; 216282115Spfg if (*env == ':') 217282115Spfg { 218282115Spfg cpu_stride = strtoul (++env, &end, 0); 219282115Spfg if (env == end || cpu_stride == 0 || cpu_stride >= 65536) 220282115Spfg goto invalid; 221282115Spfg 222282115Spfg env = end; 223282115Spfg } 224282115Spfg } 225282115Spfg 226282115Spfg needed = (cpu_end - cpu_beg) / cpu_stride + 1; 227282115Spfg if (used + needed >= allocated) 228282115Spfg { 229282115Spfg unsigned short *new_cpus; 230282115Spfg 231282115Spfg if (allocated < 64) 232282115Spfg allocated = 64; 233282115Spfg if (allocated > needed) 234282115Spfg allocated <<= 1; 235282115Spfg else 236282115Spfg allocated += 2 * needed; 237282115Spfg new_cpus = realloc (cpus, allocated * sizeof (unsigned short)); 238282115Spfg if (new_cpus == NULL) 239282115Spfg { 240282115Spfg free (cpus); 241282115Spfg gomp_error ("not enough memory to store GOMP_CPU_AFFINITY list"); 242282115Spfg return false; 243282115Spfg } 244282115Spfg 245282115Spfg cpus = new_cpus; 246282115Spfg } 247282115Spfg 248282115Spfg while (needed--) 249282115Spfg { 250282115Spfg cpus[used++] = cpu_beg; 251282115Spfg cpu_beg += cpu_stride; 252282115Spfg } 253282115Spfg 254282115Spfg while (*env == ' ' || *env == '\t') 255282115Spfg env++; 256282115Spfg 257282115Spfg if (*env == ',') 258282115Spfg env++; 259282115Spfg else if (*env == '\0') 260282115Spfg break; 261282115Spfg } 262282115Spfg while (1); 263282115Spfg 264282115Spfg gomp_cpu_affinity = cpus; 265282115Spfg gomp_cpu_affinity_len = used; 266282115Spfg return true; 267282115Spfg 268282115Spfg invalid: 269282115Spfg gomp_error ("Invalid value for enviroment variable GOMP_CPU_AFFINITY"); 270282115Spfg return false; 271282115Spfg} 272282115Spfg 273169695Skanstatic void __attribute__((constructor)) 274169695Skaninitialize_env (void) 275169695Skan{ 276169695Skan unsigned long stacksize; 277169695Skan 278169695Skan /* Do a compile time check that mkomp_h.pl did good job. */ 279169695Skan omp_check_defines (); 280169695Skan 281169695Skan parse_schedule (); 282169695Skan parse_boolean ("OMP_DYNAMIC", &gomp_dyn_var); 283169695Skan parse_boolean ("OMP_NESTED", &gomp_nest_var); 284169695Skan if (!parse_unsigned_long ("OMP_NUM_THREADS", &gomp_nthreads_var)) 285169695Skan gomp_init_num_threads (); 286282115Spfg if (parse_affinity ()) 287282115Spfg gomp_init_affinity (); 288169695Skan 289169695Skan /* Not strictly environment related, but ordering constructors is tricky. */ 290169695Skan pthread_attr_init (&gomp_thread_attr); 291169695Skan pthread_attr_setdetachstate (&gomp_thread_attr, PTHREAD_CREATE_DETACHED); 292169695Skan 293169695Skan if (parse_unsigned_long ("GOMP_STACKSIZE", &stacksize)) 294169695Skan { 295169695Skan int err; 296169695Skan 297169695Skan stacksize *= 1024; 298169695Skan err = pthread_attr_setstacksize (&gomp_thread_attr, stacksize); 299169695Skan 300169695Skan#ifdef PTHREAD_STACK_MIN 301169695Skan if (err == EINVAL) 302169695Skan { 303169695Skan if (stacksize < PTHREAD_STACK_MIN) 304169695Skan gomp_error ("Stack size less than minimum of %luk", 305169695Skan PTHREAD_STACK_MIN / 1024ul 306169695Skan + (PTHREAD_STACK_MIN % 1024 != 0)); 307169695Skan else 308169695Skan gomp_error ("Stack size larger than system limit"); 309169695Skan } 310169695Skan else 311169695Skan#endif 312169695Skan if (err != 0) 313169695Skan gomp_error ("Stack size change failed: %s", strerror (err)); 314169695Skan } 315169695Skan} 316169695Skan 317169695Skan 318169695Skan/* The public OpenMP API routines that access these variables. */ 319169695Skan 320169695Skanvoid 321169695Skanomp_set_num_threads (int n) 322169695Skan{ 323169695Skan gomp_nthreads_var = (n > 0 ? n : 1); 324169695Skan} 325169695Skan 326169695Skanvoid 327169695Skanomp_set_dynamic (int val) 328169695Skan{ 329169695Skan gomp_dyn_var = val; 330169695Skan} 331169695Skan 332169695Skanint 333169695Skanomp_get_dynamic (void) 334169695Skan{ 335169695Skan return gomp_dyn_var; 336169695Skan} 337169695Skan 338169695Skanvoid 339169695Skanomp_set_nested (int val) 340169695Skan{ 341169695Skan gomp_nest_var = val; 342169695Skan} 343169695Skan 344169695Skanint 345169695Skanomp_get_nested (void) 346169695Skan{ 347169695Skan return gomp_nest_var; 348169695Skan} 349169695Skan 350169695Skanialias (omp_set_dynamic) 351169695Skanialias (omp_set_nested) 352169695Skanialias (omp_set_num_threads) 353169695Skanialias (omp_get_dynamic) 354169695Skanialias (omp_get_nested) 355