| ... | ... | @@ -604,82 +604,3 @@ test "Condition - broadcasting - wake all threads" { |
| 604 | 604 | } |
| 605 | 605 | } |
| 606 | 606 | } |
| 607 | | |
| 608 | | test "Condition - signal wakes one" { |
| 609 | | // This test requires spawning threads |
| 610 | | if (builtin.single_threaded) { |
| 611 | | return error.SkipZigTest; |
| 612 | | } |
| 613 | | |
| 614 | | if (builtin.os.tag == .windows) { |
| 615 | | // https://github.com/ziglang/zig/issues/13660 |
| 616 | | return error.SkipZigTest; |
| 617 | | } |
| 618 | | |
| 619 | | var num_runs: usize = 1; |
| 620 | | const num_threads = 3; |
| 621 | | const timeoutDelay = 10 * std.time.ns_per_ms; |
| 622 | | |
| 623 | | while (num_runs > 0) : (num_runs -= 1) { |
| 624 | | |
| 625 | | // Start multiple runner threads, wait for them to start and send the signal |
| 626 | | // then. Expect that one thread wake up and all other times out. |
| 627 | | // |
| 628 | | // Test depends on delay in timedWait! If too small all threads can timeout |
| 629 | | // before any one gets wake up. |
| 630 | | |
| 631 | | const Runner = struct { |
| 632 | | mutex: Mutex = .{}, |
| 633 | | cond: Condition = .{}, |
| 634 | | completed: Condition = .{}, |
| 635 | | count: usize = 0, |
| 636 | | threads: [num_threads]std.Thread = undefined, |
| 637 | | wakeups: usize = 0, |
| 638 | | timeouts: usize = 0, |
| 639 | | |
| 640 | | fn run(self: *@This()) void { |
| 641 | | self.mutex.lock(); |
| 642 | | defer self.mutex.unlock(); |
| 643 | | |
| 644 | | // The last started thread tells the main test thread it's completed. |
| 645 | | self.count += 1; |
| 646 | | if (self.count == num_threads) { |
| 647 | | self.completed.signal(); |
| 648 | | } |
| 649 | | |
| 650 | | self.cond.timedWait(&self.mutex, timeoutDelay) catch { |
| 651 | | self.timeouts += 1; |
| 652 | | return; |
| 653 | | }; |
| 654 | | self.wakeups += 1; |
| 655 | | } |
| 656 | | }; |
| 657 | | |
| 658 | | // Start threads |
| 659 | | var runner = Runner{}; |
| 660 | | for (runner.threads) |*t| { |
| 661 | | t.* = try std.Thread.spawn(.{}, Runner.run, .{&runner}); |
| 662 | | } |
| 663 | | |
| 664 | | { |
| 665 | | runner.mutex.lock(); |
| 666 | | defer runner.mutex.unlock(); |
| 667 | | |
| 668 | | // Wait for all the threads to spawn. |
| 669 | | // timedWait() to detect any potential deadlocks. |
| 670 | | while (runner.count != num_threads) { |
| 671 | | try runner.completed.timedWait(&runner.mutex, 1 * std.time.ns_per_s); |
| 672 | | } |
| 673 | | // Signal one thread, the others should get timeout. |
| 674 | | runner.cond.signal(); |
| 675 | | } |
| 676 | | |
| 677 | | for (runner.threads) |t| { |
| 678 | | t.join(); |
| 679 | | } |
| 680 | | |
| 681 | | // Expect that only one got singal |
| 682 | | try std.testing.expectEqual(runner.wakeups, 1); |
| 683 | | try std.testing.expectEqual(runner.timeouts, num_threads - 1); |
| 684 | | } |
| 685 | | } |