Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/openmp/runtime/src/kmp_environment.cpp
35258 views
1
/*
2
* kmp_environment.cpp -- Handle environment variables OS-independently.
3
*/
4
5
//===----------------------------------------------------------------------===//
6
//
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
10
//
11
//===----------------------------------------------------------------------===//
12
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
17
18
On Windows* OS, there are two environments (at least, see below):
19
20
1. Environment maintained by Windows* OS on IA-32 architecture. Accessible
21
through GetEnvironmentVariable(), SetEnvironmentVariable(), and
22
GetEnvironmentStrings().
23
24
2. Environment maintained by C RTL. Accessible through getenv(), putenv().
25
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
29
IA-32 architecture.
30
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.
34
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. :-(
37
38
Thus, proper way to work with environment on Windows* OS is:
39
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.
43
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().
47
48
2007-04-05 -- lev
49
*/
50
51
#include "kmp_environment.h"
52
53
#include "kmp.h" //
54
#include "kmp_i18n.h"
55
#include "kmp_os.h" // KMP_OS_*.
56
#include "kmp_str.h" // __kmp_str_*().
57
58
#if KMP_OS_UNIX
59
#include <stdlib.h> // getenv, setenv, unsetenv.
60
#include <string.h> // strlen, strcpy.
61
#if KMP_OS_DARWIN
62
#include <crt_externs.h>
63
#define environ (*_NSGetEnviron())
64
#else
65
extern char **environ;
66
#endif
67
#elif KMP_OS_WINDOWS
68
#include <windows.h> // GetEnvironmentVariable, SetEnvironmentVariable,
69
// GetLastError.
70
#else
71
#error Unknown or unsupported OS.
72
#endif
73
74
// TODO: Eliminate direct memory allocations, use string operations instead.
75
76
static inline void *allocate(size_t size) {
77
void *ptr = KMP_INTERNAL_MALLOC(size);
78
if (ptr == NULL) {
79
KMP_FATAL(MemoryAllocFailed);
80
}
81
return ptr;
82
} // allocate
83
84
char *__kmp_env_get(char const *name) {
85
86
char *result = NULL;
87
88
#if KMP_OS_UNIX
89
char const *value = getenv(name);
90
if (value != NULL) {
91
size_t len = KMP_STRLEN(value) + 1;
92
result = (char *)KMP_INTERNAL_MALLOC(len);
93
if (result == NULL) {
94
KMP_FATAL(MemoryAllocFailed);
95
}
96
KMP_STRNCPY_S(result, len, value, len);
97
}
98
#elif KMP_OS_WINDOWS
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.
103
JH 12/23/2002 */
104
DWORD rc;
105
rc = GetEnvironmentVariable(name, NULL, 0);
106
if (!rc) {
107
DWORD error = GetLastError();
108
if (error != ERROR_ENVVAR_NOT_FOUND) {
109
__kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), __kmp_msg_null);
110
}
111
// Variable is not found, it's ok, just continue.
112
} else {
113
DWORD len = rc;
114
result = (char *)KMP_INTERNAL_MALLOC(len);
115
if (result == NULL) {
116
KMP_FATAL(MemoryAllocFailed);
117
}
118
rc = GetEnvironmentVariable(name, result, len);
119
if (!rc) {
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),
127
__kmp_msg_null);
128
KMP_INTERNAL_FREE((void *)result);
129
result = NULL;
130
}
131
}
132
}
133
#else
134
#error Unknown or unsupported OS.
135
#endif
136
137
return result;
138
139
} // func __kmp_env_get
140
141
// TODO: Find and replace all regular free() with __kmp_env_free().
142
143
void __kmp_env_free(char const **value) {
144
145
KMP_DEBUG_ASSERT(value != NULL);
146
KMP_INTERNAL_FREE(CCAST(char *, *value));
147
*value = NULL;
148
149
} // func __kmp_env_free
150
151
int __kmp_env_exists(char const *name) {
152
153
#if KMP_OS_UNIX
154
char const *value = getenv(name);
155
return ((value == NULL) ? (0) : (1));
156
#elif KMP_OS_WINDOWS
157
DWORD rc;
158
rc = GetEnvironmentVariable(name, NULL, 0);
159
if (rc == 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);
163
}
164
return 0;
165
}
166
return 1;
167
#else
168
#error Unknown or unsupported OS.
169
#endif
170
171
} // func __kmp_env_exists
172
173
void __kmp_env_set(char const *name, char const *value, int overwrite) {
174
175
#if KMP_OS_UNIX
176
int rc = setenv(name, value, overwrite);
177
if (rc != 0) {
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),
184
__kmp_msg_null);
185
}
186
#elif KMP_OS_WINDOWS
187
BOOL rc;
188
if (!overwrite) {
189
rc = GetEnvironmentVariable(name, NULL, 0);
190
if (rc) {
191
// Variable exists, do not overwrite.
192
return;
193
}
194
DWORD error = GetLastError();
195
if (error != ERROR_ENVVAR_NOT_FOUND) {
196
__kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), __kmp_msg_null);
197
}
198
}
199
rc = SetEnvironmentVariable(name, value);
200
if (!rc) {
201
DWORD error = GetLastError();
202
__kmp_fatal(KMP_MSG(CantSetEnvVar, name), KMP_ERR(error), __kmp_msg_null);
203
}
204
#else
205
#error Unknown or unsupported OS.
206
#endif
207
208
} // func __kmp_env_set
209
210
void __kmp_env_unset(char const *name) {
211
212
#if KMP_OS_UNIX
213
unsetenv(name);
214
#elif KMP_OS_WINDOWS
215
BOOL rc = SetEnvironmentVariable(name, NULL);
216
if (!rc) {
217
DWORD error = GetLastError();
218
__kmp_fatal(KMP_MSG(CantSetEnvVar, name), KMP_ERR(error), __kmp_msg_null);
219
}
220
#else
221
#error Unknown or unsupported OS.
222
#endif
223
224
} // func __kmp_env_unset
225
226
/* Intel OpenMP RTL string representation of environment: just a string of
227
characters, variables are separated with vertical bars, e. g.:
228
229
"KMP_WARNINGS=0|KMP_AFFINITY=compact|"
230
231
Empty variables are allowed and ignored:
232
233
"||KMP_WARNINGS=1||"
234
*/
235
236
static void
237
___kmp_env_blk_parse_string(kmp_env_blk_t *block, // M: Env block to fill.
238
char const *env // I: String to parse.
239
) {
240
241
char const chr_delimiter = '|';
242
char const str_delimiter[] = {chr_delimiter, 0};
243
244
char *bulk = NULL;
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.
248
249
// Copy original string, we will modify the copy.
250
bulk = __kmp_str_format("%s", env);
251
252
// Loop thru all the vars in environment block. Count delimiters (maximum
253
// number of variables is number of delimiters plus one).
254
{
255
char const *ptr = bulk;
256
for (;;) {
257
ptr = strchr(ptr, chr_delimiter);
258
if (ptr == NULL) {
259
break;
260
}
261
++delimiters;
262
ptr += 1;
263
}
264
}
265
266
// Allocate vars array.
267
vars = (kmp_env_var_t *)allocate((delimiters + 1) * sizeof(kmp_env_var_t));
268
269
// Loop thru all the variables.
270
{
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;
282
++count;
283
// Get the next var.
284
var = __kmp_str_token(NULL, str_delimiter, &buf);
285
}
286
}
287
288
// Fill out result.
289
block->bulk = bulk;
290
block->vars = vars;
291
block->count = count;
292
}
293
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.:
298
299
"HOME=C:\\users\\lev\x00OS=Windows_NT\x00\x00"
300
301
It is not clear how empty environment is represented. "\x00\x00"?
302
*/
303
304
#if KMP_OS_WINDOWS
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.
308
) {
309
310
char *bulk = NULL;
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.
314
315
char *name; // Pointer to name of variable.
316
char *value; // Pointer to value.
317
318
if (env != NULL) {
319
320
// Loop thru all the vars in environment block. Count variables, find size
321
// of block.
322
{
323
char const *var; // Pointer to beginning of var.
324
int len; // Length of variable.
325
count = 0;
326
var =
327
env; // The first variable starts and beginning of environment block.
328
len = KMP_STRLEN(var);
329
while (len != 0) {
330
++count;
331
size = size + len + 1;
332
var = var + len +
333
1; // Move pointer to the beginning of the next variable.
334
len = KMP_STRLEN(var);
335
}
336
size =
337
size + 1; // Total size of env block, including terminating zero byte.
338
}
339
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));
345
346
// Loop thru all the vars, now in bulk.
347
{
348
char *var; // Pointer to beginning of var.
349
int len; // Length of variable.
350
count = 0;
351
var = bulk;
352
len = KMP_STRLEN(var);
353
while (len != 0) {
354
// Save variable in vars array.
355
__kmp_str_split(var, '=', &name, &value);
356
vars[count].name = name;
357
vars[count].value = value;
358
++count;
359
// Get the next var.
360
var = var + len + 1;
361
len = KMP_STRLEN(var);
362
}
363
}
364
}
365
366
// Fill out result.
367
block->bulk = bulk;
368
block->vars = vars;
369
block->count = count;
370
}
371
#endif
372
373
/* Unix environment block is a array of pointers to variables, last pointer in
374
array is NULL:
375
376
{ "HOME=/home/lev", "TERM=xterm", NULL }
377
*/
378
379
#if KMP_OS_UNIX
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
char *bulk = NULL;
385
kmp_env_var_t *vars = NULL;
386
int count = 0;
387
size_t size = 0; // Size of bulk.
388
389
// Count number of variables and length of required bulk.
390
{
391
while (env[count] != NULL) {
392
size += KMP_STRLEN(env[count]) + 1;
393
++count;
394
}
395
}
396
397
// Allocate memory.
398
bulk = (char *)allocate(size);
399
vars = (kmp_env_var_t *)allocate(count * sizeof(kmp_env_var_t));
400
401
// Loop thru all the vars.
402
{
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.
407
int i;
408
var = bulk;
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);
417
vars[i].name = name;
418
vars[i].value = value;
419
// Move pointer.
420
var += len + 1;
421
}
422
}
423
424
// Fill out result.
425
block->bulk = bulk;
426
block->vars = vars;
427
block->count = count;
428
}
429
#endif
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(kmp_env_blk_t *block, // I: Block of environment variables.
487
char const *name // I: Name of variable to find.
488
) {
489
490
int i;
491
for (i = 0; i < block->count; ++i) {
492
if (strcmp(block->vars[i].name, name) == 0) {
493
return block->vars[i].value;
494
}
495
}
496
return NULL;
497
498
} // __kmp_env_block_var
499
500
// end of file //
501
502