authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-12-21 16:42:53-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-12-23 13:36:21-08:00
log19459840fe0a1dcc39a4552a430a70fbf39b52ea
tree78aa73531c5aab5ad1d6fc3482a12966bb9c3398
parent028af97df46f1b856047cc146739cc5066e65bab

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.

2 files changed, 47 insertions(+), 41 deletions(-)

lib/std/c/linux.zig+5-32
......@@ -123,6 +123,10 @@ pub const pthread_mutex_t = extern struct {
123123pub const pthread_cond_t = extern struct {
124124 size: [__SIZEOF_PTHREAD_COND_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_COND_T,
125125};
126pub const sem_t = extern struct {
127 __size: [__SIZEOF_SEM_T]u8 align(@alignOf(usize)),
128};
129
126130const __SIZEOF_PTHREAD_COND_T = 48;
127131const __SIZEOF_PTHREAD_MUTEX_T = if (builtin.os.tag == .fuchsia) 40 else switch (builtin.abi) {
128132 .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
134138 },
135139 else => unreachable,
136140};
137
138pub const sem_t = switch (builtin.abi) {
139 .musl, .musleabi, .musleabihf => extern struct {
140 __val: [4 * @sizeOf(c_long) / @sizeOf(c_int)]c_int,
141
142 pub fn init(pshared: c_int, value: c_uint) @This() {
143 var result: @This() = undefined;
144 result.__val[0] = @bitCast(c_int, value);
145 result.__val[1] = 0;
146 result.__val[2] = if (pshared != 0) 0 else 128;
147 return result;
148 }
149 },
150 .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => extern struct {
151 __lock: c_int,
152 __queue: ?*pthread_t,
153 __pshared: c_int,
154 __value: c_int,
155 __data: ?*c_void,
156
157 pub fn init(pshared: c_int, value: c_uint) @This() {
158 return .{
159 .__lock = 0,
160 .__queue = null,
161 .__pshared = pshared,
162 .__value = @bitCast(c_int, value),
163 .__data = null,
164 };
165 }
166 },
167 else => unreachable,
168};
141const __SIZEOF_SEM_T = 4 * @sizeOf(usize);
169142
170143pub const RTLD_LAZY = 1;
171144pub const RTLD_NOW = 2;
lib/std/reset_event.zig+42-9
......@@ -101,30 +101,48 @@ const DebugEvent = struct {
101101};
102102
103103const PosixEvent = struct {
104 sem: c.sem_t,
104 sem: c.sem_t = undefined,
105 /// Sadly this is needed because pthreads semaphore API does not
106 /// support static initialization.
107 init_mutex: std.mutex.PthreadMutex = .{},
108 state: enum { uninit, init } = .uninit,
105109
106110 fn init() PosixEvent {
107 return PosixEvent{
108 .sem = c.sem_t.init(0, 0),
109 };
111 return .{};
110112 }
111113
114 /// Not thread-safe.
112115 fn deinit(self: *PosixEvent) void {
113 assert(c.sem_destroy(&self.sem) == 0);
116 switch (self.state) {
117 .uninit => {},
118 .init => {
119 assert(c.sem_destroy(&self.sem) == 0);
120 },
121 }
122 self.* = undefined;
114123 }
115124
116125 fn reset(self: *PosixEvent) void {
117 self.deinit();
118 assert(c.sem_init(&self.sem, 0, 0) == 0);
126 const sem = self.getInitializedSem();
127 while (true) {
128 switch (c.getErrno(c.sem_trywait(sem))) {
129 0 => continue, // Need to make it go to zero.
130 c.EINTR => continue,
131 c.EINVAL => unreachable,
132 c.EAGAIN => return, // The semaphore currently has the value zero.
133 else => unreachable,
134 }
135 }
119136 }
120137
121138 fn set(self: *PosixEvent) void {
122 assert(c.sem_post(&self.sem) == 0);
139 assert(c.sem_post(self.getInitializedSem()) == 0);
123140 }
124141
125142 fn wait(self: *PosixEvent) void {
143 const sem = self.getInitializedSem();
126144 while (true) {
127 switch (c.getErrno(c.sem_wait(&self.sem))) {
145 switch (c.getErrno(c.sem_wait(sem))) {
128146 0 => return,
129147 c.EINTR => continue,
130148 c.EINVAL => unreachable,
......@@ -148,6 +166,7 @@ const PosixEvent = struct {
148166 }
149167 ts.tv_sec = @intCast(@TypeOf(ts.tv_sec), @divFloor(timeout_abs, time.ns_per_s));
150168 ts.tv_nsec = @intCast(@TypeOf(ts.tv_nsec), @mod(timeout_abs, time.ns_per_s));
169 const sem = self.getInitializedSem();
151170 while (true) {
152171 switch (c.getErrno(c.sem_timedwait(&self.sem, &ts))) {
153172 0 => return,
......@@ -158,6 +177,20 @@ const PosixEvent = struct {
158177 }
159178 }
160179 }
180
181 fn getInitializedSem(self: *PosixEvent) *c.sem_t {
182 const held = self.init_mutex.acquire();
183 defer held.release();
184
185 switch (self.state) {
186 .init => return &self.sem,
187 .uninit => {
188 self.state = .init;
189 assert(c.sem_init(&self.sem, 0, 0) == 0);
190 return &self.sem;
191 },
192 }
193 }
161194};
162195
163196const AtomicEvent = struct {