@@ -90,6 +90,7 @@ $(LREF environment), $(LREF thisProcessID) and $(LREF thisThreadID).
90
90
module std.process ;
91
91
92
92
import core.thread : ThreadID;
93
+ import core.sync.rwmutex ;
93
94
94
95
version (Posix )
95
96
{
@@ -160,6 +161,13 @@ private
160
161
// Environment variable manipulation.
161
162
// =============================================================================
162
163
164
+ shared ReadWriteMutex mutex;
165
+
166
+ shared static this ()
167
+ {
168
+ mutex = new shared ReadWriteMutex (mutex.Policy.PREFER_READERS );
169
+ }
170
+
163
171
/**
164
172
Manipulates _environment variables using an associative-array-like
165
173
interface.
@@ -259,12 +267,14 @@ static:
259
267
import std.exception : enforce, errnoEnforce;
260
268
if (value is null )
261
269
{
270
+ // Note: remove needs write lock
262
271
remove(name);
263
272
return value;
264
273
}
265
- if ( core.sys.posix.stdlib.setenv (name.tempCString(), value.tempCString(), 1 ) != - 1 )
274
+ synchronized (mutex.writer )
266
275
{
267
- return value;
276
+ if (core.sys.posix.stdlib.setenv (name.tempCString(), value.tempCString(), 1 ) != - 1 )
277
+ return value;
268
278
}
269
279
// The default errno error message is very uninformative
270
280
// in the most common case, so we handle it manually.
@@ -277,6 +287,8 @@ static:
277
287
else version (Windows )
278
288
{
279
289
import std.windows.syserror : wenforce;
290
+
291
+ synchronized (mutex.writer)
280
292
wenforce(
281
293
SetEnvironmentVariableW(name.tempCStringW(), value.tempCStringW()),
282
294
);
@@ -296,8 +308,9 @@ static:
296
308
multi-threaded programs. See e.g.
297
309
$(LINK2 https://www.gnu.org/software/libc/manual/html_node/Environment-Access.html#Environment-Access, glibc).
298
310
*/
299
- void remove (scope const (char )[] name) @trusted nothrow @nogc
311
+ void remove (scope const (char )[] name) @trusted // nothrow @nogc
300
312
{
313
+ synchronized (mutex.writer)
301
314
version (Windows ) SetEnvironmentVariableW(name.tempCStringW(), null );
302
315
else version (Posix ) core.sys.posix.stdlib.unsetenv (name.tempCString());
303
316
else static assert (0 );
@@ -329,6 +342,8 @@ static:
329
342
{
330
343
if (name is null )
331
344
return false ;
345
+
346
+ synchronized (mutex.reader)
332
347
version (Posix )
333
348
return core.sys.posix.stdlib.getenv (name.tempCString()) ! is null ;
334
349
else version (Windows )
@@ -363,6 +378,8 @@ static:
363
378
{
364
379
import std.conv : to;
365
380
string [string ] aa;
381
+
382
+ synchronized (mutex.reader)
366
383
version (Posix )
367
384
{
368
385
auto environ = getEnvironPtr;
@@ -428,12 +445,13 @@ private:
428
445
// Retrieves the environment variable. Calls `sink` with a
429
446
// temporary buffer of OS characters, or `null` if the variable
430
447
// doesn't exist.
431
- void getImpl (scope const (char )[] name, scope void delegate (const (OSChar)[]) @safe sink) @trusted
448
+ void getImpl (scope const (char )[] name, scope void delegate (scope const (OSChar)[]) @safe sink) @trusted
432
449
{
433
450
// fix issue https://issues.dlang.org/show_bug.cgi?id=24549
434
451
if (name is null )
435
452
return sink (null );
436
453
454
+ synchronized (mutex.reader)
437
455
version (Windows )
438
456
{
439
457
// first we ask windows how long the environment variable is,
@@ -1205,7 +1223,7 @@ private Pid spawnProcessPosix(scope const(char[])[] args,
1205
1223
}
1206
1224
1207
1225
// Execute program.
1208
- core.sys.posix.unistd.execve (argz[0 ], argz.ptr, envz is null ? getEnvironPtr : envz );
1226
+ core.sys.posix.unistd.execve (argz[0 ], argz.ptr, envz);
1209
1227
1210
1228
// If execution fails, exit as quickly as possible.
1211
1229
abortOnError(forkPipeOut, InternalError.exec, .errno);
@@ -1511,7 +1529,7 @@ private Pid spawnProcessWin(scope const(char)[] commandLine,
1511
1529
// on the form "name=value", optionally adding those of the current process'
1512
1530
// environment strings that are not present in childEnv. If the parent's
1513
1531
// environment should be inherited without modification, this function
1514
- // returns null .
1532
+ // returns environ directly .
1515
1533
version (Posix )
1516
1534
private const (char * )* createEnv (const string [string ] childEnv,
1517
1535
bool mergeWithParentEnv)
@@ -1521,7 +1539,7 @@ private const(char*)* createEnv(const string[string] childEnv,
1521
1539
auto environ = getEnvironPtr;
1522
1540
if (mergeWithParentEnv)
1523
1541
{
1524
- if (childEnv.length == 0 ) return null ;
1542
+ if (childEnv.length == 0 ) return environ ;
1525
1543
while (environ[parentEnvLength] != null ) ++ parentEnvLength;
1526
1544
}
1527
1545
@@ -1551,7 +1569,16 @@ version (Posix) @system unittest
1551
1569
assert (e1 != null && * e1 == null );
1552
1570
1553
1571
auto e2 = createEnv(null , true );
1554
- assert (e2 == null );
1572
+ assert (e2 != null );
1573
+ int i = 0 ;
1574
+ auto environ = getEnvironPtr;
1575
+ for (; environ[i] != null ; ++ i)
1576
+ {
1577
+ assert (e2[i] != null );
1578
+ import core.stdc.string : strcmp;
1579
+ assert (strcmp(e2[i], environ[i]) == 0 );
1580
+ }
1581
+ assert (e2[i] == null );
1555
1582
1556
1583
auto e3 = createEnv([" foo" : " bar" , " hello" : " world" ], false );
1557
1584
assert (e3 != null && e3[0 ] != null && e3[1 ] != null && e3[2 ] == null );
0 commit comments