@zigc/lib 0.17.0-dev.44 → 0.17.0-dev.76

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1943,10 +1943,6 @@ pub fn io(t: *Threaded) Io {
1943
1943
  .windows => netShutdownWindows,
1944
1944
  else => netShutdownPosix,
1945
1945
  },
1946
- .netRead = switch (native_os) {
1947
- .windows => netReadWindows,
1948
- else => netReadPosix,
1949
- },
1950
1946
  .netWrite = switch (native_os) {
1951
1947
  .windows => netWriteWindows,
1952
1948
  else => netWritePosix,
@@ -2009,7 +2005,7 @@ const have_waitid = switch (native_os) {
2009
2005
 
2010
2006
  const have_wait4 = switch (native_os) {
2011
2007
  .linux => @hasField(std.os.linux.SYS, "wait4"),
2012
- .dragonfly, .freebsd, .netbsd, .openbsd, .illumos, .serenity, .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => true,
2008
+ .dragonfly, .freebsd, .netbsd, .openbsd, .illumos, .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => true,
2013
2009
  else => false,
2014
2010
  };
2015
2011
 
@@ -2566,6 +2562,12 @@ fn operate(userdata: ?*anyopaque, operation: Io.Operation) Io.Cancelable!Io.Oper
2566
2562
  };
2567
2563
  break :o .{ null, 1 };
2568
2564
  } },
2565
+ .net_read => |o| return .{
2566
+ .net_read = netRead(o.socket_handle, o.data) catch |err| switch (err) {
2567
+ error.Canceled => |e| return e,
2568
+ else => |e| e,
2569
+ },
2570
+ },
2569
2571
  }
2570
2572
  }
2571
2573
 
@@ -2621,6 +2623,14 @@ fn batchAwaitAsync(userdata: ?*anyopaque, b: *Io.Batch) Io.Cancelable!void {
2621
2623
  };
2622
2624
  poll_len += 1;
2623
2625
  },
2626
+ .net_read => |o| {
2627
+ poll_buffer[poll_len] = .{
2628
+ .fd = o.socket_handle,
2629
+ .events = posix.POLL.IN | posix.POLL.ERR,
2630
+ .revents = 0,
2631
+ };
2632
+ poll_len += 1;
2633
+ },
2624
2634
  }
2625
2635
  index = submission.node.next;
2626
2636
  }
@@ -2798,6 +2808,7 @@ fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout
2798
2808
  storage.* = .{ .completion = .{ .node = .{ .next = .none }, .result = result } };
2799
2809
  b.completed.tail = index;
2800
2810
  },
2811
+ .net_read => |o| try poll_storage.add(o.socket_handle, posix.POLL.IN | posix.POLL.ERR),
2801
2812
  }
2802
2813
  index = submission.node.next;
2803
2814
  }
@@ -2993,6 +3004,7 @@ fn batchApc(
2993
3004
  .file_write_streaming => .{ .file_write_streaming = ntWriteFileResult(iosb) },
2994
3005
  .device_io_control => .{ .device_io_control = iosb.* },
2995
3006
  .net_receive => unreachable,
3007
+ .net_read => unreachable,
2996
3008
  };
2997
3009
  storage.* = .{ .completion = .{ .node = .{ .next = .none }, .result = result } };
2998
3010
  },
@@ -3201,6 +3213,16 @@ fn batchDrainSubmittedWindows(t: *Threaded, b: *Io.Batch, concurrency: bool) (Io
3201
3213
  .net_receive = netReceiveWindows(t, o.socket_handle, o.message_buffer, o.data_buffer, o.flags),
3202
3214
  });
3203
3215
  },
3216
+ .net_read => |*o| {
3217
+ // TODO integrate with overlapped I/O or equivalent to avoid this error
3218
+ if (concurrency) return error.ConcurrencyUnavailable;
3219
+ batchCompleteBlockingWindows(b, operation_userdata, .{
3220
+ .net_read = netRead(o.socket_handle, o.data) catch |err| switch (err) {
3221
+ error.Canceled => |e| return e,
3222
+ else => |e| e,
3223
+ },
3224
+ });
3225
+ },
3204
3226
  }
3205
3227
  index = submission.node.next;
3206
3228
  }
