@shd101wyy/yo 0.1.26 → 0.1.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/skills/yo-async-effects/SKILL.md +4 -4
- package/.github/skills/yo-async-effects/async-effects-recipes.md +34 -34
- package/.github/skills/yo-core-patterns/SKILL.md +1 -1
- package/.github/skills/yo-core-patterns/core-patterns-cheatsheet.md +26 -26
- package/.github/skills/yo-project-workflow/SKILL.md +6 -3
- package/.github/skills/yo-project-workflow/workflow-cheatsheet.md +34 -11
- package/.github/skills/yo-syntax/SKILL.md +7 -6
- package/.github/skills/yo-syntax/syntax-cheatsheet.md +73 -60
- package/.github/skills/yo-wasm-integration/wasm-integration-cheatsheet.md +3 -3
- package/README.md +10 -8
- package/out/cjs/index.cjs +456 -438
- package/out/cjs/yo-cli.cjs +576 -543
- package/out/cjs/yo-lsp.cjs +559 -532
- package/out/esm/index.mjs +281 -263
- package/out/types/src/formatter.d.ts +11 -0
- package/out/types/src/lsp/formatting.d.ts +2 -0
- package/out/types/src/tests/formatter.test.d.ts +1 -0
- package/out/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/std/alg/hash.yo +13 -21
- package/std/allocator.yo +25 -40
- package/std/async.yo +3 -7
- package/std/build.yo +105 -151
- package/std/cli/arg_parser.yo +184 -169
- package/std/collections/array_list.yo +350 -314
- package/std/collections/btree_map.yo +142 -131
- package/std/collections/deque.yo +132 -128
- package/std/collections/hash_map.yo +542 -566
- package/std/collections/hash_set.yo +623 -687
- package/std/collections/linked_list.yo +275 -293
- package/std/collections/ordered_map.yo +113 -85
- package/std/collections/priority_queue.yo +73 -73
- package/std/crypto/md5.yo +191 -95
- package/std/crypto/random.yo +56 -64
- package/std/crypto/sha256.yo +151 -107
- package/std/encoding/base64.yo +87 -81
- package/std/encoding/hex.yo +43 -50
- package/std/encoding/html.yo +56 -81
- package/std/encoding/html_char_utils.yo +7 -13
- package/std/encoding/html_entities.yo +2248 -2253
- package/std/encoding/json.yo +316 -224
- package/std/encoding/punycode.yo +86 -116
- package/std/encoding/toml.yo +67 -66
- package/std/encoding/utf16.yo +37 -44
- package/std/env.yo +62 -91
- package/std/error.yo +7 -15
- package/std/fmt/display.yo +5 -9
- package/std/fmt/index.yo +8 -14
- package/std/fmt/to_string.yo +330 -315
- package/std/fmt/writer.yo +58 -87
- package/std/fs/dir.yo +83 -102
- package/std/fs/file.yo +147 -180
- package/std/fs/metadata.yo +45 -78
- package/std/fs/temp.yo +55 -65
- package/std/fs/types.yo +27 -40
- package/std/fs/walker.yo +53 -68
- package/std/gc.yo +5 -8
- package/std/glob.yo +30 -43
- package/std/http/client.yo +107 -120
- package/std/http/http.yo +106 -96
- package/std/http/index.yo +4 -6
- package/std/imm/list.yo +88 -93
- package/std/imm/map.yo +528 -464
- package/std/imm/set.yo +52 -57
- package/std/imm/sorted_map.yo +340 -286
- package/std/imm/sorted_set.yo +57 -63
- package/std/imm/string.yo +404 -345
- package/std/imm/vec.yo +173 -181
- package/std/io/reader.yo +3 -6
- package/std/io/writer.yo +4 -8
- package/std/libc/assert.yo +5 -9
- package/std/libc/ctype.yo +32 -22
- package/std/libc/dirent.yo +26 -25
- package/std/libc/errno.yo +164 -90
- package/std/libc/fcntl.yo +52 -45
- package/std/libc/float.yo +66 -44
- package/std/libc/limits.yo +42 -33
- package/std/libc/math.yo +53 -82
- package/std/libc/signal.yo +72 -47
- package/std/libc/stdatomic.yo +217 -188
- package/std/libc/stdint.yo +5 -29
- package/std/libc/stdio.yo +5 -29
- package/std/libc/stdlib.yo +32 -39
- package/std/libc/string.yo +5 -23
- package/std/libc/sys/stat.yo +58 -56
- package/std/libc/time.yo +5 -19
- package/std/libc/unistd.yo +5 -20
- package/std/libc/wctype.yo +6 -9
- package/std/libc/windows.yo +26 -30
- package/std/log.yo +41 -55
- package/std/net/addr.yo +102 -97
- package/std/net/dns.yo +27 -28
- package/std/net/errors.yo +50 -49
- package/std/net/tcp.yo +113 -124
- package/std/net/udp.yo +55 -66
- package/std/os/env.yo +35 -33
- package/std/os/signal.yo +15 -25
- package/std/path.yo +276 -311
- package/std/prelude.yo +6304 -4315
- package/std/process/command.yo +87 -103
- package/std/process/index.yo +12 -31
- package/std/regex/compiler.yo +196 -95
- package/std/regex/flags.yo +58 -39
- package/std/regex/index.yo +157 -173
- package/std/regex/match.yo +20 -31
- package/std/regex/node.yo +134 -152
- package/std/regex/parser.yo +283 -259
- package/std/regex/unicode.yo +172 -202
- package/std/regex/vm.yo +155 -171
- package/std/string/index.yo +5 -7
- package/std/string/rune.yo +45 -55
- package/std/string/string.yo +937 -964
- package/std/string/string_builder.yo +94 -104
- package/std/string/unicode.yo +46 -64
- package/std/sync/channel.yo +72 -73
- package/std/sync/cond.yo +31 -36
- package/std/sync/mutex.yo +30 -32
- package/std/sync/once.yo +13 -16
- package/std/sync/rwlock.yo +26 -31
- package/std/sync/waitgroup.yo +20 -25
- package/std/sys/advise.yo +16 -24
- package/std/sys/bufio/buf_reader.yo +77 -93
- package/std/sys/bufio/buf_writer.yo +52 -65
- package/std/sys/clock.yo +4 -9
- package/std/sys/constants.yo +77 -61
- package/std/sys/copy.yo +4 -10
- package/std/sys/dir.yo +26 -43
- package/std/sys/dns.yo +41 -61
- package/std/sys/errors.yo +95 -103
- package/std/sys/events.yo +45 -57
- package/std/sys/externs.yo +319 -267
- package/std/sys/fallocate.yo +7 -11
- package/std/sys/fcntl.yo +14 -22
- package/std/sys/file.yo +26 -40
- package/std/sys/future.yo +5 -8
- package/std/sys/iov.yo +12 -25
- package/std/sys/lock.yo +12 -13
- package/std/sys/mmap.yo +38 -43
- package/std/sys/path.yo +3 -8
- package/std/sys/perm.yo +7 -21
- package/std/sys/pipe.yo +5 -12
- package/std/sys/process.yo +23 -29
- package/std/sys/seek.yo +10 -12
- package/std/sys/signal.yo +7 -13
- package/std/sys/signals.yo +52 -35
- package/std/sys/socket.yo +63 -58
- package/std/sys/socketpair.yo +3 -6
- package/std/sys/sockinfo.yo +11 -20
- package/std/sys/statfs.yo +11 -34
- package/std/sys/statx.yo +25 -52
- package/std/sys/sysinfo.yo +15 -20
- package/std/sys/tcp.yo +62 -92
- package/std/sys/temp.yo +5 -9
- package/std/sys/time.yo +5 -15
- package/std/sys/timer.yo +6 -11
- package/std/sys/tty.yo +10 -18
- package/std/sys/udp.yo +22 -39
- package/std/sys/umask.yo +3 -6
- package/std/sys/unix.yo +33 -52
- package/std/testing/bench.yo +49 -52
- package/std/thread.yo +10 -15
- package/std/time/datetime.yo +105 -89
- package/std/time/duration.yo +43 -56
- package/std/time/instant.yo +13 -18
- package/std/time/sleep.yo +5 -9
- package/std/url/index.yo +184 -209
- package/std/worker.yo +6 -10
package/std/sync/channel.yo
CHANGED
|
@@ -18,60 +18,63 @@
|
|
|
18
18
|
//! assert((val.unwrap() == i32(42)), "received value");
|
|
19
19
|
//! t.join();
|
|
20
20
|
//! ```
|
|
21
|
-
|
|
22
|
-
{ GlobalAllocator } :: import "../allocator";
|
|
21
|
+
{ GlobalAllocator } :: import("../allocator");
|
|
23
22
|
{ malloc, free } :: GlobalAllocator;
|
|
24
|
-
{ Mutex } :: import
|
|
25
|
-
{ Cond } :: import
|
|
26
|
-
|
|
23
|
+
{ Mutex } :: import("./mutex");
|
|
24
|
+
{ Cond } :: import("./cond");
|
|
27
25
|
/// Thread-safe bounded channel for passing values between threads.
|
|
28
26
|
/// Uses atomic reference counting — implements `Send` and can be
|
|
29
27
|
/// safely shared across threads without `Arc` wrapping.
|
|
30
28
|
/// T must implement `Send` to ensure values are safe to transfer between threads.
|
|
31
|
-
Channel :: (fn(comptime(T) : Type, where(T <: Send)) -> comptime(Type))
|
|
32
|
-
atomic
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
29
|
+
Channel :: (fn(comptime(T) : Type, where(T <: Send)) -> comptime(Type))(
|
|
30
|
+
atomic(
|
|
31
|
+
object(
|
|
32
|
+
_data : *(T),
|
|
33
|
+
_head : usize,
|
|
34
|
+
_len : usize,
|
|
35
|
+
_capacity : usize,
|
|
36
|
+
_mutex : Mutex,
|
|
37
|
+
_not_empty : Cond,
|
|
38
|
+
_not_full : Cond,
|
|
39
|
+
_closed : bool
|
|
40
|
+
)
|
|
41
41
|
)
|
|
42
|
-
;
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
);
|
|
43
|
+
impl(
|
|
44
|
+
forall(T : Type),
|
|
45
|
+
Channel(T),
|
|
46
|
+
where(T <: Send),
|
|
45
47
|
/// Create a bounded channel with the given capacity.
|
|
46
48
|
/// Capacity must be > 0.
|
|
47
|
-
new : (fn(capacity: usize) -> Self)({
|
|
48
|
-
assert(
|
|
49
|
-
(ptr : *(T)) = *(T)(malloc(
|
|
50
|
-
return
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
49
|
+
new : (fn(capacity : usize) -> Self)({
|
|
50
|
+
assert(capacity > usize(0), "Channel.new: capacity must be > 0");
|
|
51
|
+
(ptr : *(T)) = *(T)(malloc(capacity * sizeof(T)).unwrap());
|
|
52
|
+
return(
|
|
53
|
+
Self(
|
|
54
|
+
_data : ptr,
|
|
55
|
+
_head : usize(0),
|
|
56
|
+
_len : usize(0),
|
|
57
|
+
_capacity : capacity,
|
|
58
|
+
_mutex : Mutex.new(),
|
|
59
|
+
_not_empty : Cond.new(),
|
|
60
|
+
_not_full : Cond.new(),
|
|
61
|
+
_closed : false
|
|
62
|
+
)
|
|
59
63
|
);
|
|
60
64
|
}),
|
|
61
|
-
|
|
62
65
|
/// Send a value into the channel.
|
|
63
66
|
/// Blocks if the channel is full until space becomes available.
|
|
64
67
|
/// Returns .Ok(()) on success, .Err(()) if the channel is closed.
|
|
65
|
-
send : (fn(self: Self, value: T) -> Result(unit, unit))({
|
|
68
|
+
send : (fn(self : Self, value : T) -> Result(unit, unit))({
|
|
66
69
|
self._mutex.lock();
|
|
67
70
|
// Wait while buffer is full and channel is not closed
|
|
68
|
-
while
|
|
71
|
+
while(runtime((self._len >= self._capacity) && (!(self._closed))), {
|
|
69
72
|
self._not_full.wait(self._mutex);
|
|
70
|
-
};
|
|
73
|
+
});
|
|
71
74
|
cond(
|
|
72
75
|
self._closed => {
|
|
73
76
|
self._mutex.unlock();
|
|
74
|
-
return
|
|
77
|
+
return(.Err(()));
|
|
75
78
|
},
|
|
76
79
|
true => ()
|
|
77
80
|
);
|
|
@@ -81,22 +84,21 @@ impl(forall(T : Type), Channel(T), where(T <: Send),
|
|
|
81
84
|
self._len = (self._len + usize(1));
|
|
82
85
|
self._not_empty.signal();
|
|
83
86
|
self._mutex.unlock();
|
|
84
|
-
return
|
|
87
|
+
return(.Ok(()));
|
|
85
88
|
}),
|
|
86
|
-
|
|
87
89
|
/// Receive a value from the channel.
|
|
88
90
|
/// Blocks if the channel is empty until a value is available.
|
|
89
91
|
/// Returns .Some(value) on success, .None if the channel is closed and empty.
|
|
90
|
-
recv : (fn(self: Self) -> ?T)({
|
|
92
|
+
recv : (fn(self : Self) -> ?(T))({
|
|
91
93
|
self._mutex.lock();
|
|
92
94
|
// Wait while buffer is empty and channel is not closed
|
|
93
|
-
while
|
|
95
|
+
while(runtime((self._len == usize(0)) && (!(self._closed))), {
|
|
94
96
|
self._not_empty.wait(self._mutex);
|
|
95
|
-
};
|
|
97
|
+
});
|
|
96
98
|
cond(
|
|
97
99
|
(self._len == usize(0)) => {
|
|
98
100
|
self._mutex.unlock();
|
|
99
|
-
return
|
|
101
|
+
return(.None);
|
|
100
102
|
},
|
|
101
103
|
true => ()
|
|
102
104
|
);
|
|
@@ -108,17 +110,16 @@ impl(forall(T : Type), Channel(T), where(T <: Send),
|
|
|
108
110
|
self._len = (self._len - usize(1));
|
|
109
111
|
self._not_full.signal();
|
|
110
112
|
self._mutex.unlock();
|
|
111
|
-
return
|
|
113
|
+
return(.Some(val));
|
|
112
114
|
}),
|
|
113
|
-
|
|
114
115
|
/// Try to send a value without blocking.
|
|
115
116
|
/// Returns .Ok(()) if sent, .Err(()) if full or closed.
|
|
116
|
-
try_send : (fn(self: Self, value: T) -> Result(unit, unit))({
|
|
117
|
+
try_send : (fn(self : Self, value : T) -> Result(unit, unit))({
|
|
117
118
|
self._mutex.lock();
|
|
118
119
|
cond(
|
|
119
120
|
(self._closed || (self._len >= self._capacity)) => {
|
|
120
121
|
self._mutex.unlock();
|
|
121
|
-
return
|
|
122
|
+
return(.Err(()));
|
|
122
123
|
},
|
|
123
124
|
true => ()
|
|
124
125
|
);
|
|
@@ -127,17 +128,16 @@ impl(forall(T : Type), Channel(T), where(T <: Send),
|
|
|
127
128
|
self._len = (self._len + usize(1));
|
|
128
129
|
self._not_empty.signal();
|
|
129
130
|
self._mutex.unlock();
|
|
130
|
-
return
|
|
131
|
+
return(.Ok(()));
|
|
131
132
|
}),
|
|
132
|
-
|
|
133
133
|
/// Try to receive a value without blocking.
|
|
134
134
|
/// Returns .Some(value) if available, .None if empty.
|
|
135
|
-
try_recv : (fn(self: Self) -> ?T)({
|
|
135
|
+
try_recv : (fn(self : Self) -> ?(T))({
|
|
136
136
|
self._mutex.lock();
|
|
137
137
|
cond(
|
|
138
138
|
(self._len == usize(0)) => {
|
|
139
139
|
self._mutex.unlock();
|
|
140
|
-
return
|
|
140
|
+
return(.None);
|
|
141
141
|
},
|
|
142
142
|
true => ()
|
|
143
143
|
);
|
|
@@ -148,47 +148,46 @@ impl(forall(T : Type), Channel(T), where(T <: Send),
|
|
|
148
148
|
self._len = (self._len - usize(1));
|
|
149
149
|
self._not_full.signal();
|
|
150
150
|
self._mutex.unlock();
|
|
151
|
-
return
|
|
151
|
+
return(.Some(val));
|
|
152
152
|
}),
|
|
153
|
-
|
|
154
153
|
/// Close the channel. No more values can be sent.
|
|
155
154
|
/// Pending recv() calls will return .None once the buffer is drained.
|
|
156
155
|
/// Pending send() calls will return .Err(()).
|
|
157
|
-
close : (fn(self: Self) -> unit)({
|
|
156
|
+
close : (fn(self : Self) -> unit)({
|
|
158
157
|
self._mutex.lock();
|
|
159
158
|
self._closed = true;
|
|
160
159
|
self._not_empty.broadcast();
|
|
161
160
|
self._not_full.broadcast();
|
|
162
161
|
self._mutex.unlock();
|
|
163
162
|
}),
|
|
164
|
-
|
|
165
163
|
/// Check if the channel is closed.
|
|
166
|
-
is_closed : (fn(self: Self) -> bool)(
|
|
164
|
+
is_closed : (fn(self : Self) -> bool)(
|
|
167
165
|
self._closed
|
|
168
166
|
),
|
|
169
|
-
|
|
170
167
|
/// Return the number of values currently buffered.
|
|
171
|
-
len : (fn(self: Self) -> usize)(
|
|
168
|
+
len : (fn(self : Self) -> usize)(
|
|
172
169
|
self._len
|
|
173
170
|
),
|
|
174
|
-
|
|
175
171
|
/// Check if the channel buffer is empty.
|
|
176
|
-
is_empty : (fn(self: Self) -> bool)(
|
|
177
|
-
|
|
172
|
+
is_empty : (fn(self : Self) -> bool)(
|
|
173
|
+
self._len == usize(0)
|
|
178
174
|
)
|
|
179
175
|
);
|
|
180
|
-
|
|
181
176
|
// Dispose: drop remaining elements and free the buffer
|
|
182
|
-
impl(
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
i
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
));
|
|
193
|
-
|
|
194
|
-
|
|
177
|
+
impl(
|
|
178
|
+
forall(T : Type),
|
|
179
|
+
Channel(T),
|
|
180
|
+
where(T <: Send),
|
|
181
|
+
Dispose(
|
|
182
|
+
dispose : (fn(self : Self) -> unit)({
|
|
183
|
+
(i : usize) = usize(0);
|
|
184
|
+
while(runtime(i < self._len), {
|
|
185
|
+
(idx : usize) = ((self._head + i) % self._capacity);
|
|
186
|
+
unsafe.drop((self._data &+ idx).*);
|
|
187
|
+
i = (i + usize(1));
|
|
188
|
+
});
|
|
189
|
+
free(.Some(*(void)(self._data)));
|
|
190
|
+
})
|
|
191
|
+
)
|
|
192
|
+
);
|
|
193
|
+
export(Channel);
|
package/std/sync/cond.yo
CHANGED
|
@@ -1,74 +1,69 @@
|
|
|
1
1
|
//! Condition variable for thread synchronization.
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
extern "Yo",
|
|
2
|
+
{ __YO_THREAD_SYNC_TYPE, mutex_t, Mutex } :: import("./mutex");
|
|
3
|
+
extern(
|
|
4
|
+
"Yo",
|
|
6
5
|
__YO_COND_TYPE : Type,
|
|
7
6
|
__yo_cond_create : (fn() -> __YO_COND_TYPE),
|
|
8
7
|
__yo_cond_wait : (fn(cv : *(__YO_COND_TYPE), mutex : *(__YO_THREAD_SYNC_TYPE)) -> unit),
|
|
9
8
|
__yo_cond_signal : (fn(cv : *(__YO_COND_TYPE)) -> unit),
|
|
10
9
|
__yo_cond_broadcast : (fn(cv : *(__YO_COND_TYPE)) -> unit),
|
|
11
10
|
__yo_cond_destroy : (fn(cv : *(__YO_COND_TYPE)) -> unit)
|
|
12
|
-
;
|
|
13
|
-
|
|
11
|
+
);
|
|
14
12
|
impl(__YO_COND_TYPE, Send());
|
|
15
13
|
impl(__YO_COND_TYPE, Acyclic());
|
|
16
|
-
|
|
17
14
|
/// Low-level condition variable (manual lifetime via `destroy`).
|
|
18
15
|
cond_t :: newtype(
|
|
19
16
|
cv : __YO_COND_TYPE
|
|
20
17
|
);
|
|
21
|
-
impl(
|
|
18
|
+
impl(
|
|
19
|
+
cond_t,
|
|
22
20
|
new : (fn() -> Self)({
|
|
23
|
-
return
|
|
21
|
+
return(Self(__yo_cond_create()));
|
|
24
22
|
}),
|
|
25
|
-
|
|
26
23
|
wait : (fn(self : *(Self), mutex : *(mutex_t)) -> unit)({
|
|
27
|
-
return
|
|
24
|
+
return(__yo_cond_wait(&(self.cv), &(mutex.mutex)));
|
|
28
25
|
}),
|
|
29
|
-
|
|
30
26
|
signal : (fn(self : *(Self)) -> unit)({
|
|
31
|
-
return
|
|
27
|
+
return(__yo_cond_signal(&(self.cv)));
|
|
32
28
|
}),
|
|
33
|
-
|
|
34
29
|
broadcast : (fn(self : *(Self)) -> unit)({
|
|
35
|
-
return
|
|
30
|
+
return(__yo_cond_broadcast(&(self.cv)));
|
|
36
31
|
}),
|
|
37
|
-
|
|
38
32
|
destroy : (fn(self : *(Self)) -> unit)({
|
|
39
|
-
return
|
|
33
|
+
return(__yo_cond_destroy(&(self.cv)));
|
|
40
34
|
})
|
|
41
35
|
);
|
|
42
|
-
|
|
43
36
|
/// Reference-counted condition variable with automatic cleanup via `Dispose`.
|
|
44
37
|
/// Uses atomic reference counting for safe cross-thread sharing.
|
|
45
|
-
Cond :: atomic
|
|
46
|
-
|
|
38
|
+
Cond :: atomic(
|
|
39
|
+
object(
|
|
40
|
+
cv : __YO_COND_TYPE
|
|
41
|
+
)
|
|
47
42
|
);
|
|
48
|
-
impl(
|
|
43
|
+
impl(
|
|
44
|
+
Cond,
|
|
49
45
|
new : (fn() -> Self)({
|
|
50
|
-
return
|
|
46
|
+
return(Self(__yo_cond_create()));
|
|
51
47
|
}),
|
|
52
|
-
|
|
53
48
|
wait : (fn(self : Self, mutex : Mutex) -> unit)({
|
|
54
|
-
return
|
|
49
|
+
return(__yo_cond_wait(&(self.cv), &(mutex.mutex)));
|
|
55
50
|
}),
|
|
56
|
-
|
|
57
51
|
signal : (fn(self : Self) -> unit)({
|
|
58
|
-
return
|
|
52
|
+
return(__yo_cond_signal(&(self.cv)));
|
|
59
53
|
}),
|
|
60
|
-
|
|
61
54
|
broadcast : (fn(self : Self) -> unit)({
|
|
62
|
-
return
|
|
55
|
+
return(__yo_cond_broadcast(&(self.cv)));
|
|
63
56
|
})
|
|
64
57
|
);
|
|
65
|
-
impl(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
));
|
|
70
|
-
|
|
71
|
-
|
|
58
|
+
impl(
|
|
59
|
+
Cond,
|
|
60
|
+
Dispose(
|
|
61
|
+
dispose : (fn(self : Self) -> unit)({
|
|
62
|
+
return(__yo_cond_destroy(&(self.cv)));
|
|
63
|
+
})
|
|
64
|
+
)
|
|
65
|
+
);
|
|
66
|
+
export(
|
|
72
67
|
cond_t,
|
|
73
68
|
Cond
|
|
74
|
-
;
|
|
69
|
+
);
|
package/std/sync/mutex.yo
CHANGED
|
@@ -1,64 +1,62 @@
|
|
|
1
1
|
//! Mutual exclusion lock primitives.
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
extern(
|
|
3
|
+
"Yo",
|
|
4
4
|
__YO_THREAD_SYNC_TYPE : Type,
|
|
5
5
|
__yo_mutex_create : (fn() -> __YO_THREAD_SYNC_TYPE),
|
|
6
6
|
__yo_mutex_lock : (fn(mutex : *(__YO_THREAD_SYNC_TYPE)) -> unit),
|
|
7
7
|
__yo_mutex_unlock : (fn(mutex : *(__YO_THREAD_SYNC_TYPE)) -> unit),
|
|
8
8
|
__yo_mutex_destroy : (fn(mutex : *(__YO_THREAD_SYNC_TYPE)) -> unit)
|
|
9
|
-
;
|
|
10
|
-
|
|
9
|
+
);
|
|
11
10
|
impl(__YO_THREAD_SYNC_TYPE, Send());
|
|
12
11
|
impl(__YO_THREAD_SYNC_TYPE, Acyclic());
|
|
13
|
-
|
|
14
12
|
/// Low-level mutex (manual lifetime via `destroy`).
|
|
15
13
|
mutex_t :: newtype(
|
|
16
14
|
mutex : __YO_THREAD_SYNC_TYPE
|
|
17
15
|
);
|
|
18
|
-
impl(
|
|
16
|
+
impl(
|
|
17
|
+
mutex_t,
|
|
19
18
|
new : (fn() -> Self)({
|
|
20
|
-
return
|
|
19
|
+
return(Self(__yo_mutex_create()));
|
|
21
20
|
}),
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return __yo_mutex_lock(&(self.mutex));
|
|
21
|
+
lock : (fn(self : *(Self)) -> unit)({
|
|
22
|
+
return(__yo_mutex_lock(&(self.mutex)));
|
|
25
23
|
}),
|
|
26
|
-
|
|
27
24
|
unlock : (fn(self : *(Self)) -> unit)({
|
|
28
|
-
return
|
|
25
|
+
return(__yo_mutex_unlock(&(self.mutex)));
|
|
29
26
|
}),
|
|
30
|
-
|
|
31
27
|
destroy : (fn(self : *(Self)) -> unit)({
|
|
32
|
-
return
|
|
28
|
+
return(__yo_mutex_destroy(&(self.mutex)));
|
|
33
29
|
})
|
|
34
30
|
);
|
|
35
|
-
|
|
36
31
|
/// Reference-counted mutex with automatic cleanup via `Dispose`.
|
|
37
32
|
/// Uses atomic reference counting for safe cross-thread sharing.
|
|
38
|
-
Mutex :: atomic
|
|
39
|
-
|
|
33
|
+
Mutex :: atomic(
|
|
34
|
+
object(
|
|
35
|
+
mutex : __YO_THREAD_SYNC_TYPE
|
|
36
|
+
)
|
|
40
37
|
);
|
|
41
|
-
impl(
|
|
38
|
+
impl(
|
|
39
|
+
Mutex,
|
|
42
40
|
new : (fn() -> Self)({
|
|
43
|
-
return
|
|
41
|
+
return(Self(__yo_mutex_create()));
|
|
44
42
|
}),
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
return __yo_mutex_lock(&(self.mutex));
|
|
43
|
+
lock : (fn(self : Self) -> unit)({
|
|
44
|
+
return(__yo_mutex_lock(&(self.mutex)));
|
|
48
45
|
}),
|
|
49
|
-
|
|
50
46
|
unlock : (fn(self : Self) -> unit)({
|
|
51
|
-
return
|
|
47
|
+
return(__yo_mutex_unlock(&(self.mutex)));
|
|
52
48
|
})
|
|
53
49
|
);
|
|
54
|
-
impl(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
));
|
|
59
|
-
|
|
60
|
-
|
|
50
|
+
impl(
|
|
51
|
+
Mutex,
|
|
52
|
+
Dispose(
|
|
53
|
+
dispose : (fn(self : Self) -> unit)({
|
|
54
|
+
return(__yo_mutex_destroy(&(self.mutex)));
|
|
55
|
+
})
|
|
56
|
+
)
|
|
57
|
+
);
|
|
58
|
+
export(
|
|
61
59
|
__YO_THREAD_SYNC_TYPE,
|
|
62
60
|
mutex_t,
|
|
63
61
|
Mutex
|
|
64
|
-
;
|
|
62
|
+
);
|
package/std/sync/once.yo
CHANGED
|
@@ -14,31 +14,30 @@
|
|
|
14
14
|
//! println("this will NOT run");
|
|
15
15
|
//! });
|
|
16
16
|
//! ```
|
|
17
|
-
|
|
18
|
-
{ Mutex } :: import "./mutex";
|
|
19
|
-
|
|
17
|
+
{ Mutex } :: import("./mutex");
|
|
20
18
|
/// Execute a function exactly once, thread-safely.
|
|
21
19
|
/// Uses atomic reference counting for safe cross-thread sharing.
|
|
22
|
-
Once :: atomic
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
Once :: atomic(
|
|
21
|
+
object(
|
|
22
|
+
_done : bool,
|
|
23
|
+
_mutex : Mutex
|
|
24
|
+
)
|
|
25
25
|
);
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
impl(
|
|
27
|
+
Once,
|
|
28
28
|
// Create a new Once.
|
|
29
29
|
new : (fn() -> Self)(
|
|
30
30
|
Self(
|
|
31
|
-
_done: false,
|
|
32
|
-
_mutex: Mutex.new()
|
|
31
|
+
_done : false,
|
|
32
|
+
_mutex : Mutex.new()
|
|
33
33
|
)
|
|
34
34
|
),
|
|
35
|
-
|
|
36
35
|
// Execute the function exactly once.
|
|
37
36
|
// Subsequent calls are no-ops.
|
|
38
37
|
// Note: The fast-path read of _done is not strictly atomic, but since _done
|
|
39
38
|
// is only ever set from false to true and the double-check inside the lock
|
|
40
39
|
// prevents the function from running twice, this is safe in practice.
|
|
41
|
-
call : (fn(self: Self, f: Impl(Fn() -> unit)) -> unit)({
|
|
40
|
+
call : (fn(self : Self, f : Impl(Fn() -> unit)) -> unit)({
|
|
42
41
|
// Fast path: already done
|
|
43
42
|
cond(
|
|
44
43
|
self._done => (),
|
|
@@ -58,11 +57,9 @@ impl(Once,
|
|
|
58
57
|
}
|
|
59
58
|
);
|
|
60
59
|
}),
|
|
61
|
-
|
|
62
60
|
// Check if the function has been called.
|
|
63
|
-
is_done : (fn(self: Self) -> bool)(
|
|
61
|
+
is_done : (fn(self : Self) -> bool)(
|
|
64
62
|
self._done
|
|
65
63
|
)
|
|
66
64
|
);
|
|
67
|
-
|
|
68
|
-
export Once;
|
|
65
|
+
export(Once);
|
package/std/sync/rwlock.yo
CHANGED
|
@@ -16,45 +16,43 @@
|
|
|
16
16
|
//! // ... write shared data ...
|
|
17
17
|
//! lock.write_unlock();
|
|
18
18
|
//! ```
|
|
19
|
-
|
|
20
|
-
{
|
|
21
|
-
{ Cond } :: import "./cond";
|
|
22
|
-
|
|
19
|
+
{ Mutex } :: import("./mutex");
|
|
20
|
+
{ Cond } :: import("./cond");
|
|
23
21
|
/// Reader-writer lock built on `Mutex` and `Cond`.
|
|
24
22
|
/// Uses atomic reference counting for safe cross-thread sharing.
|
|
25
|
-
RwLock :: atomic
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
RwLock :: atomic(
|
|
24
|
+
object(
|
|
25
|
+
_readers : i32,
|
|
26
|
+
_writer : bool,
|
|
27
|
+
_mutex : Mutex,
|
|
28
|
+
_read_cv : Cond,
|
|
29
|
+
_write_cv : Cond
|
|
30
|
+
)
|
|
31
31
|
);
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
impl(
|
|
33
|
+
RwLock,
|
|
34
34
|
// Create a new reader-writer lock.
|
|
35
35
|
new : (fn() -> Self)(
|
|
36
36
|
Self(
|
|
37
|
-
_readers: i32(0),
|
|
38
|
-
_writer: false,
|
|
39
|
-
_mutex: Mutex.new(),
|
|
40
|
-
_read_cv: Cond.new(),
|
|
41
|
-
_write_cv: Cond.new()
|
|
37
|
+
_readers : i32(0),
|
|
38
|
+
_writer : false,
|
|
39
|
+
_mutex : Mutex.new(),
|
|
40
|
+
_read_cv : Cond.new(),
|
|
41
|
+
_write_cv : Cond.new()
|
|
42
42
|
)
|
|
43
43
|
),
|
|
44
|
-
|
|
45
44
|
// Acquire a read lock. Blocks if a writer holds the lock.
|
|
46
45
|
// Multiple readers can hold the lock simultaneously.
|
|
47
|
-
read_lock : (fn(self: Self) -> unit)({
|
|
46
|
+
read_lock : (fn(self : Self) -> unit)({
|
|
48
47
|
self._mutex.lock();
|
|
49
|
-
while
|
|
48
|
+
while(runtime(self._writer), {
|
|
50
49
|
self._read_cv.wait(self._mutex);
|
|
51
|
-
};
|
|
50
|
+
});
|
|
52
51
|
self._readers = (self._readers + i32(1));
|
|
53
52
|
self._mutex.unlock();
|
|
54
53
|
}),
|
|
55
|
-
|
|
56
54
|
// Release a read lock.
|
|
57
|
-
read_unlock : (fn(self: Self) -> unit)({
|
|
55
|
+
read_unlock : (fn(self : Self) -> unit)({
|
|
58
56
|
self._mutex.lock();
|
|
59
57
|
self._readers = (self._readers - i32(1));
|
|
60
58
|
cond(
|
|
@@ -63,19 +61,17 @@ impl(RwLock,
|
|
|
63
61
|
);
|
|
64
62
|
self._mutex.unlock();
|
|
65
63
|
}),
|
|
66
|
-
|
|
67
64
|
// Acquire a write lock. Blocks until all readers and writers release.
|
|
68
|
-
write_lock : (fn(self: Self) -> unit)({
|
|
65
|
+
write_lock : (fn(self : Self) -> unit)({
|
|
69
66
|
self._mutex.lock();
|
|
70
|
-
while
|
|
67
|
+
while(runtime(self._writer || (self._readers > i32(0))), {
|
|
71
68
|
self._write_cv.wait(self._mutex);
|
|
72
|
-
};
|
|
69
|
+
});
|
|
73
70
|
self._writer = true;
|
|
74
71
|
self._mutex.unlock();
|
|
75
72
|
}),
|
|
76
|
-
|
|
77
73
|
// Release a write lock.
|
|
78
|
-
write_unlock : (fn(self: Self) -> unit)({
|
|
74
|
+
write_unlock : (fn(self : Self) -> unit)({
|
|
79
75
|
self._mutex.lock();
|
|
80
76
|
self._writer = false;
|
|
81
77
|
self._read_cv.broadcast();
|
|
@@ -83,5 +79,4 @@ impl(RwLock,
|
|
|
83
79
|
self._mutex.unlock();
|
|
84
80
|
})
|
|
85
81
|
);
|
|
86
|
-
|
|
87
|
-
export RwLock;
|
|
82
|
+
export(RwLock);
|
package/std/sync/waitgroup.yo
CHANGED
|
@@ -18,31 +18,30 @@
|
|
|
18
18
|
//! };
|
|
19
19
|
//! wg.wait(); // blocks until all 3 tasks call done()
|
|
20
20
|
//! ```
|
|
21
|
-
|
|
22
|
-
{
|
|
23
|
-
{ Cond } :: import "./cond";
|
|
24
|
-
|
|
21
|
+
{ Mutex } :: import("./mutex");
|
|
22
|
+
{ Cond } :: import("./cond");
|
|
25
23
|
/// Synchronization primitive that blocks until a counter reaches zero.
|
|
26
24
|
/// Uses atomic reference counting for safe cross-thread sharing.
|
|
27
|
-
WaitGroup :: atomic
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
WaitGroup :: atomic(
|
|
26
|
+
object(
|
|
27
|
+
_count : i32,
|
|
28
|
+
_mutex : Mutex,
|
|
29
|
+
_cv : Cond
|
|
30
|
+
)
|
|
31
31
|
);
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
impl(
|
|
33
|
+
WaitGroup,
|
|
34
34
|
// Create a new WaitGroup with count 0.
|
|
35
35
|
new : (fn() -> Self)(
|
|
36
36
|
Self(
|
|
37
|
-
_count: i32(0),
|
|
38
|
-
_mutex: Mutex.new(),
|
|
39
|
-
_cv: Cond.new()
|
|
37
|
+
_count : i32(0),
|
|
38
|
+
_mutex : Mutex.new(),
|
|
39
|
+
_cv : Cond.new()
|
|
40
40
|
)
|
|
41
41
|
),
|
|
42
|
-
|
|
43
42
|
// Add delta to the counter (can be negative).
|
|
44
43
|
// If the counter becomes zero, all waiters are woken.
|
|
45
|
-
add : (fn(self: Self, delta: i32) -> unit)({
|
|
44
|
+
add : (fn(self : Self, delta : i32) -> unit)({
|
|
46
45
|
self._mutex.lock();
|
|
47
46
|
self._count = (self._count + delta);
|
|
48
47
|
cond(
|
|
@@ -54,25 +53,21 @@ impl(WaitGroup,
|
|
|
54
53
|
);
|
|
55
54
|
self._mutex.unlock();
|
|
56
55
|
}),
|
|
57
|
-
|
|
58
56
|
// Decrement the counter by one (equivalent to add(-1)).
|
|
59
|
-
done : (fn(self: Self) -> unit)(
|
|
57
|
+
done : (fn(self : Self) -> unit)(
|
|
60
58
|
self.add(i32(-(1)))
|
|
61
59
|
),
|
|
62
|
-
|
|
63
60
|
// Block until the counter reaches zero.
|
|
64
|
-
wait : (fn(self: Self) -> unit)({
|
|
61
|
+
wait : (fn(self : Self) -> unit)({
|
|
65
62
|
self._mutex.lock();
|
|
66
|
-
while
|
|
63
|
+
while(runtime(self._count > i32(0)), {
|
|
67
64
|
self._cv.wait(self._mutex);
|
|
68
|
-
};
|
|
65
|
+
});
|
|
69
66
|
self._mutex.unlock();
|
|
70
67
|
}),
|
|
71
|
-
|
|
72
68
|
// Get the current count (for debugging).
|
|
73
|
-
count : (fn(self: Self) -> i32)(
|
|
69
|
+
count : (fn(self : Self) -> i32)(
|
|
74
70
|
self._count
|
|
75
71
|
)
|
|
76
72
|
);
|
|
77
|
-
|
|
78
|
-
export WaitGroup;
|
|
73
|
+
export(WaitGroup);
|