]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/openmp/runtime/src/kmp_environment.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / openmp / runtime / src / kmp_environment.cpp
1 /*
2  * kmp_environment.cpp -- Handle environment variables OS-independently.
3  */
4
5 //===----------------------------------------------------------------------===//
6 //
7 //                     The LLVM Compiler Infrastructure
8 //
9 // This file is dual licensed under the MIT and the University of Illinois Open
10 // Source Licenses. See LICENSE.txt for details.
11 //
12 //===----------------------------------------------------------------------===//
13
14 /* We use GetEnvironmentVariable for Windows* OS instead of getenv because the
15    act of loading a DLL on Windows* OS makes any user-set environment variables
16    (i.e. with putenv()) unavailable.  getenv() apparently gets a clean copy of
17    the env variables as they existed at the start of the run. JH 12/23/2002
18
19    On Windows* OS, there are two environments (at least, see below):
20
21    1. Environment maintained by Windows* OS on IA-32 architecture. Accessible
22       through GetEnvironmentVariable(), SetEnvironmentVariable(), and
23       GetEnvironmentStrings().
24
25    2. Environment maintained by C RTL. Accessible through getenv(), putenv().
26
27    putenv() function updates both C and Windows* OS on IA-32 architecture.
28    getenv() function search for variables in C RTL environment only.
29    Windows* OS on IA-32 architecture functions work *only* with Windows* OS on
30    IA-32 architecture.
31
32    Windows* OS on IA-32 architecture maintained by OS, so there is always only
33    one Windows* OS on IA-32 architecture per process. Changes in Windows* OS on
34    IA-32 architecture are process-visible.
35
36    C environment maintained by C RTL. Multiple copies of C RTL may be present
37    in the process, and each C RTL maintains its own environment. :-(
38
39    Thus, proper way to work with environment on Windows* OS is:
40
41    1. Set variables with putenv() function -- both C and Windows* OS on IA-32
42       architecture are being updated. Windows* OS on IA-32 architecture may be
43       considered primary target, while updating C RTL environment is free bonus.
44
45    2. Get variables with GetEnvironmentVariable() -- getenv() does not
46       search Windows* OS on IA-32 architecture, and can not see variables
47       set with SetEnvironmentVariable().
48
49    2007-04-05 -- lev
50 */
51
52 #include "kmp_environment.h"
53
54 #include "kmp.h" //
55 #include "kmp_i18n.h"
56 #include "kmp_os.h" // KMP_OS_*.
57 #include "kmp_str.h" // __kmp_str_*().
58
59 #if KMP_OS_UNIX
60 #include <stdlib.h> // getenv, setenv, unsetenv.
61 #include <string.h> // strlen, strcpy.
62 #if KMP_OS_DARWIN
63 #include <crt_externs.h>
64 #define environ (*_NSGetEnviron())
65 #else
66 extern char **environ;
67 #endif
68 #elif KMP_OS_WINDOWS
69 #include <windows.h> // GetEnvironmentVariable, SetEnvironmentVariable,
70 // GetLastError.
71 #else
72 #error Unknown or unsupported OS.
73 #endif
74
75 // TODO: Eliminate direct memory allocations, use string operations instead.
76
77 static inline void *allocate(size_t size) {
78   void *ptr = KMP_INTERNAL_MALLOC(size);
79   if (ptr == NULL) {
80     KMP_FATAL(MemoryAllocFailed);
81   }
82   return ptr;
83 } // allocate
84
85 char *__kmp_env_get(char const *name) {
86
87   char *result = NULL;
88
89 #if KMP_OS_UNIX
90   char const *value = getenv(name);
91   if (value != NULL) {
92     size_t len = KMP_STRLEN(value) + 1;
93     result = (char *)KMP_INTERNAL_MALLOC(len);
94     if (result == NULL) {
95       KMP_FATAL(MemoryAllocFailed);
96     }
97     KMP_STRNCPY_S(result, len, value, len);
98   }
99 #elif KMP_OS_WINDOWS
100   /* We use GetEnvironmentVariable for Windows* OS instead of getenv because the
101      act of loading a DLL on Windows* OS makes any user-set environment
102      variables (i.e. with putenv()) unavailable. getenv() apparently gets a
103      clean copy of the env variables as they existed at the start of the run.
104      JH 12/23/2002 */
105   DWORD rc;
106   rc = GetEnvironmentVariable(name, NULL, 0);
107   if (!rc) {
108     DWORD error = GetLastError();
109     if (error != ERROR_ENVVAR_NOT_FOUND) {
110       __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), __kmp_msg_null);
111     }
112     // Variable is not found, it's ok, just continue.
113   } else {
114     DWORD len = rc;
115     result = (char *)KMP_INTERNAL_MALLOC(len);
116     if (result == NULL) {
117       KMP_FATAL(MemoryAllocFailed);
118     }
119     rc = GetEnvironmentVariable(name, result, len);
120     if (!rc) {
121       // GetEnvironmentVariable() may return 0 if variable is empty.
122       // In such a case GetLastError() returns ERROR_SUCCESS.
123       DWORD error = GetLastError();
124       if (error != ERROR_SUCCESS) {
125         // Unexpected error. The variable should be in the environment,
126         // and buffer should be large enough.
127         __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error),
128                     __kmp_msg_null);
129         KMP_INTERNAL_FREE((void *)result);
130         result = NULL;
131       }
132     }
133   }
134 #else
135 #error Unknown or unsupported OS.
136 #endif
137
138   return result;
139
140 } // func __kmp_env_get
141
142 // TODO: Find and replace all regular free() with __kmp_env_free().
143
144 void __kmp_env_free(char const **value) {
145
146   KMP_DEBUG_ASSERT(value != NULL);
147   KMP_INTERNAL_FREE(CCAST(char *, *value));
148   *value = NULL;
149
150 } // func __kmp_env_free
151
152 int __kmp_env_exists(char const *name) {
153
154 #if KMP_OS_UNIX
155   char const *value = getenv(name);
156   return ((value == NULL) ? (0) : (1));
157 #elif KMP_OS_WINDOWS
158   DWORD rc;
159   rc = GetEnvironmentVariable(name, NULL, 0);
160   if (rc == 0) {
161     DWORD error = GetLastError();
162     if (error != ERROR_ENVVAR_NOT_FOUND) {
163       __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), __kmp_msg_null);
164     }
165     return 0;
166   }
167   return 1;
168 #else
169 #error Unknown or unsupported OS.
170 #endif
171
172 } // func __kmp_env_exists
173
174 void __kmp_env_set(char const *name, char const *value, int overwrite) {
175
176 #if KMP_OS_UNIX
177   int rc = setenv(name, value, overwrite);
178   if (rc != 0) {
179     // Dead code. I tried to put too many variables into Linux* OS
180     // environment on IA-32 architecture. When application consumes
181     // more than ~2.5 GB of memory, entire system feels bad. Sometimes
182     // application is killed (by OS?), sometimes system stops
183     // responding... But this error message never appears. --ln
184     __kmp_fatal(KMP_MSG(CantSetEnvVar, name), KMP_HNT(NotEnoughMemory),
185                 __kmp_msg_null);
186   }
187 #elif KMP_OS_WINDOWS
188   BOOL rc;
189   if (!overwrite) {
190     rc = GetEnvironmentVariable(name, NULL, 0);
191     if (rc) {
192       // Variable exists, do not overwrite.
193       return;
194     }
195     DWORD error = GetLastError();
196     if (error != ERROR_ENVVAR_NOT_FOUND) {
197       __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), __kmp_msg_null);
198     }
199   }
200   rc = SetEnvironmentVariable(name, value);
201   if (!rc) {
202     DWORD error = GetLastError();
203     __kmp_fatal(KMP_MSG(CantSetEnvVar, name), KMP_ERR(error), __kmp_msg_null);
204   }
205 #else
206 #error Unknown or unsupported OS.
207 #endif
208
209 } // func __kmp_env_set
210
211 void __kmp_env_unset(char const *name) {
212
213 #if KMP_OS_UNIX
214   unsetenv(name);
215 #elif KMP_OS_WINDOWS
216   BOOL rc = SetEnvironmentVariable(name, NULL);
217   if (!rc) {
218     DWORD error = GetLastError();
219     __kmp_fatal(KMP_MSG(CantSetEnvVar, name), KMP_ERR(error), __kmp_msg_null);
220   }
221 #else
222 #error Unknown or unsupported OS.
223 #endif
224
225 } // func __kmp_env_unset
226
227 /* Intel OpenMP RTL string representation of environment: just a string of
228    characters, variables are separated with vertical bars, e. g.:
229
230         "KMP_WARNINGS=0|KMP_AFFINITY=compact|"
231
232     Empty variables are allowed and ignored:
233
234         "||KMP_WARNINGS=1||"
235 */
236
237 static void
238 ___kmp_env_blk_parse_string(kmp_env_blk_t *block, // M: Env block to fill.
239                             char const *env // I: String to parse.
240                             ) {
241
242   char const chr_delimiter = '|';
243   char const str_delimiter[] = {chr_delimiter, 0};
244
245   char *bulk = NULL;
246   kmp_env_var_t *vars = NULL;
247   int count = 0; // Number of used elements in vars array.
248   int delimiters = 0; // Number of delimiters in input string.
249
250   // Copy original string, we will modify the copy.
251   bulk = __kmp_str_format("%s", env);
252
253   // Loop thru all the vars in environment block. Count delimiters (maximum
254   // number of variables is number of delimiters plus one).
255   {
256     char const *ptr = bulk;
257     for (;;) {
258       ptr = strchr(ptr, chr_delimiter);
259       if (ptr == NULL) {
260         break;
261       }
262       ++delimiters;
263       ptr += 1;
264     }
265   }
266
267   // Allocate vars array.
268   vars = (kmp_env_var_t *)allocate((delimiters + 1) * sizeof(kmp_env_var_t));
269
270   // Loop thru all the variables.
271   {
272     char *var; // Pointer to variable (both name and value).
273     char *name; // Pointer to name of variable.
274     char *value; // Pointer to value.
275     char *buf; // Buffer for __kmp_str_token() function.
276     var = __kmp_str_token(bulk, str_delimiter, &buf); // Get the first var.
277     while (var != NULL) {
278       // Save found variable in vars array.
279       __kmp_str_split(var, '=', &name, &value);
280       KMP_DEBUG_ASSERT(count < delimiters + 1);
281       vars[count].name = name;
282       vars[count].value = value;
283       ++count;
284       // Get the next var.
285       var = __kmp_str_token(NULL, str_delimiter, &buf);
286     }
287   }
288
289   // Fill out result.
290   block->bulk = bulk;
291   block->vars = vars;
292   block->count = count;
293 }
294
295 /* Windows* OS (actually, DOS) environment block is a piece of memory with
296    environment variables. Each variable is terminated with zero byte, entire
297    block is terminated with one extra zero byte, so we have two zero bytes at
298    the end of environment block, e. g.:
299
300         "HOME=C:\\users\\lev\x00OS=Windows_NT\x00\x00"
301
302     It is not clear how empty environment is represented. "\x00\x00"?
303 */
304
305 #if KMP_OS_WINDOWS
306 static void ___kmp_env_blk_parse_windows(
307     kmp_env_blk_t *block, // M: Env block to fill.
308     char const *env // I: Pointer to Windows* OS (DOS) environment block.
309     ) {
310
311   char *bulk = NULL;
312   kmp_env_var_t *vars = NULL;
313   int count = 0; // Number of used elements in vars array.
314   int size = 0; // Size of bulk.
315
316   char *name; // Pointer to name of variable.
317   char *value; // Pointer to value.
318
319   if (env != NULL) {
320
321     // Loop thru all the vars in environment block. Count variables, find size
322     // of block.
323     {
324       char const *var; // Pointer to beginning of var.
325       int len; // Length of variable.
326       count = 0;
327       var =
328           env; // The first variable starts and beginning of environment block.
329       len = KMP_STRLEN(var);
330       while (len != 0) {
331         ++count;
332         size = size + len + 1;
333         var = var + len +
334               1; // Move pointer to the beginning of the next variable.
335         len = KMP_STRLEN(var);
336       }
337       size =
338           size + 1; // Total size of env block, including terminating zero byte.
339     }
340
341     // Copy original block to bulk, we will modify bulk, not original block.
342     bulk = (char *)allocate(size);
343     KMP_MEMCPY_S(bulk, size, env, size);
344     // Allocate vars array.
345     vars = (kmp_env_var_t *)allocate(count * sizeof(kmp_env_var_t));
346
347     // Loop thru all the vars, now in bulk.
348     {
349       char *var; // Pointer to beginning of var.
350       int len; // Length of variable.
351       count = 0;
352       var = bulk;
353       len = KMP_STRLEN(var);
354       while (len != 0) {
355         // Save variable in vars array.
356         __kmp_str_split(var, '=', &name, &value);
357         vars[count].name = name;
358         vars[count].value = value;
359         ++count;
360         // Get the next var.
361         var = var + len + 1;
362         len = KMP_STRLEN(var);
363       }
364     }
365   }
366
367   // Fill out result.
368   block->bulk = bulk;
369   block->vars = vars;
370   block->count = count;
371 }
372 #endif
373
374 /* Unix environment block is a array of pointers to variables, last pointer in
375    array is NULL:
376
377         { "HOME=/home/lev", "TERM=xterm", NULL }
378 */
379
380 static void
381 ___kmp_env_blk_parse_unix(kmp_env_blk_t *block, // M: Env block to fill.
382                           char **env // I: Unix environment to parse.
383                           ) {
384
385   char *bulk = NULL;
386   kmp_env_var_t *vars = NULL;
387   int count = 0;
388   int size = 0; // Size of bulk.
389
390   // Count number of variables and length of required bulk.
391   {
392     count = 0;
393     size = 0;
394     while (env[count] != NULL) {
395       size += KMP_STRLEN(env[count]) + 1;
396       ++count;
397     }
398   }
399
400   // Allocate memory.
401   bulk = (char *)allocate(size);
402   vars = (kmp_env_var_t *)allocate(count * sizeof(kmp_env_var_t));
403
404   // Loop thru all the vars.
405   {
406     char *var; // Pointer to beginning of var.
407     char *name; // Pointer to name of variable.
408     char *value; // Pointer to value.
409     int len; // Length of variable.
410     int i;
411     var = bulk;
412     for (i = 0; i < count; ++i) {
413       // Copy variable to bulk.
414       len = KMP_STRLEN(env[i]);
415       KMP_MEMCPY_S(var, size, env[i], len + 1);
416       // Save found variable in vars array.
417       __kmp_str_split(var, '=', &name, &value);
418       vars[i].name = name;
419       vars[i].value = value;
420       // Move pointer.
421       var += len + 1;
422     }
423   }
424
425   // Fill out result.
426   block->bulk = bulk;
427   block->vars = vars;
428   block->count = count;
429 }
430
431 void __kmp_env_blk_init(kmp_env_blk_t *block, // M: Block to initialize.
432                         char const *bulk // I: Initialization string, or NULL.
433                         ) {
434
435   if (bulk != NULL) {
436     ___kmp_env_blk_parse_string(block, bulk);
437   } else {
438 #if KMP_OS_UNIX
439     ___kmp_env_blk_parse_unix(block, environ);
440 #elif KMP_OS_WINDOWS
441     {
442       char *mem = GetEnvironmentStrings();
443       if (mem == NULL) {
444         DWORD error = GetLastError();
445         __kmp_fatal(KMP_MSG(CantGetEnvironment), KMP_ERR(error),
446                     __kmp_msg_null);
447       }
448       ___kmp_env_blk_parse_windows(block, mem);
449       FreeEnvironmentStrings(mem);
450     }
451 #else
452 #error Unknown or unsupported OS.
453 #endif
454   }
455
456 } // __kmp_env_blk_init
457
458 static int ___kmp_env_var_cmp( // Comparison function for qsort().
459     kmp_env_var_t const *lhs, kmp_env_var_t const *rhs) {
460   return strcmp(lhs->name, rhs->name);
461 }
462
463 void __kmp_env_blk_sort(
464     kmp_env_blk_t *block // M: Block of environment variables to sort.
465     ) {
466
467   qsort(CCAST(kmp_env_var_t *, block->vars), block->count,
468         sizeof(kmp_env_var_t),
469         (int (*)(void const *, void const *)) & ___kmp_env_var_cmp);
470
471 } // __kmp_env_block_sort
472
473 void __kmp_env_blk_free(
474     kmp_env_blk_t *block // M: Block of environment variables to free.
475     ) {
476
477   KMP_INTERNAL_FREE(CCAST(kmp_env_var_t *, block->vars));
478   __kmp_str_free(&(block->bulk));
479
480   block->count = 0;
481   block->vars = NULL;
482
483 } // __kmp_env_blk_free
484
485 char const * // R: Value of variable or NULL if variable does not exist.
486     __kmp_env_blk_var(
487         kmp_env_blk_t *block, // I: Block of environment variables.
488         char const *name // I: Name of variable to find.
489         ) {
490
491   int i;
492   for (i = 0; i < block->count; ++i) {
493     if (strcmp(block->vars[i].name, name) == 0) {
494       return block->vars[i].value;
495     }
496   }
497   return NULL;
498
499 } // __kmp_env_block_var
500
501 // end of file //