@@ -5345,7 +5367,7 @@ fn dirOpenDirHaiku(
5345
5367
  .NOMEM => return error.SystemResources,
5346
5368
  .NOTDIR => return error.NotDir,
5347
5369
  .PERM => return error.PermissionDenied,
5348
- .BUSY => return error.DeviceBusy,
5370
+ .BUSY => |err| return errnoBug(err),
5349
5371
  else => |err| return posix.unexpectedErrno(err),
5350
5372
  }
5351
5373
  },
@@ -5791,10 +5813,119 @@ fn dirReadIllumos(userdata: ?*anyopaque, dr: *Dir.Reader, buffer: []Dir.Entry) D
5791
5813
  }
5792
5814
 
5793
5815
  fn dirReadHaiku(userdata: ?*anyopaque, dr: *Dir.Reader, buffer: []Dir.Entry) Dir.Reader.Error!usize {
5794
- _ = userdata;
5795
- _ = dr;
5796
- _ = buffer;
5797
- @panic("TODO implement dirReadHaiku");
5816
+ const t: *Threaded = @ptrCast(@alignCast(userdata));
5817
+ _ = t;
5818
+ var buffer_index: usize = 0;
5819
+ while (buffer.len - buffer_index != 0) {
5820
+ if (dr.end - dr.index == 0) {
5821
+ // Refill the buffer, unless we've already created references to
5822
+ // buffered data.
5823
+ if (buffer_index != 0) break;
5824
+ if (dr.state == .reset) {
5825
+ const syscall: Syscall = try .start();
5826
+ while (true) {
5827
+ const rc = posix.system._kern_rewind_dir(dr.dir.handle);
5828
+ switch (@as(posix.E, @enumFromInt(@min(rc, 0)))) {
5829
+ .SUCCESS => {
5830
+ syscall.finish();
5831
+ break;
5832
+ },
5833
+ .INTR => {
5834
+ try syscall.checkCancel();
5835
+ continue;
5836
+ },
5837
+ else => |e| {
5838
+ syscall.finish();
5839
+ switch (e) {
5840
+ else => |err| return posix.unexpectedErrno(err),
5841
+ }
5842
+ },
5843
+ }
5844
+ }
5845
+ dr.state = .reading;
5846
+ }
5847
+ const syscall: Syscall = try .start();
5848
+ const n: usize = while (true) {
5849
+ const rc = posix.system._kern_read_dir(dr.dir.handle, dr.buffer.ptr, dr.buffer.len, @truncate(dr.buffer.len / @sizeOf(posix.system.DirEnt)));
5850
+ switch (@as(posix.E, @enumFromInt(@min(rc, 0)))) {
5851
+ .SUCCESS => {
5852
+ syscall.finish();
5853
+ break @intCast(rc);
5854
+ },
5855
+ .INTR => {
5856
+ try syscall.checkCancel();
5857
+ continue;
5858
+ },
5859
+ else => |e| {
5860
+ syscall.finish();
5861
+ switch (e) {
5862
+ else => |err| return posix.unexpectedErrno(err),
5863
+ }
5864
+ },
5865
+ }
5866
+ };
5867
+ if (n == 0) {
5868
+ dr.state = .finished;
5869
+ return 0;
5870
+ }
5871
+ dr.index = 0;
5872
+ // _kern_read_dir returns entry count, but Dir.Reader is designed for byte count
5873
+ dr.end = 0;
5874
+ var i: usize = 0;
5875
+ while (i < n) : (i += 1) {
5876
+ const entry = @as(*align(1) posix.system.DirEnt, @ptrCast(&dr.buffer[dr.end]));
5877
+ dr.end += entry.reclen;
5878
+ }
5879
+ }
5880
+ const entry = @as(*align(1) posix.system.DirEnt, @ptrCast(&dr.buffer[dr.index]));
5881
+ const next_index = dr.index + entry.reclen;
5882
+ dr.index = next_index;
5883
+
5884
+ const name = std.mem.sliceTo(@as([*:0]u8, @ptrCast(&entry.name)), 0);
5885
+ if (std.mem.eql(u8, name, ".") or std.mem.eql(u8, name, "..") or entry.ino == 0) continue;
5886
+
5887
+ // haiku dirent doesn't expose type, so we have to call stat to get it.
5888
+ var stat: std.c.Stat = undefined;
5889
+ {
5890
+ const syscall: Syscall = try .start();
5891
+ while (true) {
5892
+ const rc = posix.system._kern_read_stat(dr.dir.handle, name, false, &stat, @sizeOf(std.c.Stat));
5893
+ switch (@as(posix.E, @enumFromInt(@min(rc, 0)))) {
5894
+ .SUCCESS => {
5895
+ syscall.finish();
5896
+ break;
5897
+ },
5898
+ .INTR => {
5899
+ try syscall.checkCancel();
5900
+ continue;
5901
+ },
5902
+ else => |e| {
5903
+ syscall.finish();
5904
+ switch (e) {
5905
+ else => |err| return posix.unexpectedErrno(err),
5906
+ }
5907
+ },
5908
+ }
5909
+ }
5910
+ }
5911
+
5912
+ const entry_kind: File.Kind = switch (stat.mode & posix.S.IFMT) {
5913
+ posix.S.IFBLK => .block_device,
5914
+ posix.S.IFCHR => .character_device,
5915
+ posix.S.IFDIR => .directory,
5916
+ posix.S.IFIFO => .named_pipe,
5917
+ posix.S.IFLNK => .sym_link,
5918
+ posix.S.IFREG => .file,
5919
+ else => .unknown,
5920
+ };
5921
+ buffer[buffer_index] = .{
5922
+ .name = name,
5923
+ .kind = entry_kind,
5924
+ .inode = entry.ino,
5925
+ };
5926
+ buffer_index += 1;
5927
+ }
5928
+ return buffer_index;
5798
5929
  }
