@@ -20,19 +20,18 @@ NOT_FOUND :: -1
20
20
// the environment is a 0 delimited list of <key>=<value> strings
21
21
_env: [dynamic ]string
22
22
23
- _env_mutex: sync.Mutex
23
+ _env_mutex: sync.Recursive_Mutex
24
24
25
25
// We need to be able to figure out if the environment variable
26
26
// is contained in the original environment or not. This also
27
27
// serves as a flag to determine if we have built _env.
28
- _org_env_begin: uintptr
29
- _org_env_end: uintptr
28
+ _org_env_begin: uintptr // atomic
29
+ _org_env_end: uintptr // guarded by _env_mutex
30
30
31
31
// Returns value + index location into _env
32
32
// or -1 if not found
33
33
_lookup :: proc (key: string ) -> (value: string , idx: int ) {
34
- sync.mutex_lock (&_env_mutex)
35
- defer sync.mutex_unlock (&_env_mutex)
34
+ sync.guard (&_env_mutex)
36
35
37
36
for entry, i in _env {
38
37
if k, v := _kv_from_entry (entry); k == key {
@@ -43,7 +42,7 @@ _lookup :: proc(key: string) -> (value: string, idx: int) {
43
42
}
44
43
45
44
_lookup_env :: proc (key: string , allocator: runtime.Allocator) -> (value: string , found: bool ) {
46
- if _org_env_begin == 0 {
45
+ if intrinsics. atomic_load_explicit (& _org_env_begin, .Acquire) == 0 {
47
46
_build_env ()
48
47
}
49
48
@@ -55,18 +54,17 @@ _lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string
55
54
}
56
55
57
56
_set_env :: proc (key, v_new: string ) -> Error {
58
- if _org_env_begin == 0 {
57
+ if intrinsics. atomic_load_explicit (& _org_env_begin, .Acquire) == 0 {
59
58
_build_env ()
60
59
}
60
+ sync.guard (&_env_mutex)
61
61
62
62
// all key values are stored as "key=value\x00"
63
63
kv_size := len (key) + len (v_new) + 2
64
64
if v_curr, idx := _lookup (key); idx != NOT_FOUND {
65
65
if v_curr == v_new {
66
66
return nil
67
67
}
68
- sync.mutex_lock (&_env_mutex)
69
- defer sync.mutex_unlock (&_env_mutex)
70
68
71
69
unordered_remove (&_env, idx)
72
70
@@ -101,41 +99,37 @@ _set_env :: proc(key, v_new: string) -> Error {
101
99
intrinsics.mem_copy_non_overlapping (&val_slice[0 ], raw_data (v_new), len (v_new))
102
100
val_slice[len (v_new)] = 0
103
101
104
- sync.mutex_lock (&_env_mutex)
105
102
append (&_env, string (k_addr[:kv_size - 1 ]))
106
- sync.mutex_unlock (&_env_mutex)
107
103
return nil
108
104
}
109
105
110
106
_unset_env :: proc (key: string ) -> bool {
111
- if _org_env_begin == 0 {
107
+ if intrinsics. atomic_load_explicit (& _org_env_begin, .Acquire) == 0 {
112
108
_build_env ()
113
109
}
110
+ sync.guard (&_env_mutex)
114
111
115
112
v: string
116
113
i: int
117
114
if v, i = _lookup (key); i == -1 {
118
115
return false
119
116
}
120
117
121
- sync.mutex_lock (&_env_mutex)
122
118
unordered_remove (&_env, i)
123
- sync.mutex_unlock (&_env_mutex)
124
119
125
120
if _is_in_org_env (v) {
126
121
return true
127
122
}
128
123
129
- // if we got this far, the envrionment variable
124
+ // if we got this far, the environment variable
130
125
// existed AND was allocated by us.
131
126
k_addr, _ := _kv_addr_from_val (v, key)
132
127
runtime.heap_free (k_addr)
133
128
return true
134
129
}
135
130
136
131
_clear_env :: proc () {
137
- sync.mutex_lock (&_env_mutex)
138
- defer sync.mutex_unlock (&_env_mutex)
132
+ sync.guard (&_env_mutex)
139
133
140
134
for kv in _env {
141
135
if !_is_in_org_env (kv) {
@@ -145,14 +139,16 @@ _clear_env :: proc() {
145
139
clear (&_env)
146
140
147
141
// nothing resides in the original environment either
148
- _org_env_begin = ~uintptr (0 )
142
+ intrinsics. atomic_store_explicit (& _org_env_begin, ~uintptr (0 ), .Release )
149
143
_org_env_end = ~uintptr (0 )
150
144
}
151
145
152
146
_environ :: proc (allocator: runtime.Allocator) -> (environ: []string , err: Error) {
153
- if _org_env_begin == 0 {
147
+ if intrinsics. atomic_load_explicit (& _org_env_begin, .Acquire) == 0 {
154
148
_build_env ()
155
149
}
150
+ sync.guard (&_env_mutex)
151
+
156
152
env := make ([dynamic ]string , 0 , len (_env), allocator) or_return
157
153
defer if err != nil {
158
154
for e in env {
@@ -161,8 +157,6 @@ _environ :: proc(allocator: runtime.Allocator) -> (environ: []string, err: Error
161
157
delete (env)
162
158
}
163
159
164
- sync.mutex_lock (&_env_mutex)
165
- defer sync.mutex_unlock (&_env_mutex)
166
160
for entry in _env {
167
161
s := clone_string (entry, allocator) or_return
168
162
append (&env, s)
@@ -174,36 +168,34 @@ _environ :: proc(allocator: runtime.Allocator) -> (environ: []string, err: Error
174
168
// The entire environment is stored as 0 terminated strings,
175
169
// so there is no need to clone/free individual variables
176
170
export_cstring_environment :: proc (allocator: runtime.Allocator) -> []cstring {
177
- if _org_env_begin == 0 {
171
+ if intrinsics. atomic_load_explicit (& _org_env_begin, .Acquire) == 0 {
178
172
// The environment has not been modified, so we can just
179
173
// send the original environment
180
174
org_env := _get_original_env ()
181
175
n: int
182
176
for ; org_env[n] != nil ; n += 1 {}
183
177
return slice.clone (org_env[:n + 1 ], allocator)
184
178
}
179
+ sync.guard (&_env_mutex)
185
180
186
181
// NOTE: already terminated by nil pointer via + 1
187
182
env := make ([]cstring , len (_env) + 1 , allocator)
188
183
189
- sync.mutex_lock (&_env_mutex)
190
- defer sync.mutex_unlock (&_env_mutex)
191
184
for entry, i in _env {
192
185
env[i] = cstring (raw_data (entry))
193
186
}
194
187
return env
195
188
}
196
189
197
190
_build_env :: proc () {
198
- sync.mutex_lock (&_env_mutex)
199
- defer sync.mutex_unlock (&_env_mutex)
200
- if _org_env_begin != 0 {
191
+ sync.guard (&_env_mutex)
192
+ if intrinsics.atomic_load_explicit (&_org_env_begin, .Acquire) != 0 {
201
193
return
202
194
}
203
195
204
196
_env = make (type_of (_env), runtime.heap_allocator ())
205
197
cstring_env := _get_original_env ()
206
- _org_env_begin = uintptr (rawptr (cstring_env[0 ]))
198
+ intrinsics. atomic_store_explicit (& _org_env_begin, uintptr (rawptr (cstring_env[0 ])), .Release )
207
199
for i := 0 ; cstring_env[i] != nil ; i += 1 {
208
200
bytes := ([^]u8 )(cstring_env[i])
209
201
n := len (cstring_env[i])
@@ -235,5 +227,5 @@ _kv_addr_from_val :: #force_inline proc(val: string, key: string) -> ([^]u8, [^]
235
227
236
228
_is_in_org_env :: #force_inline proc (env_data: string ) -> bool {
237
229
addr := uintptr (raw_data (env_data))
238
- return addr >= _org_env_begin && addr < _org_env_end
230
+ return addr >= intrinsics. atomic_load_explicit (& _org_env_begin, .Acquire) && addr < _org_env_end
239
231
}
0 commit comments