2 * kmp_environment.cpp -- Handle environment variables OS-independently.
5 //===----------------------------------------------------------------------===//
7 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
8 // See https://llvm.org/LICENSE.txt for license information.
9 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
11 //===----------------------------------------------------------------------===//
13 /* We use GetEnvironmentVariable for Windows* OS instead of getenv because the
14 act of loading a DLL on Windows* OS makes any user-set environment variables
15 (i.e. with putenv()) unavailable. getenv() apparently gets a clean copy of
16 the env variables as they existed at the start of the run. JH 12/23/2002
18 On Windows* OS, there are two environments (at least, see below):
20 1. Environment maintained by Windows* OS on IA-32 architecture. Accessible
21 through GetEnvironmentVariable(), SetEnvironmentVariable(), and
22 GetEnvironmentStrings().
24 2. Environment maintained by C RTL. Accessible through getenv(), putenv().
26 putenv() function updates both C and Windows* OS on IA-32 architecture.
27 getenv() function search for variables in C RTL environment only.
28 Windows* OS on IA-32 architecture functions work *only* with Windows* OS on
31 Windows* OS on IA-32 architecture maintained by OS, so there is always only
32 one Windows* OS on IA-32 architecture per process. Changes in Windows* OS on
33 IA-32 architecture are process-visible.
35 C environment maintained by C RTL. Multiple copies of C RTL may be present
36 in the process, and each C RTL maintains its own environment. :-(
38 Thus, proper way to work with environment on Windows* OS is:
40 1. Set variables with putenv() function -- both C and Windows* OS on IA-32
41 architecture are being updated. Windows* OS on IA-32 architecture may be
42 considered primary target, while updating C RTL environment is free bonus.
44 2. Get variables with GetEnvironmentVariable() -- getenv() does not
45 search Windows* OS on IA-32 architecture, and can not see variables
46 set with SetEnvironmentVariable().
51 #include "kmp_environment.h"
55 #include "kmp_os.h" // KMP_OS_*.
56 #include "kmp_str.h" // __kmp_str_*().
59 #include <stdlib.h> // getenv, setenv, unsetenv.
60 #include <string.h> // strlen, strcpy.
62 #include <crt_externs.h>
63 #define environ (*_NSGetEnviron())
65 extern char **environ
;
68 #include <windows.h> // GetEnvironmentVariable, SetEnvironmentVariable,
71 #error Unknown or unsupported OS.
74 // TODO: Eliminate direct memory allocations, use string operations instead.
76 static inline void *allocate(size_t size
) {
77 void *ptr
= KMP_INTERNAL_MALLOC(size
);
79 KMP_FATAL(MemoryAllocFailed
);
84 char *__kmp_env_get(char const *name
) {
89 char const *value
= getenv(name
);
91 size_t len
= KMP_STRLEN(value
) + 1;
92 result
= (char *)KMP_INTERNAL_MALLOC(len
);
94 KMP_FATAL(MemoryAllocFailed
);
96 KMP_STRNCPY_S(result
, len
, value
, len
);
99 /* We use GetEnvironmentVariable for Windows* OS instead of getenv because the
100 act of loading a DLL on Windows* OS makes any user-set environment
101 variables (i.e. with putenv()) unavailable. getenv() apparently gets a
102 clean copy of the env variables as they existed at the start of the run.
105 rc
= GetEnvironmentVariable(name
, NULL
, 0);
107 DWORD error
= GetLastError();
108 if (error
!= ERROR_ENVVAR_NOT_FOUND
) {
109 __kmp_fatal(KMP_MSG(CantGetEnvVar
, name
), KMP_ERR(error
), __kmp_msg_null
);
111 // Variable is not found, it's ok, just continue.
114 result
= (char *)KMP_INTERNAL_MALLOC(len
);
115 if (result
== NULL
) {
116 KMP_FATAL(MemoryAllocFailed
);
118 rc
= GetEnvironmentVariable(name
, result
, len
);
120 // GetEnvironmentVariable() may return 0 if variable is empty.
121 // In such a case GetLastError() returns ERROR_SUCCESS.
122 DWORD error
= GetLastError();
123 if (error
!= ERROR_SUCCESS
) {
124 // Unexpected error. The variable should be in the environment,
125 // and buffer should be large enough.
126 __kmp_fatal(KMP_MSG(CantGetEnvVar
, name
), KMP_ERR(error
),
128 KMP_INTERNAL_FREE((void *)result
);
134 #error Unknown or unsupported OS.
139 } // func __kmp_env_get
141 // TODO: Find and replace all regular free() with __kmp_env_free().
143 void __kmp_env_free(char const **value
) {
145 KMP_DEBUG_ASSERT(value
!= NULL
);
146 KMP_INTERNAL_FREE(CCAST(char *, *value
));
149 } // func __kmp_env_free
151 int __kmp_env_exists(char const *name
) {
154 char const *value
= getenv(name
);
155 return ((value
== NULL
) ? (0) : (1));
158 rc
= GetEnvironmentVariable(name
, NULL
, 0);
160 DWORD error
= GetLastError();
161 if (error
!= ERROR_ENVVAR_NOT_FOUND
) {
162 __kmp_fatal(KMP_MSG(CantGetEnvVar
, name
), KMP_ERR(error
), __kmp_msg_null
);
168 #error Unknown or unsupported OS.
171 } // func __kmp_env_exists
173 void __kmp_env_set(char const *name
, char const *value
, int overwrite
) {
176 int rc
= setenv(name
, value
, overwrite
);
178 // Dead code. I tried to put too many variables into Linux* OS
179 // environment on IA-32 architecture. When application consumes
180 // more than ~2.5 GB of memory, entire system feels bad. Sometimes
181 // application is killed (by OS?), sometimes system stops
182 // responding... But this error message never appears. --ln
183 __kmp_fatal(KMP_MSG(CantSetEnvVar
, name
), KMP_HNT(NotEnoughMemory
),
189 rc
= GetEnvironmentVariable(name
, NULL
, 0);
191 // Variable exists, do not overwrite.
194 DWORD error
= GetLastError();
195 if (error
!= ERROR_ENVVAR_NOT_FOUND
) {
196 __kmp_fatal(KMP_MSG(CantGetEnvVar
, name
), KMP_ERR(error
), __kmp_msg_null
);
199 rc
= SetEnvironmentVariable(name
, value
);
201 DWORD error
= GetLastError();
202 __kmp_fatal(KMP_MSG(CantSetEnvVar
, name
), KMP_ERR(error
), __kmp_msg_null
);
205 #error Unknown or unsupported OS.
208 } // func __kmp_env_set
210 void __kmp_env_unset(char const *name
) {
215 BOOL rc
= SetEnvironmentVariable(name
, NULL
);
217 DWORD error
= GetLastError();
218 __kmp_fatal(KMP_MSG(CantSetEnvVar
, name
), KMP_ERR(error
), __kmp_msg_null
);
221 #error Unknown or unsupported OS.
224 } // func __kmp_env_unset
226 /* Intel OpenMP RTL string representation of environment: just a string of
227 characters, variables are separated with vertical bars, e. g.:
229 "KMP_WARNINGS=0|KMP_AFFINITY=compact|"
231 Empty variables are allowed and ignored:
237 ___kmp_env_blk_parse_string(kmp_env_blk_t
*block
, // M: Env block to fill.
238 char const *env
// I: String to parse.
241 char const chr_delimiter
= '|';
242 char const str_delimiter
[] = {chr_delimiter
, 0};
245 kmp_env_var_t
*vars
= NULL
;
246 int count
= 0; // Number of used elements in vars array.
247 int delimiters
= 0; // Number of delimiters in input string.
249 // Copy original string, we will modify the copy.
250 bulk
= __kmp_str_format("%s", env
);
252 // Loop thru all the vars in environment block. Count delimiters (maximum
253 // number of variables is number of delimiters plus one).
255 char const *ptr
= bulk
;
257 ptr
= strchr(ptr
, chr_delimiter
);
266 // Allocate vars array.
267 vars
= (kmp_env_var_t
*)allocate((delimiters
+ 1) * sizeof(kmp_env_var_t
));
269 // Loop thru all the variables.
271 char *var
; // Pointer to variable (both name and value).
272 char *name
; // Pointer to name of variable.
273 char *value
; // Pointer to value.
274 char *buf
; // Buffer for __kmp_str_token() function.
275 var
= __kmp_str_token(bulk
, str_delimiter
, &buf
); // Get the first var.
276 while (var
!= NULL
) {
277 // Save found variable in vars array.
278 __kmp_str_split(var
, '=', &name
, &value
);
279 KMP_DEBUG_ASSERT(count
< delimiters
+ 1);
280 vars
[count
].name
= name
;
281 vars
[count
].value
= value
;
284 var
= __kmp_str_token(NULL
, str_delimiter
, &buf
);
291 block
->count
= count
;
294 /* Windows* OS (actually, DOS) environment block is a piece of memory with
295 environment variables. Each variable is terminated with zero byte, entire
296 block is terminated with one extra zero byte, so we have two zero bytes at
297 the end of environment block, e. g.:
299 "HOME=C:\\users\\lev\x00OS=Windows_NT\x00\x00"
301 It is not clear how empty environment is represented. "\x00\x00"?
305 static void ___kmp_env_blk_parse_windows(
306 kmp_env_blk_t
*block
, // M: Env block to fill.
307 char const *env
// I: Pointer to Windows* OS (DOS) environment block.
311 kmp_env_var_t
*vars
= NULL
;
312 int count
= 0; // Number of used elements in vars array.
313 int size
= 0; // Size of bulk.
315 char *name
; // Pointer to name of variable.
316 char *value
; // Pointer to value.
320 // Loop thru all the vars in environment block. Count variables, find size
323 char const *var
; // Pointer to beginning of var.
324 int len
; // Length of variable.
327 env
; // The first variable starts and beginning of environment block.
328 len
= KMP_STRLEN(var
);
331 size
= size
+ len
+ 1;
333 1; // Move pointer to the beginning of the next variable.
334 len
= KMP_STRLEN(var
);
337 size
+ 1; // Total size of env block, including terminating zero byte.
340 // Copy original block to bulk, we will modify bulk, not original block.
341 bulk
= (char *)allocate(size
);
342 KMP_MEMCPY_S(bulk
, size
, env
, size
);
343 // Allocate vars array.
344 vars
= (kmp_env_var_t
*)allocate(count
* sizeof(kmp_env_var_t
));
346 // Loop thru all the vars, now in bulk.
348 char *var
; // Pointer to beginning of var.
349 int len
; // Length of variable.
352 len
= KMP_STRLEN(var
);
354 // Save variable in vars array.
355 __kmp_str_split(var
, '=', &name
, &value
);
356 vars
[count
].name
= name
;
357 vars
[count
].value
= value
;
361 len
= KMP_STRLEN(var
);
369 block
->count
= count
;
373 /* Unix environment block is a array of pointers to variables, last pointer in
376 { "HOME=/home/lev", "TERM=xterm", NULL }
381 ___kmp_env_blk_parse_unix(kmp_env_blk_t
*block
, // M: Env block to fill.
382 char **env
// I: Unix environment to parse.
385 kmp_env_var_t
*vars
= NULL
;
387 size_t size
= 0; // Size of bulk.
389 // Count number of variables and length of required bulk.
391 while (env
[count
] != NULL
) {
392 size
+= KMP_STRLEN(env
[count
]) + 1;
398 bulk
= (char *)allocate(size
);
399 vars
= (kmp_env_var_t
*)allocate(count
* sizeof(kmp_env_var_t
));
401 // Loop thru all the vars.
403 char *var
; // Pointer to beginning of var.
404 char *name
; // Pointer to name of variable.
405 char *value
; // Pointer to value.
406 size_t len
; // Length of variable.
409 for (i
= 0; i
< count
; ++i
) {
410 KMP_ASSERT(var
< bulk
+ size
);
411 [[maybe_unused
]] size_t ssize
= size
- (var
- bulk
);
412 // Copy variable to bulk.
413 len
= KMP_STRLEN(env
[i
]);
414 KMP_MEMCPY_S(var
, ssize
, env
[i
], len
+ 1);
415 // Save found variable in vars array.
416 __kmp_str_split(var
, '=', &name
, &value
);
418 vars
[i
].value
= value
;
427 block
->count
= count
;
431 void __kmp_env_blk_init(kmp_env_blk_t
*block
, // M: Block to initialize.
432 char const *bulk
// I: Initialization string, or NULL.
436 ___kmp_env_blk_parse_string(block
, bulk
);
439 ___kmp_env_blk_parse_unix(block
, environ
);
442 char *mem
= GetEnvironmentStrings();
444 DWORD error
= GetLastError();
445 __kmp_fatal(KMP_MSG(CantGetEnvironment
), KMP_ERR(error
),
448 ___kmp_env_blk_parse_windows(block
, mem
);
449 FreeEnvironmentStrings(mem
);
452 #error Unknown or unsupported OS.
456 } // __kmp_env_blk_init
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
);
463 void __kmp_env_blk_sort(
464 kmp_env_blk_t
*block
// M: Block of environment variables to sort.
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
);
471 } // __kmp_env_block_sort
473 void __kmp_env_blk_free(
474 kmp_env_blk_t
*block
// M: Block of environment variables to free.
477 KMP_INTERNAL_FREE(CCAST(kmp_env_var_t
*, block
->vars
));
478 __kmp_str_free(&(block
->bulk
));
483 } // __kmp_env_blk_free
485 char const * // R: Value of variable or NULL if variable does not exist.
486 __kmp_env_blk_var(kmp_env_blk_t
*block
, // I: Block of environment variables.
487 char const *name
// I: Name of variable to find.
491 for (i
= 0; i
< block
->count
; ++i
) {
492 if (strcmp(block
->vars
[i
].name
, name
) == 0) {
493 return block
->vars
[i
].value
;
498 } // __kmp_env_block_var