5799
5930
 
5800
5931
  fn dirReadWindows(userdata: ?*anyopaque, dr: *Dir.Reader, buffer: []Dir.Entry) Dir.Reader.Error!usize {
@@ -9812,7 +9943,10 @@ fn fileReadPositionalPosix(file: File, data: []const []u8, offset: u64) File.Rea
9812
9943
  if (have_preadv) {
9813
9944
  const syscall: Syscall = try .start();
9814
9945
  while (true) {
9815
- const rc = preadv_sym(file.handle, dest.ptr, @intCast(dest.len), @bitCast(offset));
9946
+ const rc = if (native_os == .haiku)
9947
+ posix.system.readv_pos(file.handle, @bitCast(offset), dest.ptr, @intCast(dest.len))
9948
+ else
9949
+ preadv_sym(file.handle, dest.ptr, @intCast(dest.len), @bitCast(offset));
9816
9950
  switch (posix.errno(rc)) {
9817
9951
  .SUCCESS => {
9818
9952
  syscall.finish();
@@ -9846,7 +9980,7 @@ fn fileReadPositionalPosix(file: File, data: []const []u8, offset: u64) File.Rea
9846
9980
 
9847
9981
  const syscall: Syscall = try .start();
9848
9982
  while (true) {
9849
- const rc = posix.pread(file.handle, dest[0].ptr, @intCast(dest[0].len), @bitCast(offset));
9983
+ const rc = pread_sym(file.handle, dest[0].base, @intCast(dest[0].len), @bitCast(offset));
9850
9984
  switch (posix.errno(rc)) {
9851
9985
  .SUCCESS => {
9852
9986
  syscall.finish();
@@ -10550,7 +10684,10 @@ fn fileWritePositional(
10550
10684
 
10551
10685
  const syscall: Syscall = try .start();
10552
10686
  while (true) {
10553
- const rc = pwritev_sym(file.handle, &iovecs, @intCast(iovlen), @bitCast(offset));
10687
+ const rc = if (native_os == .haiku)
10688
+ posix.system.writev_pos(file.handle, @bitCast(offset), &iovecs, @intCast(iovlen))
10689
+ else
10690
+ pwritev_sym(file.handle, &iovecs, @intCast(iovlen), @bitCast(offset));
10554
10691
  switch (posix.errno(rc)) {
10555
10692
  .SUCCESS => {
10556
10693
  syscall.finish();
@@ -12549,11 +12686,14 @@ fn deferAcceptAfd(t: *Threaded, listen_handle: net.Socket.Handle, info: windows.
12549
12686
  }
12550
12687
  }
12551
12688
 
12552
- fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize {
12689
+ fn netRead(socket_handle: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize {
12553
12690
  if (!have_networking) return error.NetworkDown;
12554
- const t: *Threaded = @ptrCast(@alignCast(userdata));
12555
- _ = t;
12556
12691
 
12692
+ if (is_windows) return netReadWindows(socket_handle, data);
12693
+ return netReadPosix(socket_handle, data);
12694
+ }
12695
+
12696
+ fn netReadPosix(fd: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize {
12557
12697
  var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined;
12558
12698
  var i: usize = 0;
12559
12699
  for (data) |buf| {
@@ -12590,7 +12730,6 @@ fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.
12590
12730
  .NOMEM => return error.SystemResources,
12591
12731
  .NOTCONN => return error.SocketUnconnected,
12592
12732
  .CONNRESET => return error.ConnectionResetByPeer,
12593
- .TIMEDOUT => return error.Timeout,
12594
12733
  .NOTCAPABLE => return error.AccessDenied,
12595
12734
  else => |err| return posix.unexpectedErrno(err),
12596
12735
  }
@@ -12622,7 +12761,6 @@ fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.
12622
12761
  .NOMEM => return error.SystemResources,
12623
12762
  .NOTCONN => return error.SocketUnconnected,
12624
12763
  .CONNRESET => return error.ConnectionResetByPeer,
12625
- .TIMEDOUT => return error.Timeout,
12626
12764
  .PIPE => return error.SocketUnconnected,
12627
12765
  .NETDOWN => return error.NetworkDown,
12628
12766
  else => |err| return posix.unexpectedErrno(err),
@@ -12632,11 +12770,7 @@ fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.
12632
12770
  }
12633
12771
  }
12634
12772
 
12635
- fn netReadWindows(userdata: ?*anyopaque, socket_handle: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize {
12636
- if (!have_networking) return error.NetworkDown;
12637
- const t: *Threaded = @ptrCast(@alignCast(userdata));
12638
- _ = t;
12639
-
12773
+ fn netReadWindows(socket_handle: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize {
12640
12774
  var iovecs: [max_iovecs_len]windows.AFD.WSABUF(.@"var") = undefined;
12641
12775
  var len: u32 = 0;
12642
12776
  for (data) |buf| {
@@ -14063,7 +14197,7 @@ pub fn posixSocketModeProtocol(family: posix.sa_family_t, mode: net.Socket.Mode,
14063
14197
  .dgram => posix.SOCK.DGRAM,
14064
14198
  .seqpacket => posix.SOCK.SEQPACKET,
14065
14199
  .raw => posix.SOCK.RAW,
14066
- .rdm => posix.SOCK.RDM,
14200
+ .rdm => if (@hasDecl(posix.SOCK, "RDM")) posix.SOCK.RDM else return error.OptionUnsupported,
14067
14201
  },
14068
14202
  if (protocol) |p| @intFromEnum(p) else if (is_windows) switch (family) {
14069
14203
  posix.AF.UNIX => switch (mode) {
package/std/Io/Uring.zig CHANGED
@@ -779,7 +779,6 @@ pub fn io(ev: *Evented) Io {
779
779
  .netConnectUnix = netConnectUnixUnavailable,
780
780
  .netSocketCreatePair = netSocketCreatePairUnavailable,
781
781
  .netSend = netSendUnavailable,
782
- .netRead = netReadUnavailable,
783
782
  .netWrite = netWriteUnavailable,
784
783
  .netWriteFile = netWriteFileUnavailable,
785
784
  .netClose = netClose,
@@ -2105,6 +2104,12 @@ fn operate(userdata: ?*anyopaque, operation: Io.Operation) Io.Cancelable!Io.Oper
2105
2104
  };
2106
2105
  },
2107
2106
  },
2107
+ .net_read => |o| .{
2108
+ .net_read = r: {
2109
+ _ = o;
2110
+ break :r error.NetworkDown; // TODO
2111
+ },
2112
+ },
2108
2113
  };
2109
2114
  }
2110
2115
 
@@ -2392,6 +2397,10 @@ fn batchDrainSubmitted(
2392
2397
  _ = o;
2393
2398
  @panic("TODO implement batchDrainSubmitted for net_receive");
2394
2399
  },
2400
+ .net_read => |o| {
2401
+ _ = o;
2402
+ @panic("TODO implement batchDrainSubmitted for net_read");
2403
+ },
2395
2404
  })) |result| {
2396
2405
  switch (batch.completed.tail) {
2397
2406
  .none => batch.completed.head = index,
@@ -2493,6 +2502,7 @@ fn batchDrainReady(batch: *Io.Batch) Io.Timeout.Error!void {
2493
2502
  },
2494
2503
  .device_io_control => unreachable,
2495
2504
  .net_receive => @panic("TODO"),
2505
+ .net_read => @panic("TODO"),
2496
2506
  })) |result| {
2497
2507
  switch (batch.completed.tail) {
2498
2508
  .none => batch.completed.head = index,
@@ -5142,18 +5152,6 @@ fn netReceive(
5142
5152
  }
5143
5153
  }
5144
5154
 
5145
- fn netReadUnavailable(
5146
- userdata: ?*anyopaque,
5147
- fd: net.Socket.Handle,
5148
- data: [][]u8,
5149
- ) net.Stream.Reader.Error!usize {
5150
- const ev: *Evented = @ptrCast(@alignCast(userdata));
5151
- _ = ev;
5152
- _ = fd;
5153
- _ = data;
5154
- return error.NetworkDown;
5155
- }
5156
-
5157
5155
  fn netWriteUnavailable(
5158
5156
  userdata: ?*anyopaque,
5159
5157
  handle: net.Socket.Handle,
package/std/Io/net.zig CHANGED
@@ -1245,6 +1245,15 @@ pub const Stream = struct {
1245
1245
 
1246
1246
  const max_iovecs_len = 8;
1247
1247
 
1248
+ /// This is a low-level API that calls the `Io` interface function directly.
1249
+ /// For a higher level API, see `reader`.
1250
+ pub fn read(s: *const Stream, io: Io, data: [][]u8) Reader.Error!usize {
1251
+ return (try io.operate(.{ .net_read = .{
1252
+ .socket_handle = s.socket.handle,
1253
+ .data = data,
1254
+ } })).net_read;
1255
+ }
1256
+
1248
1257
  pub fn close(s: *const Stream, io: Io) void {
1249
1258
  io.vtable.netClose(io.userdata, (&s.socket.handle)[0..1]);
1250
1259
  }
@@ -1259,16 +1268,7 @@ pub const Stream = struct {
1259
1268
  stream: Stream,
1260
1269
  err: ?Error,
1261
1270
 
1262
- pub const Error = error{
1263
- SystemResources,
1264
- ConnectionResetByPeer,
1265
- Timeout,
1266
- SocketUnconnected,
1267
- /// The file descriptor does not hold the required rights to read
1268
- /// from it.
1269
- AccessDenied,
1270
- NetworkDown,
1271
- } || Io.Cancelable || Io.UnexpectedError;
1271
+ pub const Error = Io.Operation.NetRead.Error || Io.Cancelable;
1272
1272
 
1273
1273
  pub fn init(stream: Stream, io: Io, buffer: []u8) Reader {
1274
1274
  return .{
@@ -1302,7 +1302,7 @@ pub const Stream = struct {
1302
1302
  const dest_n, const data_size = try io_r.writableVector(&iovecs_buffer, data);
1303
1303
  const dest = iovecs_buffer[0..dest_n];
1304
1304
  assert(dest[0].len > 0);
1305
- const n = io.vtable.netRead(io.userdata, r.stream.socket.handle, dest) catch |err| {
1305
+ const n = r.stream.read(io, dest) catch |err| {
1306
1306
  r.err = err;
1307
1307
  return error.ReadFailed;
1308
1308
  };
package/std/Io.zig CHANGED
@@ -243,8 +243,6 @@ pub const VTable = struct {
243
243
  netConnectUnix: *const fn (?*anyopaque, *const net.UnixAddress) net.UnixAddress.ConnectError!net.Socket.Handle,
244
244
  netSocketCreatePair: *const fn (?*anyopaque, net.Socket.CreatePairOptions) net.Socket.CreatePairError![2]net.Socket,
245
245
  netSend: *const fn (?*anyopaque, net.Socket.Handle, []net.OutgoingMessage, net.SendFlags) struct { ?net.Socket.SendError, usize },
246
- /// Returns 0 on end of stream.
247
- netRead: *const fn (?*anyopaque, src: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize,
248
246
  netWrite: *const fn (?*anyopaque, dest: net.Socket.Handle, header: []const u8, data: []const []const u8, splat: usize) net.Stream.Writer.Error!usize,
249
247
  netWriteFile: *const fn (?*anyopaque, net.Socket.Handle, header: []const u8, *Io.File.Reader, Io.Limit) net.Stream.Writer.WriteFileError!usize,
250
248
  netClose: *const fn (?*anyopaque, handle: []const net.Socket.Handle) void,
@@ -261,6 +259,7 @@ pub const Operation = union(enum) {
261
259
  /// other systems this tag is unreachable.
262
260
  device_io_control: DeviceIoControl,
263
261
  net_receive: NetReceive,
262
+ net_read: NetRead,
264
263
 
265
264
  pub const Tag = @typeInfo(Operation).@"union".tag_type.?;
266
265
 
@@ -386,6 +385,23 @@ pub const Operation = union(enum) {
386
385
  pub const Result = struct { ?net.Socket.ReceiveError, usize };
387
386
  };
388
387
 
388
+ pub const NetRead = struct {
389
+ socket_handle: net.Socket.Handle,
390
+ data: [][]u8,
391
+
392
+ pub const Error = error{
393
+ SystemResources,
394
+ ConnectionResetByPeer,
395
+ SocketUnconnected,
396
+ /// The file descriptor does not hold the required rights to read
397
+ /// from it.
398
+ AccessDenied,
399
+ NetworkDown,
400
+ } || Io.UnexpectedError;
401
+
402
+ pub const Result = Error!usize;
403
+ };
404
+
389
405
  pub const Result = Result: {
390
406
  const operation_fields = @typeInfo(Operation).@"union".fields;
391
407
  var field_names: [operation_fields.len][]const u8 = undefined;
@@ -1665,20 +1681,29 @@ pub const Condition = struct {
1665
1681
  .epoch = .init(0),
1666
1682
  };
1667
1683
 
1684
+ /// Blocks until the condition is signaled or canceled.
1685
+ ///
1686
+ /// See also:
1687
+ /// * `waitUncancelable`
1688
+ /// * `waitTimeout`
1668
1689
  pub fn wait(cond: *Condition, io: Io, mutex: *Mutex) Cancelable!void {
1669
- try waitInner(cond, io, mutex, false);
1690
+ waitTimeout(cond, io, mutex, .none) catch |err| switch (err) {
1691
+ error.Timeout => unreachable,
1692
+ error.Canceled => |e| return e,
1693
+ };
1670
1694
  }
1671
1695
 
1672
- /// Same as `wait`, except does not introduce a cancelation point.
1696
+ pub const WaitTimeoutError = Cancelable || Timeout.Error;
1697
+
1698
+ /// Blocks until the condition is signaled, canceled, or the provided
1699
+ /// timeout expires.
1673
1700
  ///
1674
- /// For a description of cancelation and cancelation points, see `Future.cancel`.
1675
- pub fn waitUncancelable(cond: *Condition, io: Io, mutex: *Mutex) void {
1676
- waitInner(cond, io, mutex, true) catch |err| switch (err) {
1677
- error.Canceled => unreachable,
1678
- };
1679
- }
1701
+ /// See also:
1702
+ /// * `wait`
1703
+ /// * `waitUncancelable`
1704
+ pub fn waitTimeout(cond: *Condition, io: Io, mutex: *Mutex, timeout: Timeout) WaitTimeoutError!void {
1705
+ const deadline = timeout.toDeadline(io);
1680
1706
 
1681
- fn waitInner(cond: *Condition, io: Io, mutex: *Mutex, uncancelable: bool) Cancelable!void {
1682
1707
  var epoch = cond.epoch.load(.acquire); // `.acquire` to ensure ordered before state load
1683
1708
 
1684
1709
  {
@@ -1690,10 +1715,7 @@ pub const Condition = struct {
1690
1715
  defer mutex.lockUncancelable(io);
1691
1716
 
1692
1717
  while (true) {
1693
- const result = if (uncancelable)
1694
- io.futexWaitUncancelable(u32, &cond.epoch.raw, epoch)
1695
- else
1696
- io.futexWait(u32, &cond.epoch.raw, epoch);
1718
+ const result = io.futexWaitTimeout(u32, &cond.epoch.raw, epoch, deadline);
1697
1719
 
1698
1720
  epoch = cond.epoch.load(.acquire); // `.acquire` to ensure ordered before `state` laod
1699
1721
 
@@ -1713,13 +1735,62 @@ pub const Condition = struct {
1713
1735
  }
1714
1736
 
1715
1737
  // There are no more signals available; this was a spurious wakeup or an error. If it
1716
- // was an error, we will remove ourselves as a waiter and return that error. Otherwise,
1717
- // we'll loop back to the futex wait.
1738
+ // was an error, we will remove ourselves as a waiter and return that error. If a
1739
+ // timeout was specified and the deadline has passed, we remove ourselves as a waiter
1740
+ // and return `error.Timeout`. Otherwise, we'll loop back to the futex wait.
1718
1741
  result catch |err| {
1719
1742
  const prev_state = cond.state.fetchSub(.{ .waiters = 1, .signals = 0 }, .monotonic);
1720
1743
  assert(prev_state.waiters > 0); // underflow caused by illegal state
1721
1744
  return err;
1722
1745
  };
1746
+ switch (deadline) {
1747
+ .none => {},
1748
+ .deadline => |d| if (d.untilNow(io).raw.nanoseconds >= 0) {
1749
+ const prev_state = cond.state.fetchSub(.{ .waiters = 1, .signals = 0 }, .monotonic);
1750
+ assert(prev_state.waiters > 0); // underflow caused by illegal state
1751
+ return error.Timeout;
1752
+ },
1753
+ .duration => unreachable,
1754
+ }
1755
+ }
1756
+ }
1757
+
1758
+ /// Same as `wait`, except does not introduce a cancelation point.
1759
+ ///
1760
+ /// See `Future.cancel` for a description of cancelation points.
1761
+ pub fn waitUncancelable(cond: *Condition, io: Io, mutex: *Mutex) void {
1762
+ var epoch = cond.epoch.load(.acquire); // `.acquire` to ensure ordered before state load
1763
+
1764
+ {
1765
+ const prev_state = cond.state.fetchAdd(.{ .waiters = 1, .signals = 0 }, .monotonic);
1766
+ assert(prev_state.waiters < math.maxInt(u16)); // overflow caused by too many waiters
1767
+ }
1768
+
1769
+ mutex.unlock(io);
1770
+ defer mutex.lockUncancelable(io);
1771
+
1772
+ while (true) {
1773
+ io.futexWaitUncancelable(u32, &cond.epoch.raw, epoch);
1774
+
1775
+ epoch = cond.epoch.load(.acquire); // `.acquire` to ensure ordered before `state` laod
1776
+
1777
+ // Even on error, try to consume a pending signal first. Otherwise a race might
1778
+ // cause a signal to get stuck in the state with no corresponding waiter.
1779
+ {
1780
+ var prev_state = cond.state.load(.monotonic);
1781
+ while (prev_state.signals > 0) {
1782
+ prev_state = cond.state.cmpxchgWeak(prev_state, .{
1783
+ .waiters = prev_state.waiters - 1,
1784
+ .signals = prev_state.signals - 1,
1785
+ }, .acquire, .monotonic) orelse {
1786
+ // We successfully consumed a signal.
1787
+ return;
1788
+ };
1789
+ }
1790
+ }
1791
+
1792
+ // There are no more signals available; this was a spurious wakeup,
1793
+ // so we'll loop back to the futex wait.
1723
1794
  }
1724
1795
  }
1725
1796
 
@@ -2626,7 +2697,6 @@ pub const failing: std.Io = .{
2626
2697
  .netConnectUnix = failingNetConnectUnix,
2627
2698
  .netSocketCreatePair = failingNetSocketCreatePair,
2628
2699
  .netSend = failingNetSend,
2629
- .netRead = failingNetRead,
2630
2700
  .netWrite = failingNetWrite,
2631
2701
  .netWriteFile = failingNetWriteFile,
2632
2702
  .netClose = unreachableNetClose,
@@ -2774,6 +2844,7 @@ pub fn failingOperate(userdata: ?*anyopaque, operation: Operation) Cancelable!Op
2774
2844
  .file_write_streaming => .{ .file_write_streaming = error.InputOutput },
2775
2845
  .device_io_control => unreachable,
2776
2846
  .net_receive => .{ .net_receive = .{ error.NetworkDown, 0 } },
2847
+ .net_read => .{ .net_read = error.NetworkDown },
2777
2848
  };
2778
2849
  }
2779
2850
 
@@ -3377,13 +3448,6 @@ pub fn failingNetSend(userdata: ?*anyopaque, handle: net.Socket.Handle, messages
3377
3448
  return .{ error.NetworkDown, 0 };
3378
3449
  }
3379
3450
 
3380
- pub fn failingNetRead(userdata: ?*anyopaque, src: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize {
3381
- _ = userdata;
3382
- _ = src;
3383
- _ = data;
3384
- return error.NetworkDown;
3385
- }
3386
-
3387
3451
  pub fn failingNetWrite(userdata: ?*anyopaque, dest: net.Socket.Handle, header: []const u8, data: []const []const u8, splat: usize) net.Stream.Writer.Error!usize {
3388
3452
  _ = userdata;
3389
3453
  _ = dest;
package/std/Target.zig CHANGED
@@ -3082,8 +3082,6 @@ pub fn cTypeByteSize(t: *const Target, c_type: CType) u16 {
3082
3082
  => @divExact(cTypeBitSize(t, c_type), 8),
3083
3083
 
3084
3084
  .longdouble => switch (cTypeBitSize(t, c_type)) {
3085
- 16 => 2,
3086
- 32 => 4,
3087
3085
  64 => 8,
3088
3086
  80 => @intCast(std.mem.alignForward(usize, 10, cTypeAlignment(t, .longdouble))),
3089
3087
  128 => 16,
package/std/c/haiku.zig CHANGED
@@ -6,6 +6,7 @@ const iovec = std.posix.iovec;
6
6
  const iovec_const = std.posix.iovec_const;
7
7
  const socklen_t = std.c.socklen_t;
8
8
  const fd_t = std.c.fd_t;
9
+ const off_t = std.c.off_t;
9
10
  const PATH_MAX = std.c.PATH_MAX;
10
11
  const uid_t = std.c.uid_t;
11
12
  const gid_t = std.c.gid_t;
@@ -28,6 +29,8 @@ pub extern "root" fn _kern_open_dir(fd: fd_t, path: [*:0]const u8) fd_t;
28
29
  pub extern "root" fn _kern_read_dir(fd: fd_t, buffer: [*]u8, bufferSize: usize, maxCount: u32) isize;
29
30
  pub extern "root" fn _kern_rewind_dir(fd: fd_t) status_t;
30
31
  pub extern "root" fn _kern_read_stat(fd: fd_t, path: [*:0]const u8, traverseLink: bool, stat: *std.c.Stat, statSize: usize) status_t;
32
+ pub extern "root" fn readv_pos(fd: fd_t, pos: off_t, vec: [*]const std.c.iovec, count: i32) isize;
33
+ pub extern "root" fn writev_pos(fd: fd_t, pos: off_t, vec: [*]const std.c.iovec_const, count: i32) isize;
31
34
 
32
35
  pub const area_info = extern struct {
33
36
  area: u32,
@@ -53,9 +53,7 @@ pub extern "c" fn profiling_enable(pid: pid_t, event_mask: PERF_EVENT) c_int;
53
53
  pub extern "c" fn profiling_disable(pid: pid_t) c_int;
54
54
  pub extern "c" fn profiling_free_buffer(pid: pid_t) c_int;
55
55
 
56
- pub extern "c" fn futex(userspace_address: *u32, futex_op: c_int, value: u32, timeout: *const timespec, userspace_address2: *u32, value3: u32) c_int;
57
- pub extern "c" fn futex_wait(userspace_address: *u32, value: u32, abstime: *const timespec, clockid: clockid_t, process_shared: c_int) c_int;
58
- pub extern "c" fn futex_wake(userspace_address: *u32, count: u32, process_shared: c_int) c_int;
56
+ pub extern "c" fn futex(userspace_address: *u32, futex_op: c_int, value: u32, timeout: ?*const timespec, userspace_address2: ?*u32, value3: u32) c_int;
59
57
 
60
58
  pub extern "c" fn purge(mode: c_int) c_int;
61
59
 
@@ -66,9 +64,6 @@ pub extern "c" fn get_stack_bounds(user_stack_base: *usize, user_stack_size: *us
66
64
 
67
65
  pub extern "c" fn anon_create(size: usize, options: O) c_int;
68
66
 
69
- pub extern "c" fn serenity_readlink(path: [*]const u8, path_length: usize, buffer: [*]u8, buffer_size: usize) c_int;
70
- pub extern "c" fn serenity_open(path: [*]const u8, path_length: usize, options: c_int, ...) c_int;
71
-
72
67
  pub extern "c" fn getkeymap(name_buffer: [*]u8, name_buffer_size: usize, map: [*]u32, shift_map: [*]u32, alt_map: [*]u32, altgr_map: [*]u32, shift_altgr_map: [*]u32) c_int;
73
68
  pub extern "c" fn setkeymap(name: [*]const u8, map: [*]const u32, shift_map: [*]const u32, alt_map: [*]const u32, altgr_map: [*]const u32, shift_altgr_map: [*]const u32) c_int;
74
69