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.
This commit is contained in:
Andrew Kelley 2020-12-21 16:42:53 -07:00
parent 028af97df4
commit 19459840fe
2 changed files with 47 additions and 41 deletions

View File

@ -123,6 +123,10 @@ pub const pthread_mutex_t = extern struct {
pub const pthread_cond_t = extern struct {
size: [__SIZEOF_PTHREAD_COND_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_COND_T,
};
pub const sem_t = extern struct {
__size: [__SIZEOF_SEM_T]u8 align(@alignOf(usize)),
};
const __SIZEOF_PTHREAD_COND_T = 48;
const __SIZEOF_PTHREAD_MUTEX_T = if (builtin.os.tag == .fuchsia) 40 else switch (builtin.abi) {
.musl, .musleabi, .musleabihf => if (@sizeOf(usize) == 8) 40 else 24,
@ -134,38 +138,7 @@ const __SIZEOF_PTHREAD_MUTEX_T = if (builtin.os.tag == .fuchsia) 40 else switch
},
else => unreachable,
};
pub const sem_t = switch (builtin.abi) {
.musl, .musleabi, .musleabihf => extern struct {
__val: [4 * @sizeOf(c_long) / @sizeOf(c_int)]c_int,
pub fn init(pshared: c_int, value: c_uint) @This() {
var result: @This() = undefined;
result.__val[0] = @bitCast(c_int, value);
result.__val[1] = 0;
result.__val[2] = if (pshared != 0) 0 else 128;
return result;
}
},
.gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => extern struct {
__lock: c_int,
__queue: ?*pthread_t,
__pshared: c_int,
__value: c_int,
__data: ?*c_void,
pub fn init(pshared: c_int, value: c_uint) @This() {
return .{
.__lock = 0,
.__queue = null,
.__pshared = pshared,
.__value = @bitCast(c_int, value),
.__data = null,
};
}
},
else => unreachable,
};
const __SIZEOF_SEM_T = 4 * @sizeOf(usize);
pub const RTLD_LAZY = 1;
pub const RTLD_NOW = 2;

View File

@ -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 {