From 19459840fe0a1dcc39a4552a430a70fbf39b52ea Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 21 Dec 2020 16:42:53 -0700 Subject: std.ResetEvent: pthreads sem_t cannot be statically initialized because it is allowed for the implementation to use a file descriptor, which would require making a syscall at runtime. --- lib/std/reset_event.zig | 51 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 9 deletions(-) (limited to 'lib/std/reset_event.zig') diff --git a/lib/std/reset_event.zig b/lib/std/reset_event.zig index f0655e4e6a..cdbad71c75 100644 --- a/lib/std/reset_event.zig +++ b/lib/std/reset_event.zig @@ -101,30 +101,48 @@ const DebugEvent = struct { }; const PosixEvent = struct { - sem: c.sem_t, + sem: c.sem_t = undefined, + /// Sadly this is needed because pthreads semaphore API does not + /// support static initialization. + init_mutex: std.mutex.PthreadMutex = .{}, + state: enum { uninit, init } = .uninit, fn init() PosixEvent { - return PosixEvent{ - .sem = c.sem_t.init(0, 0), - }; + return .{}; } + /// Not thread-safe. fn deinit(self: *PosixEvent) void { - assert(c.sem_destroy(&self.sem) == 0); + switch (self.state) { + .uninit => {}, + .init => { + assert(c.sem_destroy(&self.sem) == 0); + }, + } + self.* = undefined; } fn reset(self: *PosixEvent) void { - self.deinit(); - assert(c.sem_init(&self.sem, 0, 0) == 0); + const sem = self.getInitializedSem(); + while (true) { + switch (c.getErrno(c.sem_trywait(sem))) { + 0 => continue, // Need to make it go to zero. + c.EINTR => continue, + c.EINVAL => unreachable, + c.EAGAIN => return, // The semaphore currently has the value zero. + else => unreachable, + } + } } fn set(self: *PosixEvent) void { - assert(c.sem_post(&self.sem) == 0); + assert(c.sem_post(self.getInitializedSem()) == 0); } fn wait(self: *PosixEvent) void { + const sem = self.getInitializedSem(); while (true) { - switch (c.getErrno(c.sem_wait(&self.sem))) { + switch (c.getErrno(c.sem_wait(sem))) { 0 => return, c.EINTR => continue, c.EINVAL => unreachable, @@ -148,6 +166,7 @@ const PosixEvent = struct { } ts.tv_sec = @intCast(@TypeOf(ts.tv_sec), @divFloor(timeout_abs, time.ns_per_s)); ts.tv_nsec = @intCast(@TypeOf(ts.tv_nsec), @mod(timeout_abs, time.ns_per_s)); + const sem = self.getInitializedSem(); while (true) { switch (c.getErrno(c.sem_timedwait(&self.sem, &ts))) { 0 => return, @@ -158,6 +177,20 @@ const PosixEvent = struct { } } } + + fn getInitializedSem(self: *PosixEvent) *c.sem_t { + const held = self.init_mutex.acquire(); + defer held.release(); + + switch (self.state) { + .init => return &self.sem, + .uninit => { + self.state = .init; + assert(c.sem_init(&self.sem, 0, 0) == 0); + return &self.sem; + }, + } + } }; const AtomicEvent = struct { -- cgit v1.2.3