authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2019-11-06 21:41:35+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-11-06 15:17:40-05:00
log4530adbd3314c28e2cfe831e7a20b154614e2c9c
tree3c2e31a1017db85db193e317c31007056e13c6d0
parent913f7d045020f7f3301201cf69e1d788439d8886

use global event loop in std.event types


6 files changed, 55 insertions(+), 77 deletions(-)

lib/std/event/future.zig+5-12
...@@ -3,7 +3,6 @@ const assert = std.debug.assert;...@@ -3,7 +3,6 @@ const assert = std.debug.assert;
3const testing = std.testing;3const testing = std.testing;
4const builtin = @import("builtin");4const builtin = @import("builtin");
5const Lock = std.event.Lock;5const Lock = std.event.Lock;
6const Loop = std.event.Loop;
76
8/// This is a value that starts out unavailable, until resolve() is called7/// This is a value that starts out unavailable, until resolve() is called
9/// While it is unavailable, functions suspend when they try to get() it,8/// While it is unavailable, functions suspend when they try to get() it,
...@@ -23,9 +22,9 @@ pub fn Future(comptime T: type) type {...@@ -23,9 +22,9 @@ pub fn Future(comptime T: type) type {
23 const Self = @This();22 const Self = @This();
24 const Queue = std.atomic.Queue(anyframe);23 const Queue = std.atomic.Queue(anyframe);
2524
26 pub fn init(loop: *Loop) Self {25 pub fn init() Self {
27 return Self{26 return Self{
28 .lock = Lock.initLocked(loop),27 .lock = Lock.initLocked(),
29 .available = 0,28 .available = 0,
30 .data = undefined,29 .data = undefined,
31 };30 };
...@@ -90,17 +89,11 @@ test "std.event.Future" {...@@ -90,17 +89,11 @@ test "std.event.Future" {
90 // TODO provide a way to run tests in evented I/O mode89 // TODO provide a way to run tests in evented I/O mode
91 if (!std.io.is_async) return error.SkipZigTest;90 if (!std.io.is_async) return error.SkipZigTest;
9291
93 var loop: Loop = undefined;92 const handle = async testFuture();
94 try loop.initMultiThreaded();
95 defer loop.deinit();
96
97 const handle = async testFuture(&loop);
98
99 loop.run();
100}93}
10194
102fn testFuture(loop: *Loop) void {95fn testFuture() void {
103 var future = Future(i32).init(loop);96 var future = Future(i32).init();
10497
105 var a = async waitOnFuture(&future);98 var a = async waitOnFuture(&future);
106 var b = async waitOnFuture(&future);99 var b = async waitOnFuture(&future);
lib/std/event/group.zig+11-15
...@@ -1,8 +1,8 @@...@@ -1,8 +1,8 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const Lock = std.event.Lock;3const Lock = std.event.Lock;
4const Loop = std.event.Loop;
5const testing = std.testing;4const testing = std.testing;
5const Allocator = std.mem.Allocator;
66
7/// ReturnType must be `void` or `E!void`7/// ReturnType must be `void` or `E!void`
8pub fn Group(comptime ReturnType: type) type {8pub fn Group(comptime ReturnType: type) type {
...@@ -10,6 +10,7 @@ pub fn Group(comptime ReturnType: type) type {...@@ -10,6 +10,7 @@ pub fn Group(comptime ReturnType: type) type {
10 frame_stack: Stack,10 frame_stack: Stack,
11 alloc_stack: Stack,11 alloc_stack: Stack,
12 lock: Lock,12 lock: Lock,
13 allocator: *Allocator,
1314
14 const Self = @This();15 const Self = @This();
1516
...@@ -19,17 +20,18 @@ pub fn Group(comptime ReturnType: type) type {...@@ -19,17 +20,18 @@ pub fn Group(comptime ReturnType: type) type {
19 };20 };
20 const Stack = std.atomic.Stack(anyframe->ReturnType);21 const Stack = std.atomic.Stack(anyframe->ReturnType);
2122
22 pub fn init(loop: *Loop) Self {23 pub fn init(allocator: *Allocator) Self {
23 return Self{24 return Self{
24 .frame_stack = Stack.init(),25 .frame_stack = Stack.init(),
25 .alloc_stack = Stack.init(),26 .alloc_stack = Stack.init(),
26 .lock = Lock.init(loop),27 .lock = Lock.init(),
28 .allocator = allocator,
27 };29 };
28 }30 }
2931
30 /// Add a frame to the group. Thread-safe.32 /// Add a frame to the group. Thread-safe.
31 pub fn add(self: *Self, handle: anyframe->ReturnType) (error{OutOfMemory}!void) {33 pub fn add(self: *Self, handle: anyframe->ReturnType) (error{OutOfMemory}!void) {
32 const node = try self.lock.loop.allocator.create(Stack.Node);34 const node = try self.allocator.create(Stack.Node);
33 node.* = Stack.Node{35 node.* = Stack.Node{
34 .next = undefined,36 .next = undefined,
35 .data = handle,37 .data = handle,
...@@ -66,7 +68,7 @@ pub fn Group(comptime ReturnType: type) type {...@@ -66,7 +68,7 @@ pub fn Group(comptime ReturnType: type) type {
66 }68 }
67 while (self.alloc_stack.pop()) |node| {69 while (self.alloc_stack.pop()) |node| {
68 const handle = node.data;70 const handle = node.data;
69 self.lock.loop.allocator.destroy(node);71 self.allocator.destroy(node);
70 if (Error == void) {72 if (Error == void) {
71 await handle;73 await handle;
72 } else {74 } else {
...@@ -87,18 +89,12 @@ test "std.event.Group" {...@@ -87,18 +89,12 @@ test "std.event.Group" {
87 // TODO provide a way to run tests in evented I/O mode89 // TODO provide a way to run tests in evented I/O mode
88 if (!std.io.is_async) return error.SkipZigTest;90 if (!std.io.is_async) return error.SkipZigTest;
8991
90 var loop: Loop = undefined;92 const handle = async testGroup(std.heap.direct_allocator);
91 try loop.initMultiThreaded();
92 defer loop.deinit();
93
94 const handle = async testGroup(&loop);
95
96 loop.run();
97}93}
9894
99async fn testGroup(loop: *Loop) void {95async fn testGroup(allocator: *Allocator) void {
100 var count: usize = 0;96 var count: usize = 0;
101 var group = Group(void).init(loop);97 var group = Group(void).init(allocator);
102 var sleep_a_little_frame = async sleepALittle(&count);98 var sleep_a_little_frame = async sleepALittle(&count);
103 group.add(&sleep_a_little_frame) catch @panic("memory");99 group.add(&sleep_a_little_frame) catch @panic("memory");
104 var increase_by_ten_frame = async increaseByTen(&count);100 var increase_by_ten_frame = async increaseByTen(&count);
...@@ -106,7 +102,7 @@ async fn testGroup(loop: *Loop) void {...@@ -106,7 +102,7 @@ async fn testGroup(loop: *Loop) void {
106 group.wait();102 group.wait();
107 testing.expect(count == 11);103 testing.expect(count == 11);
108104
109 var another = Group(anyerror!void).init(loop);105 var another = Group(anyerror!void).init(allocator);
110 var something_else_frame = async somethingElse();106 var something_else_frame = async somethingElse();
111 another.add(&something_else_frame) catch @panic("memory");107 another.add(&something_else_frame) catch @panic("memory");
112 var something_that_fails_frame = async doSomethingThatFails();108 var something_that_fails_frame = async doSomethingThatFails();
lib/std/event/lock.zig+13-18
...@@ -11,20 +11,22 @@ const Loop = std.event.Loop;...@@ -11,20 +11,22 @@ const Loop = std.event.Loop;
11/// Allows only one actor to hold the lock.11/// Allows only one actor to hold the lock.
12/// TODO: make this API also work in blocking I/O mode.12/// TODO: make this API also work in blocking I/O mode.
13pub const Lock = struct {13pub const Lock = struct {
14 loop: *Loop,
15 shared_bit: u8, // TODO make this a bool14 shared_bit: u8, // TODO make this a bool
16 queue: Queue,15 queue: Queue,
17 queue_empty_bit: u8, // TODO make this a bool16 queue_empty_bit: u8, // TODO make this a bool
1817
19 const Queue = std.atomic.Queue(anyframe);18 const Queue = std.atomic.Queue(anyframe);
2019
20 const global_event_loop = Loop.instance orelse
21 @compileError("std.event.Lock currently only works with event-based I/O");
22
21 pub const Held = struct {23 pub const Held = struct {
22 lock: *Lock,24 lock: *Lock,
2325
24 pub fn release(self: Held) void {26 pub fn release(self: Held) void {
25 // Resume the next item from the queue.27 // Resume the next item from the queue.
26 if (self.lock.queue.get()) |node| {28 if (self.lock.queue.get()) |node| {
27 self.lock.loop.onNextTick(node);29 global_event_loop.onNextTick(node);
28 return;30 return;
29 }31 }
3032
...@@ -49,7 +51,7 @@ pub const Lock = struct {...@@ -49,7 +51,7 @@ pub const Lock = struct {
4951
50 // Resume the next item from the queue.52 // Resume the next item from the queue.
51 if (self.lock.queue.get()) |node| {53 if (self.lock.queue.get()) |node| {
52 self.lock.loop.onNextTick(node);54 global_event_loop.onNextTick(node);
53 return;55 return;
54 }56 }
5557
...@@ -65,18 +67,16 @@ pub const Lock = struct {...@@ -65,18 +67,16 @@ pub const Lock = struct {
65 }67 }
66 };68 };
6769
68 pub fn init(loop: *Loop) Lock {70 pub fn init() Lock {
69 return Lock{71 return Lock{
70 .loop = loop,
71 .shared_bit = 0,72 .shared_bit = 0,
72 .queue = Queue.init(),73 .queue = Queue.init(),
73 .queue_empty_bit = 1,74 .queue_empty_bit = 1,
74 };75 };
75 }76 }
7677
77 pub fn initLocked(loop: *Loop) Lock {78 pub fn initLocked() Lock {
78 return Lock{79 return Lock{
79 .loop = loop,
80 .shared_bit = 1,80 .shared_bit = 1,
81 .queue = Queue.init(),81 .queue = Queue.init(),
82 .queue_empty_bit = 1,82 .queue_empty_bit = 1,
...@@ -126,27 +126,22 @@ test "std.event.Lock" {...@@ -126,27 +126,22 @@ test "std.event.Lock" {
126 // TODO provide a way to run tests in evented I/O mode126 // TODO provide a way to run tests in evented I/O mode
127 if (!std.io.is_async) return error.SkipZigTest;127 if (!std.io.is_async) return error.SkipZigTest;
128128
129 var loop: Loop = undefined;129 var lock = Lock.init();
130 try loop.initMultiThreaded();
131 defer loop.deinit();
132
133 var lock = Lock.init(&loop);
134 defer lock.deinit();130 defer lock.deinit();
135131
136 _ = async testLock(&loop, &lock);132 _ = async testLock(&lock);
137 loop.run();
138133
139 testing.expectEqualSlices(i32, [1]i32{3 * @intCast(i32, shared_test_data.len)} ** shared_test_data.len, shared_test_data);134 testing.expectEqualSlices(i32, [1]i32{3 * @intCast(i32, shared_test_data.len)} ** shared_test_data.len, shared_test_data);
140}135}
141136
142async fn testLock(loop: *Loop, lock: *Lock) void {137async fn testLock(lock: *Lock) void {
143 var handle1 = async lockRunner(lock);138 var handle1 = async lockRunner(lock);
144 var tick_node1 = Loop.NextTickNode{139 var tick_node1 = Loop.NextTickNode{
145 .prev = undefined,140 .prev = undefined,
146 .next = undefined,141 .next = undefined,
147 .data = &handle1,142 .data = &handle1,
148 };143 };
149 loop.onNextTick(&tick_node1);144 Loop.instance.?.onNextTick(&tick_node1);
150145
151 var handle2 = async lockRunner(lock);146 var handle2 = async lockRunner(lock);
152 var tick_node2 = Loop.NextTickNode{147 var tick_node2 = Loop.NextTickNode{
...@@ -154,7 +149,7 @@ async fn testLock(loop: *Loop, lock: *Lock) void {...@@ -154,7 +149,7 @@ async fn testLock(loop: *Loop, lock: *Lock) void {
154 .next = undefined,149 .next = undefined,
155 .data = &handle2,150 .data = &handle2,
156 };151 };
157 loop.onNextTick(&tick_node2);152 Loop.instance.?.onNextTick(&tick_node2);
158153
159 var handle3 = async lockRunner(lock);154 var handle3 = async lockRunner(lock);
160 var tick_node3 = Loop.NextTickNode{155 var tick_node3 = Loop.NextTickNode{
...@@ -162,7 +157,7 @@ async fn testLock(loop: *Loop, lock: *Lock) void {...@@ -162,7 +157,7 @@ async fn testLock(loop: *Loop, lock: *Lock) void {
162 .next = undefined,157 .next = undefined,
163 .data = &handle3,158 .data = &handle3,
164 };159 };
165 loop.onNextTick(&tick_node3);160 Loop.instance.?.onNextTick(&tick_node3);
166161
167 await handle1;162 await handle1;
168 await handle2;163 await handle2;
lib/std/event/locked.zig+3-4
...@@ -1,6 +1,5 @@...@@ -1,6 +1,5 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const Lock = std.event.Lock;2const Lock = std.event.Lock;
3const Loop = std.event.Loop;
43
5/// Thread-safe async/await lock that protects one piece of data.4/// Thread-safe async/await lock that protects one piece of data.
6/// Functions which are waiting for the lock are suspended, and5/// Functions which are waiting for the lock are suspended, and
...@@ -21,9 +20,9 @@ pub fn Locked(comptime T: type) type {...@@ -21,9 +20,9 @@ pub fn Locked(comptime T: type) type {
21 }20 }
22 };21 };
2322
24 pub fn init(loop: *Loop, data: T) Self {23 pub fn init(data: T) Self {
25 return Self{24 return Self{
26 .lock = Lock.init(loop),25 .lock = Lock.init(),
27 .private_data = data,26 .private_data = data,
28 };27 };
29 }28 }
...@@ -35,7 +34,7 @@ pub fn Locked(comptime T: type) type {...@@ -35,7 +34,7 @@ pub fn Locked(comptime T: type) type {
35 pub async fn acquire(self: *Self) HeldLock {34 pub async fn acquire(self: *Self) HeldLock {
36 return HeldLock{35 return HeldLock{
37 // TODO guaranteed allocation elision36 // TODO guaranteed allocation elision
38 .held = await (async self.lock.acquire() catch unreachable),37 .held = self.lock.acquire(),
39 .value = &self.private_data,38 .value = &self.private_data,
40 };39 };
41 }40 }
lib/std/event/rwlock.zig+19-23
...@@ -13,7 +13,6 @@ const Loop = std.event.Loop;...@@ -13,7 +13,6 @@ const Loop = std.event.Loop;
13/// When a write lock is held, it will not be released until the writer queue is empty.13/// When a write lock is held, it will not be released until the writer queue is empty.
14/// TODO: make this API also work in blocking I/O mode14/// TODO: make this API also work in blocking I/O mode
15pub const RwLock = struct {15pub const RwLock = struct {
16 loop: *Loop,
17 shared_state: u8, // TODO make this an enum16 shared_state: u8, // TODO make this an enum
18 writer_queue: Queue,17 writer_queue: Queue,
19 reader_queue: Queue,18 reader_queue: Queue,
...@@ -29,6 +28,9 @@ pub const RwLock = struct {...@@ -29,6 +28,9 @@ pub const RwLock = struct {
2928
30 const Queue = std.atomic.Queue(anyframe);29 const Queue = std.atomic.Queue(anyframe);
3130
31 const global_event_loop = Loop.instance orelse
32 @compileError("std.event.RwLock currently only works with event-based I/O");
33
32 pub const HeldRead = struct {34 pub const HeldRead = struct {
33 lock: *RwLock,35 lock: *RwLock,
3436
...@@ -55,7 +57,7 @@ pub const RwLock = struct {...@@ -55,7 +57,7 @@ pub const RwLock = struct {
55 // See if we can leave it locked for writing, and pass the lock to the next writer57 // See if we can leave it locked for writing, and pass the lock to the next writer
56 // in the queue to grab the lock.58 // in the queue to grab the lock.
57 if (self.lock.writer_queue.get()) |node| {59 if (self.lock.writer_queue.get()) |node| {
58 self.lock.loop.onNextTick(node);60 global_event_loop.onNextTick(node);
59 return;61 return;
60 }62 }
6163
...@@ -64,7 +66,7 @@ pub const RwLock = struct {...@@ -64,7 +66,7 @@ pub const RwLock = struct {
64 // Switch to a read lock.66 // Switch to a read lock.
65 _ = @atomicRmw(u8, &self.lock.shared_state, .Xchg, State.ReadLock, .SeqCst);67 _ = @atomicRmw(u8, &self.lock.shared_state, .Xchg, State.ReadLock, .SeqCst);
66 while (self.lock.reader_queue.get()) |node| {68 while (self.lock.reader_queue.get()) |node| {
67 self.lock.loop.onNextTick(node);69 global_event_loop.onNextTick(node);
68 }70 }
69 return;71 return;
70 }72 }
...@@ -76,9 +78,8 @@ pub const RwLock = struct {...@@ -76,9 +78,8 @@ pub const RwLock = struct {
76 }78 }
77 };79 };
7880
79 pub fn init(loop: *Loop) RwLock {81 pub fn init() RwLock {
80 return RwLock{82 return RwLock{
81 .loop = loop,
82 .shared_state = State.Unlocked,83 .shared_state = State.Unlocked,
83 .writer_queue = Queue.init(),84 .writer_queue = Queue.init(),
84 .writer_queue_empty_bit = 1,85 .writer_queue_empty_bit = 1,
...@@ -120,7 +121,7 @@ pub const RwLock = struct {...@@ -120,7 +121,7 @@ pub const RwLock = struct {
120 // Give out all the read locks.121 // Give out all the read locks.
121 if (self.reader_queue.get()) |first_node| {122 if (self.reader_queue.get()) |first_node| {
122 while (self.reader_queue.get()) |node| {123 while (self.reader_queue.get()) |node| {
123 self.loop.onNextTick(node);124 global_event_loop.onNextTick(node);
124 }125 }
125 resume first_node.data;126 resume first_node.data;
126 }127 }
...@@ -171,7 +172,7 @@ pub const RwLock = struct {...@@ -171,7 +172,7 @@ pub const RwLock = struct {
171 }172 }
172 // If there's an item in the writer queue, give them the lock, and we're done.173 // If there's an item in the writer queue, give them the lock, and we're done.
173 if (self.writer_queue.get()) |node| {174 if (self.writer_queue.get()) |node| {
174 self.loop.onNextTick(node);175 global_event_loop.onNextTick(node);
175 return;176 return;
176 }177 }
177 // Release the lock again.178 // Release the lock again.
...@@ -187,9 +188,9 @@ pub const RwLock = struct {...@@ -187,9 +188,9 @@ pub const RwLock = struct {
187 }188 }
188 // If there are any items in the reader queue, give out all the reader locks, and we're done.189 // If there are any items in the reader queue, give out all the reader locks, and we're done.
189 if (self.reader_queue.get()) |first_node| {190 if (self.reader_queue.get()) |first_node| {
190 self.loop.onNextTick(first_node);191 global_event_loop.onNextTick(first_node);
191 while (self.reader_queue.get()) |node| {192 while (self.reader_queue.get()) |node| {
192 self.loop.onNextTick(node);193 global_event_loop.onNextTick(node);
193 }194 }
194 return;195 return;
195 }196 }
...@@ -216,46 +217,41 @@ test "std.event.RwLock" {...@@ -216,46 +217,41 @@ test "std.event.RwLock" {
216 // TODO provide a way to run tests in evented I/O mode217 // TODO provide a way to run tests in evented I/O mode
217 if (!std.io.is_async) return error.SkipZigTest;218 if (!std.io.is_async) return error.SkipZigTest;
218219
219 var loop: Loop = undefined;220 var lock = RwLock.init();
220 try loop.initMultiThreaded();
221 defer loop.deinit();
222
223 var lock = RwLock.init(&loop);
224 defer lock.deinit();221 defer lock.deinit();
225222
226 const handle = testLock(&loop, &lock);223 const handle = testLock(std.heap.direct_allocator, &lock);
227 loop.run();
228224
229 const expected_result = [1]i32{shared_it_count * @intCast(i32, shared_test_data.len)} ** shared_test_data.len;225 const expected_result = [1]i32{shared_it_count * @intCast(i32, shared_test_data.len)} ** shared_test_data.len;
230 testing.expectEqualSlices(i32, expected_result, shared_test_data);226 testing.expectEqualSlices(i32, expected_result, shared_test_data);
231}227}
232228
233async fn testLock(loop: *Loop, lock: *RwLock) void {229async fn testLock(allocator: *Allocator, lock: *RwLock) void {
234 var read_nodes: [100]Loop.NextTickNode = undefined;230 var read_nodes: [100]Loop.NextTickNode = undefined;
235 for (read_nodes) |*read_node| {231 for (read_nodes) |*read_node| {
236 const frame = loop.allocator.create(@Frame(readRunner)) catch @panic("memory");232 const frame = allocator.create(@Frame(readRunner)) catch @panic("memory");
237 read_node.data = frame;233 read_node.data = frame;
238 frame.* = async readRunner(lock);234 frame.* = async readRunner(lock);
239 loop.onNextTick(read_node);235 Loop.instance.?.onNextTick(read_node);
240 }236 }
241237
242 var write_nodes: [shared_it_count]Loop.NextTickNode = undefined;238 var write_nodes: [shared_it_count]Loop.NextTickNode = undefined;
243 for (write_nodes) |*write_node| {239 for (write_nodes) |*write_node| {
244 const frame = loop.allocator.create(@Frame(writeRunner)) catch @panic("memory");240 const frame = allocator.create(@Frame(writeRunner)) catch @panic("memory");
245 write_node.data = frame;241 write_node.data = frame;
246 frame.* = async writeRunner(lock);242 frame.* = async writeRunner(lock);
247 loop.onNextTick(write_node);243 Loop.instance.?.onNextTick(write_node);
248 }244 }
249245
250 for (write_nodes) |*write_node| {246 for (write_nodes) |*write_node| {
251 const casted = @ptrCast(*const @Frame(writeRunner), write_node.data);247 const casted = @ptrCast(*const @Frame(writeRunner), write_node.data);
252 await casted;248 await casted;
253 loop.allocator.destroy(casted);249 allocator.destroy(casted);
254 }250 }
255 for (read_nodes) |*read_node| {251 for (read_nodes) |*read_node| {
256 const casted = @ptrCast(*const @Frame(readRunner), read_node.data);252 const casted = @ptrCast(*const @Frame(readRunner), read_node.data);
257 await casted;253 await casted;
258 loop.allocator.destroy(casted);254 allocator.destroy(casted);
259 }255 }
260}256}
261257
lib/std/event/rwlocked.zig+4-5
...@@ -1,6 +1,5 @@...@@ -1,6 +1,5 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const RwLock = std.event.RwLock;2const RwLock = std.event.RwLock;
3const Loop = std.event.Loop;
43
5/// Thread-safe async/await RW lock that protects one piece of data.4/// Thread-safe async/await RW lock that protects one piece of data.
6/// Functions which are waiting for the lock are suspended, and5/// Functions which are waiting for the lock are suspended, and
...@@ -30,9 +29,9 @@ pub fn RwLocked(comptime T: type) type {...@@ -30,9 +29,9 @@ pub fn RwLocked(comptime T: type) type {
30 }29 }
31 };30 };
3231
33 pub fn init(loop: *Loop, data: T) Self {32 pub fn init(data: T) Self {
34 return Self{33 return Self{
35 .lock = RwLock.init(loop),34 .lock = RwLock.init(),
36 .locked_data = data,35 .locked_data = data,
37 };36 };
38 }37 }
...@@ -43,14 +42,14 @@ pub fn RwLocked(comptime T: type) type {...@@ -43,14 +42,14 @@ pub fn RwLocked(comptime T: type) type {
4342
44 pub async fn acquireRead(self: *Self) HeldReadLock {43 pub async fn acquireRead(self: *Self) HeldReadLock {
45 return HeldReadLock{44 return HeldReadLock{
46 .held = await (async self.lock.acquireRead() catch unreachable),45 .held = self.lock.acquireRead(),
47 .value = &self.locked_data,46 .value = &self.locked_data,
48 };47 };
49 }48 }
5049
51 pub async fn acquireWrite(self: *Self) HeldWriteLock {50 pub async fn acquireWrite(self: *Self) HeldWriteLock {
52 return HeldWriteLock{51 return HeldWriteLock{
53 .held = await (async self.lock.acquireWrite() catch unreachable),52 .held = self.lock.acquireWrite(),
54 .value = &self.locked_data,53 .value = &self.locked_data,
55 };54 };
56 }55 }