authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-04-26 13:11:35-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-04-27 08:24:32-07:00
log8c52c6ec6c4d6648ae4e2f11dd620d95599f4039
treec97b4764565825488e89d7d52af383194c58c6d1
parent131b328c10abde0193c13073b5ab82f0031fb121

std: prevent the possibility of deadlocks in some threaded tests


1 files changed, 20 insertions(+), 3 deletions(-)

lib/std/Thread/Condition.zig+20-3
...@@ -330,10 +330,12 @@ test "Condition - wait and signal" {...@@ -330,10 +330,12 @@ test "Condition - wait and signal" {
330 mutex: Mutex = .{},330 mutex: Mutex = .{},
331 cond: Condition = .{},331 cond: Condition = .{},
332 threads: [num_threads]std.Thread = undefined,332 threads: [num_threads]std.Thread = undefined,
333 spawn_count: std.math.IntFittingRange(0, num_threads) = 0,
333334
334 fn run(self: *@This()) void {335 fn run(self: *@This()) void {
335 self.mutex.lock();336 self.mutex.lock();
336 defer self.mutex.unlock();337 defer self.mutex.unlock();
338 self.spawn_count += 1;
337339
338 self.cond.wait(&self.mutex);340 self.cond.wait(&self.mutex);
339 self.cond.timedWait(&self.mutex, std.time.ns_per_ms) catch {};341 self.cond.timedWait(&self.mutex, std.time.ns_per_ms) catch {};
...@@ -346,7 +348,14 @@ test "Condition - wait and signal" {...@@ -346,7 +348,14 @@ test "Condition - wait and signal" {
346 t.* = try std.Thread.spawn(.{}, MultiWait.run, .{&multi_wait});348 t.* = try std.Thread.spawn(.{}, MultiWait.run, .{&multi_wait});
347 }349 }
348350
349 std.time.sleep(100 * std.time.ns_per_ms);351 while (true) {
352 std.time.sleep(100 * std.time.ns_per_ms);
353
354 multi_wait.mutex.lock();
355 defer multi_wait.mutex.unlock();
356 // Make sure all of the threads have finished spawning to avoid a deadlock.
357 if (multi_wait.spawn_count == num_threads) break;
358 }
350359
351 multi_wait.cond.signal();360 multi_wait.cond.signal();
352 for (multi_wait.threads) |t| {361 for (multi_wait.threads) |t| {
...@@ -367,10 +376,12 @@ test "Condition - signal" {...@@ -367,10 +376,12 @@ test "Condition - signal" {
367 cond: Condition = .{},376 cond: Condition = .{},
368 notified: bool = false,377 notified: bool = false,
369 threads: [num_threads]std.Thread = undefined,378 threads: [num_threads]std.Thread = undefined,
379 spawn_count: std.math.IntFittingRange(0, num_threads) = 0,
370380
371 fn run(self: *@This()) void {381 fn run(self: *@This()) void {
372 self.mutex.lock();382 self.mutex.lock();
373 defer self.mutex.unlock();383 defer self.mutex.unlock();
384 self.spawn_count += 1;
374385
375 // Use timedWait() a few times before using wait()386 // Use timedWait() a few times before using wait()
376 // to test multiple threads timing out frequently.387 // to test multiple threads timing out frequently.
...@@ -394,10 +405,16 @@ test "Condition - signal" {...@@ -394,10 +405,16 @@ test "Condition - signal" {
394 t.* = try std.Thread.spawn(.{}, SignalTest.run, .{&signal_test});405 t.* = try std.Thread.spawn(.{}, SignalTest.run, .{&signal_test});
395 }406 }
396407
397 {408 while (true) {
398 // Wait for a bit in hopes that the spawned threads start queuing up on the condvar
399 std.time.sleep(10 * std.time.ns_per_ms);409 std.time.sleep(10 * std.time.ns_per_ms);
400410
411 signal_test.mutex.lock();
412 defer signal_test.mutex.unlock();
413 // Make sure at least one thread has finished spawning to avoid testing nothing.
414 if (signal_test.spawn_count > 0) break;
415 }
416
417 {
401 // Wake up one of them (outside the lock) after setting notified=true.418 // Wake up one of them (outside the lock) after setting notified=true.
402 defer signal_test.cond.signal();419 defer signal_test.cond.signal();
403420