authorgravatar for kbutcher6200@gmail.comkprotty <kbutcher6200@gmail.com> 2021-06-26 09:03:53-05:00
committergravatar for kbutcher6200@gmail.comkprotty <kbutcher6200@gmail.com> 2021-06-30 21:49:00-05:00
logfd4a607bb2f1a1cbf8b8c1fd5d35f5f775e79114
tree65a2b16c47c2784562d3a93eeefdcc04e883b88c
parent18bcb2e990853f3e32cb0d72beb962390c9e8714

std.Thread: fix futex test + thread errors


2 files changed, 90 insertions(+), 98 deletions(-)

lib/std/Thread.zig+2
...@@ -385,6 +385,7 @@ const PosixThreadImpl = struct {...@@ -385,6 +385,7 @@ const PosixThreadImpl = struct {
385 };385 };
386386
387 const args_ptr = try allocator.create(Args);387 const args_ptr = try allocator.create(Args);
388 args_ptr.* = args;
388 errdefer allocator.destroy(args_ptr);389 errdefer allocator.destroy(args_ptr);
389390
390 var attr: c.pthread_attr_t = undefined;391 var attr: c.pthread_attr_t = undefined;
...@@ -523,6 +524,7 @@ const LinuxThreadImpl = struct {...@@ -523,6 +524,7 @@ const LinuxThreadImpl = struct {
523 error.PermissionDenied => unreachable,524 error.PermissionDenied => unreachable,
524 else => |e| return e,525 else => |e| return e,
525 };526 };
527 assert(mapped.len >= map_bytes);
526 errdefer os.munmap(mapped);528 errdefer os.munmap(mapped);
527529
528 // map everything but the guard page as read/write530 // map everything but the guard page as read/write
lib/std/Thread/Futex.zig+88-98
...@@ -391,70 +391,74 @@ test "Futex - wait/wake" {...@@ -391,70 +391,74 @@ test "Futex - wait/wake" {
391}391}
392392
393test "Futex - Signal" {393test "Futex - Signal" {
394 if (!single_threaded) {394 if (single_threaded) {
395 return;395 return;
396 }396 }
397397
398 try (struct {398 const Paddle = struct {
399 value: Atomic(u32) = Atomic(u32).init(0),399 value: Atomic(u32) = Atomic(u32).init(0),
400 current: u32 = 0,
400401
401 const Self = @This();402 fn run(self: *@This(), hit_to: *@This()) !void {
402403 var iterations: usize = 4;
403 fn send(self: *Self, value: u32) void {404 while (iterations > 0) : (iterations -= 1) {
404 self.value.store(value, .Release);
405 Futex.wake(&self.value, 1);
406 }
407
408 fn recv(self: *Self, expected: u32) void {
409 while (true) {
410 const value = self.value.load(.Acquire);
411 if (value == expected) break;
412 Futex.wait(&self.value, value, null) catch unreachable;
413 }
414 }
415405
416 const start_value = 1;406 var value: u32 = undefined;
407 while (true) {
408 value = self.value.load(.Acquire);
409 if (value != self.current) break;
410 Futex.wait(&self.value, self.current, null) catch unreachable;
411 }
417412
418 fn runThread(rx: *Self, tx: *Self) void {413 try testing.expectEqual(value, self.current + 1);
419 var iterations: u32 = start_value;414 self.current = value;
420 while (iterations < 10) : (iterations += 1) {415
421 rx.recv(iterations);416 _ = hit_to.value.fetchAdd(1, .Release);
422 tx.send(iterations);417 Futex.wake(&hit_to.value, 1);
423 }418 }
424 }419 }
420 };
425421
426 fn run() !void {422 var ping = Paddle{};
427 var ping = Self{};423 var pong = Paddle{};
428 var pong = Self{};
429424
430 const t1 = try std.Thread.spawn(.{}, runThread, .{ &ping, &pong });425 const t1 = try std.Thread.spawn(.{}, Paddle.run, .{&ping, &pong});
431 defer t1.join();426 defer t1.join();
432427
433 const t2 = try std.Thread.spawn(.{}, runThread, .{ &pong, &ping });428 const t2 = try std.Thread.spawn(.{}, Paddle.run, .{&pong, &ping});
434 defer t2.join();429 defer t2.join();
435430
436 ping.send(start_value);431 _ = ping.value.fetchAdd(1, .Release);
437 }432 Futex.wake(&ping.value, 1);
438 }).run();
439}433}
440434
441test "Futex - Broadcast" {435test "Futex - Broadcast" {
442 if (!single_threaded) {436 if (single_threaded) {
443 return;437 return;
444 }438 }
445439
446 try (struct {440 const Context = struct {
447 threads: [10]std.Thread = undefined,441 threads: [4]std.Thread = undefined,
448 broadcast: Atomic(u32) = Atomic(u32).init(0),442 broadcast: Atomic(u32) = Atomic(u32).init(0),
449 notified: Atomic(usize) = Atomic(usize).init(0),443 notified: Atomic(usize) = Atomic(usize).init(0),
450444
451 const Self = @This();
452
453 const BROADCAST_EMPTY = 0;445 const BROADCAST_EMPTY = 0;
454 const BROADCAST_SENT = 1;446 const BROADCAST_SENT = 1;
455 const BROADCAST_RECEIVED = 2;447 const BROADCAST_RECEIVED = 2;
456448
457 fn runReceiver(self: *Self) void {449 fn runSender(self: *@This()) !void {
450 self.broadcast.store(BROADCAST_SENT, .Monotonic);
451 Futex.wake(&self.broadcast, @intCast(u32, self.threads.len));
452
453 while (true) {
454 const broadcast = self.broadcast.load(.Acquire);
455 if (broadcast == BROADCAST_RECEIVED) break;
456 try testing.expectEqual(broadcast, BROADCAST_SENT);
457 Futex.wait(&self.broadcast, broadcast, null) catch unreachable;
458 }
459 }
460
461 fn runReceiver(self: *@This()) void {
458 while (true) {462 while (true) {
459 const broadcast = self.broadcast.load(.Acquire);463 const broadcast = self.broadcast.load(.Acquire);
460 if (broadcast == BROADCAST_SENT) break;464 if (broadcast == BROADCAST_SENT) break;
...@@ -468,66 +472,55 @@ test "Futex - Broadcast" {...@@ -468,66 +472,55 @@ test "Futex - Broadcast" {
468 Futex.wake(&self.broadcast, 1);472 Futex.wake(&self.broadcast, 1);
469 }473 }
470 }474 }
475 };
471476
472 fn run() !void {477 var ctx = Context{};
473 var self = Self{};478 for (ctx.threads) |*thread|
474479 thread.* = try std.Thread.spawn(.{}, Context.runReceiver, .{&ctx});
475 for (self.threads) |*thread|480 defer for (ctx.threads) |thread|
476 thread.* = try std.Thread.spawn(runReceiver, &self);481 thread.join();
477 defer for (self.threads) |thread|
478 thread.join();
479482
480 std.time.sleep(16 * std.time.ns_per_ms);483 // Try to wait for the threads to start before running runSender().
481 self.broadcast.store(BROADCAST_SENT, .Monotonic);484 // NOTE: not actually needed for correctness.
482 Futex.wake(&self.broadcast, @intCast(u32, self.threads.len));485 std.time.sleep(16 * std.time.ns_per_ms);
486 try ctx.runSender();
483487
484 while (true) {488 const notified = ctx.notified.load(.Monotonic);
485 const broadcast = self.broadcast.load(.Acquire);489 try testing.expectEqual(notified, ctx.threads.len);
486 if (broadcast == BROADCAST_RECEIVED) break;
487 try testing.expectEqual(broadcast, BROADCAST_SENT);
488 Futex.wait(&self.broadcast, broadcast, null) catch unreachable;
489 }
490
491 const notified = self.notified.load(.Monotonic);
492 try testing.expectEqual(notified, self.threads.len);
493 }
494 }).run();
495}490}
496491
497test "Futex - Chain" {492test "Futex - Chain" {
498 if (!single_threaded) {493 if (single_threaded) {
499 return;494 return;
500 }495 }
501496
502 try (struct {497 const Signal = struct {
503 completed: Signal = .{},498 value: Atomic(u32) = Atomic(u32).init(0),
504 threads: [10]struct {
505 thread: std.Thread,
506 signal: Signal,
507 } = undefined,
508
509 const Signal = struct {
510 state: Atomic(u32) = Atomic(u32).init(0),
511499
512 fn wait(self: *Signal) void {500 fn wait(self: *@This()) void {
513 while (true) {501 while (true) {
514 const value = self.value.load(.Acquire);502 const value = self.value.load(.Acquire);
515 if (value == 1) break;503 if (value == 1) break;
516 assert(value == 0);504 assert(value == 0);
517 Futex.wait(&self.value, 0, null) catch unreachable;505 Futex.wait(&self.value, 0, null) catch unreachable;
518 }
519 }506 }
507 }
520508
521 fn notify(self: *Signal) void {509 fn notify(self: *@This()) void {
522 assert(self.value.load(.Unordered) == 0);510 assert(self.value.load(.Unordered) == 0);
523 self.value.store(1, .Release);511 self.value.store(1, .Release);
524 Futex.wake(&self.value, 1);512 Futex.wake(&self.value, 1);
525 }513 }
526 };514 };
527515
528 const Self = @This();516 const Context = struct {
517 completed: Signal = .{},
518 threads: [4]struct {
519 thread: std.Thread,
520 signal: Signal,
521 } = undefined,
529522
530 fn runThread(self: *Self, index: usize) void {523 fn run(self: *@This(), index: usize) void {
531 const this_signal = &self.threads[index].signal;524 const this_signal = &self.threads[index].signal;
532525
533 var next_signal = &self.completed;526 var next_signal = &self.completed;
...@@ -538,21 +531,18 @@ test "Futex - Chain" {...@@ -538,21 +531,18 @@ test "Futex - Chain" {
538 this_signal.wait();531 this_signal.wait();
539 next_signal.notify();532 next_signal.notify();
540 }533 }
534 };
541535
542 fn run() !void {536 var ctx = Context{};
543 var self = Self{};537 for (ctx.threads) |*entry, index| {
544538 entry.signal = .{};
545 for (self.threads) |*entry, index| {539 entry.thread = try std.Thread.spawn(.{}, Context.run, .{&ctx, index});
546 entry.signal = .{};540 }
547 entry.thread = try std.Thread.spawn(.{}, runThread, .{&self, index});
548 }
549541
550 self.threads[0].signal.notify();542 ctx.threads[0].signal.notify();
551 self.completed.wait();543 ctx.completed.wait();
552544
553 for (self.threads) |entry| {545 for (ctx.threads) |entry| {
554 entry.thread.join();546 entry.thread.join();
555 }547 }
556 }
557 }).run();
558}548}