authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-10-01 23:28:24+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-10-01 23:28:24+02:00
logeb20ecded85ca72256d5dacc52c39226edfe0889
tree8a64f13caa04c18544fecb9bae8ffb6e77f2ad91
parenta0501add57ff187193ddfa3c79b3d26cc96fa1d8
parentf19259c85b9fc3678d61f8c0d306dc8513b75a39

Merge pull request 'std.Io.Operation: improve handling of control data' (#37035) from control-data into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/37035

7 files changed, 339 insertions(+), 22 deletions(-)

lib/std/Io.zig+3-1
......@@ -430,6 +430,7 @@ pub const Operation = union(enum) {
430430 pub const NetRead = struct {
431431 socket_handle: net.Socket.Handle,
432432 data: [][]u8,
433 control: []u8 = &.{},
433434
434435 pub const Error = error{
435436 SystemResources,
......@@ -443,7 +444,7 @@ pub const Operation = union(enum) {
443444 ConnectionTimedOut,
444445 } || Io.UnexpectedError;
445446
446 pub const Result = Error!usize;
447 pub const Result = Error!net.Stream.ReadResult;
447448 };
448449
449450 pub const NetWrite = struct {
......@@ -451,6 +452,7 @@ pub const Operation = union(enum) {
451452 header: []const u8 = &.{},
452453 data: []const []const u8,
453454 splat: usize = 1,
455 control: []const u8 = &.{},
454456
455457 pub const Error = error{
456458 /// Another TCP Fast Open is already in progress.
lib/std/Io/Threaded.zig+37-15
......@@ -2583,16 +2583,16 @@ fn operate(userdata: ?*anyopaque, operation: Io.Operation) Io.Cancelable!Io.Oper
25832583 },
25842584 },
25852585 .net_read => |o| return .{
2586 .net_read = netRead(o.socket_handle, o.data) catch |err| switch (err) {
2586 .net_read = netRead(o.socket_handle, o.data, o.control) catch |err| switch (err) {
25872587 error.Canceled => |e| return e,
25882588 else => |e| e,
25892589 },
25902590 },
25912591 .net_write => |o| return .{
25922592 .net_write = (if (is_windows)
2593 netWriteWindows(o.socket_handle, o.header, o.data, o.splat)
2593 netWriteWindows(o.socket_handle, o.header, o.data, o.splat, o.control)
25942594 else
2595 netWritePosix(o.socket_handle, o.header, o.data, o.splat)) catch |err| switch (err) {
2595 netWritePosix(o.socket_handle, o.header, o.data, o.splat, o.control)) catch |err| switch (err) {
25962596 error.Canceled => |e| return e,
25972597 else => |e| e,
25982598 },
......@@ -3293,7 +3293,7 @@ fn batchDrainSubmittedWindows(t: *Threaded, b: *Io.Batch, concurrency: bool) (Io
32933293 // TODO integrate with overlapped I/O or equivalent to avoid this error
32943294 if (concurrency) return error.ConcurrencyUnavailable;
32953295 batchCompleteBlockingWindows(b, operation_userdata, .{
3296 .net_read = netRead(o.socket_handle, o.data) catch |err| switch (err) {
3296 .net_read = netRead(o.socket_handle, o.data, o.control) catch |err| switch (err) {
32973297 error.Canceled => |e| return e,
32983298 else => |e| e,
32993299 },
......@@ -3303,7 +3303,7 @@ fn batchDrainSubmittedWindows(t: *Threaded, b: *Io.Batch, concurrency: bool) (Io
33033303 // TODO integrate with overlapped I/O or equivalent to avoid this error
33043304 if (concurrency) return error.ConcurrencyUnavailable;
33053305 batchCompleteBlockingWindows(b, operation_userdata, .{
3306 .net_write = netWriteWindows(o.socket_handle, o.header, o.data, o.splat) catch |err| switch (err) {
3306 .net_write = netWriteWindows(o.socket_handle, o.header, o.data, o.splat, o.control) catch |err| switch (err) {
33073307 error.Canceled => |e| return e,
33083308 else => |e| e,
33093309 },
......@@ -12883,14 +12883,14 @@ fn deferAcceptAfd(t: *Threaded, listen_handle: net.Socket.Handle, info: windows.
1288312883 }
1288412884}
1288512885
12886fn netRead(socket_handle: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize {
12886fn netRead(socket_handle: net.Socket.Handle, data: [][]u8, control: []u8) net.Stream.Reader.Error!net.Stream.ReadResult {
1288712887 if (!have_networking) return error.NetworkDown;
1288812888
12889 if (is_windows) return netReadWindows(socket_handle, data);
12890 return netReadPosix(socket_handle, data);
12889 if (is_windows) return .{ .data_len = try netReadWindows(socket_handle, data) };
12890 return netReadPosix(socket_handle, data, control);
1289112891}
1289212892
12893fn netReadPosix(fd: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize {
12893fn netReadPosix(fd: net.Socket.Handle, data: [][]u8, control: []u8) net.Stream.Reader.Error!net.Stream.ReadResult {
1289412894 var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined;
1289512895 var i: usize = 0;
1289612896 for (data) |buf| {
......@@ -12936,13 +12936,31 @@ fn netReadPosix(fd: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usi
1293612936 }
1293712937 }
1293812938
12939 var msg: posix.msghdr = .{
12940 .name = null,
12941 .namelen = 0,
12942 .iov = dest.ptr,
12943 .iovlen = @intCast(dest.len),
12944 .control = control.ptr,
12945 .controllen = @intCast(control.len),
12946 .flags = 0,
12947 };
12948
12949 const flags: u32 =
12950 @as(u32, if (@hasDecl(posix.MSG, "CMSG_CLOEXEC")) posix.MSG.CMSG_CLOEXEC else 0);
12951
1293912952 const syscall: Syscall = try .start();
1294012953 while (true) {
12941 const rc = posix.system.readv(fd, dest.ptr, @intCast(dest.len));
12954 const rc = posix.system.recvmsg(fd, &msg, flags);
12955 const rc_control = msg.controllen;
1294212956 switch (posix.errno(rc)) {
1294312957 .SUCCESS => {
1294412958 syscall.finish();
12945 return @intCast(rc);
12959 return .{
12960 .data_len = @intCast(rc),
12961 .control_len = @intCast(rc_control),
12962 .control_truncated = (msg.flags & posix.MSG.CTRUNC) != 0,
12963 };
1294612964 },
1294712965 .INTR => {
1294812966 try syscall.checkCancel();
......@@ -13229,7 +13247,6 @@ fn netReceivePosix(
1322913247 @as(u32, if (flags.oob) posix.MSG.OOB else 0) |
1323013248 @as(u32, if (flags.peek) posix.MSG.PEEK else 0) |
1323113249 @as(u32, if (flags.trunc) posix.MSG.TRUNC else 0) |
13232 posix.MSG.NOSIGNAL |
1323313250 @as(u32, if (nonblocking) posix.MSG.DONTWAIT else 0);
1323413251
1323513252 var storage: PosixAddress = undefined;
......@@ -13241,7 +13258,7 @@ fn netReceivePosix(
1324113258 .iovlen = 1,
1324213259 .control = message.control.ptr,
1324313260 .controllen = @intCast(message.control.len),
13244 .flags = undefined,
13261 .flags = 0,
1324513262 };
1324613263
1324713264 const syscall = try Syscall.start();
......@@ -13362,6 +13379,7 @@ fn netWritePosix(
1336213379 header: []const u8,
1336313380 data: []const []const u8,
1336413381 splat: usize,
13382 control: []const u8,
1336513383) net.Stream.Writer.Error!usize {
1336613384 if (!have_networking) return error.NetworkDown;
1336713385
......@@ -13371,8 +13389,8 @@ fn netWritePosix(
1337113389 .namelen = 0,
1337213390 .iov = &iovecs,
1337313391 .iovlen = 0,
13374 .control = null,
13375 .controllen = 0,
13392 .control = if (control.len == 0) null else @constCast(control.ptr),
13393 .controllen = @intCast(control.len),
1337613394 .flags = 0,
1337713395 };
1337813396 addBuf(&iovecs, &msg.iovlen, header);
......@@ -13454,9 +13472,13 @@ fn netWriteWindows(
1345413472 header: []const u8,
1345513473 data: []const []const u8,
1345613474 splat: usize,
13475 control: []const u8,
1345713476) net.Stream.Writer.Error!usize {
1345813477 if (!have_networking) return error.NetworkDown;
1345913478
13479 // Windows doesn't have the concept of control/ancillary data.
13480 _ = control;
13481
1346013482 var iovecs: [max_iovecs_len]windows.AFD.WSABUF(.@"const") = undefined;
1346113483 var len: u32 = 0;
1346213484 addAfdBuf(.@"const", &iovecs, &len, header);
lib/std/Io/net.zig+125-6
......@@ -1269,12 +1269,36 @@ pub const Stream = struct {
12691269
12701270 const max_iovecs_len = 8;
12711271
1272 pub const ReadResult = struct {
1273 data_len: usize,
1274 control_len: usize = 0,
1275 /// Whether only some of the control data was received.
1276 ///
1277 /// When control data is truncated, the extra data essentially
1278 /// disappears into the ether. This is indicative of a design problem,
1279 /// such as the control buffer being too small.
1280 control_truncated: bool = false,
1281 };
1282
12721283 /// This is a low-level API that calls the `Io` interface function directly.
12731284 /// For a higher level API, see `reader`.
12741285 pub fn read(s: *const Stream, io: Io, data: [][]u8) Reader.Error!usize {
1275 return (try io.operate(.{ .net_read = .{
1286 const rc, _ = try (try io.operate(.{ .net_read = .{
1287 .socket_handle = s.socket.handle,
1288 .data = data,
1289 } })).net_read;
1290 return rc;
1291 }
1292
1293 /// Read with control data.
1294 ///
1295 /// This is a low-level API that calls the `Io` interface function directly.
1296 /// For a higher level API, see `reader`.
1297 pub fn readWithControl(s: *const Stream, io: Io, data: [][]u8, control: []u8) Reader.Error!ReadResult {
1298 return try (try io.operate(.{ .net_read = .{
12761299 .socket_handle = s.socket.handle,
12771300 .data = data,
1301 .control = control,
12781302 } })).net_read;
12791303 }
12801304
......@@ -1289,12 +1313,25 @@ pub const Stream = struct {
12891313 pub const Reader = struct {
12901314 io: Io,
12911315 interface: Io.Reader,
1316 control_buffer: []align(cmsg_align) u8,
1317 control_len: usize,
1318 control_truncated: bool,
12921319 stream: Stream,
12931320 err: ?Error,
12941321
12951322 pub const Error = Io.Operation.NetRead.Error || Io.Cancelable;
12961323
12971324 pub fn init(stream: Stream, io: Io, buffer: []u8) Reader {
1325 return initWithControl(stream, io, buffer, &.{});
1326 }
1327
1328 /// Same as `init`, but also provides a buffer for storing control data.
1329 pub fn initWithControl(
1330 stream: Stream,
1331 io: Io,
1332 buffer: []u8,
1333 control_buffer: []align(cmsg_align) u8,
1334 ) Reader {
12981335 return .{
12991336 .io = io,
13001337 .interface = .{
......@@ -1306,6 +1343,9 @@ pub const Stream = struct {
13061343 .seek = 0,
13071344 .end = 0,
13081345 },
1346 .control_buffer = control_buffer,
1347 .control_len = 0,
1348 .control_truncated = false,
13091349 .stream = stream,
13101350 .err = null,
13111351 };
......@@ -1326,24 +1366,44 @@ pub const Stream = struct {
13261366 const dest_n, const data_size = try io_r.writableVector(&iovecs_buffer, data);
13271367 const dest = iovecs_buffer[0..dest_n];
13281368 assert(dest[0].len > 0);
1329 const n = r.stream.read(io, dest) catch |err| {
1369 const result = r.stream.readWithControl(io, dest, r.control_buffer[r.control_len..]) catch |err| {
13301370 r.err = err;
13311371 return error.ReadFailed;
13321372 };
1333 if (n == 0) {
1373 r.control_len += result.control_len;
1374 r.control_truncated = r.control_truncated or result.control_truncated;
1375 if (result.data_len == 0) {
13341376 return error.EndOfStream;
13351377 }
1336 if (n > data_size) {
1337 r.interface.end += n - data_size;
1378 if (result.data_len > data_size) {
1379 r.interface.end += result.data_len - data_size;
13381380 return data_size;
13391381 }
1340 return n;
1382 return result.data_len;
1383 }
1384
1385 /// Access raw buffered control data.
1386 pub fn controlSlice(r: *const Reader) []align(cmsg_align) u8 {
1387 return r.control_buffer[0..r.control_len];
1388 }
1389
1390 /// Iterate over buffered control messages.
1391 pub fn controlIterator(r: *const Reader) cmsg.Iterator {
1392 return .{ .control = r.controlSlice() };
1393 }
1394
1395 /// Clear buffered control data.
1396 pub fn clearControl(r: *Reader) void {
1397 r.control_len = 0;
1398 r.control_truncated = false;
13411399 }
13421400 };
13431401
13441402 pub const Writer = struct {
13451403 io: Io,
13461404 interface: Io.Writer,
1405 /// Will be sent on next drain, then set back to an empty slice.
1406 control: []const u8 = &.{},
13471407 stream: Stream,
13481408 err: ?Error = null,
13491409 write_file_err: ?WriteFileError = null,
......@@ -1386,6 +1446,7 @@ pub const Stream = struct {
13861446 .header = buffered,
13871447 .data = data,
13881448 .splat = splat,
1449 .control = w.control,
13891450 } }) catch |err| {
13901451 w.err = err;
13911452 return error.WriteFailed;
......@@ -1394,6 +1455,7 @@ pub const Stream = struct {
13941455 w.err = err;
13951456 return error.WriteFailed;
13961457 };
1458 w.control = &.{};
13971459 return io_w.consume(n);
13981460 }
13991461
......@@ -1424,11 +1486,68 @@ pub const Stream = struct {
14241486 return .init(stream, io, buffer);
14251487 }
14261488
1489 /// Same as `reader`, but also provides a buffer for storing control data.
1490 pub fn readerWithControl(
1491 stream: Stream,
1492 io: Io,
1493 buffer: []u8,
1494 control_buffer: []align(cmsg_align) u8,
1495 ) Reader {
1496 return .initWithControl(stream, io, buffer, control_buffer);
1497 }
1498
14271499 pub fn writer(stream: Stream, io: Io, buffer: []u8) Writer {
14281500 return .init(stream, io, buffer);
14291501 }
14301502};
14311503
1504pub const cmsg_align = if (@TypeOf(std.posix.cmsg_align) == void) 1 else std.posix.cmsg_align;
1505/// Utility Functions for interacting with POSIX socket control messages.
1506/// See also https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_socket.h.html
1507pub const cmsg = struct {
1508 const cmsghdr = std.posix.cmsghdr;
1509
1510 /// Equivalent to `CMSG_SPACE` in C.
1511 pub fn space(data_len: usize) usize {
1512 return std.mem.alignForward(usize, @sizeOf(cmsghdr), cmsg_align) +
1513 std.mem.alignForward(usize, data_len, cmsg_align);
1514 }
1515
1516 /// Equivalent to `CMSG_LEN` in C.
1517 pub fn len(data_len: @FieldType(cmsghdr, "len")) @TypeOf(data_len) {
1518 return std.mem.alignForward(@TypeOf(data_len), @sizeOf(cmsghdr), cmsg_align) + data_len;
1519 }
1520
1521 /// Equivalent to `CMSG_DATA` in C.
1522 pub fn data(header: *align(cmsg_align) cmsghdr) []align(cmsg_align) u8 {
1523 const bytes: [*]u8 = @ptrCast(header);
1524 return @alignCast(bytes[0..header.len][std.mem.alignForward(usize, @sizeOf(cmsghdr), cmsg_align)..]);
1525 }
1526
1527 /// Equivalent to `CMSG_FIRSTHDR` and `CMSG_NXTHDR` in C.
1528 pub const Iterator = struct {
1529 control: []align(cmsg_align) u8,
1530
1531 pub const Message = struct {
1532 header: *cmsghdr,
1533 data: []align(cmsg_align) u8,
1534 };
1535
1536 pub fn next(it: *Iterator) ?Message {
1537 if (it.control.len < @sizeOf(cmsghdr)) return null;
1538 const header: *align(cmsg_align) cmsghdr = @ptrCast(it.control.ptr);
1539 if (it.control.len < header.len) return null;
1540 const next_header = std.mem.alignForward(usize, header.len, cmsg_align);
1541 if (it.control.len < next_header) {
1542 it.control = &.{};
1543 } else {
1544 it.control = @alignCast(it.control[next_header..]);
1545 }
1546 return .{ .header = header, .data = data(header) };
1547 }
1548 };
1549};
1550
14321551pub const Server = struct {
14331552 socket: Socket,
14341553 options: AcceptOptions,
lib/std/Io/net/test.zig+94
......@@ -4,6 +4,7 @@ const std = @import("std");
44const Io = std.Io;
55const net = std.Io.net;
66const mem = std.mem;
7const posix = std.posix;
78const testing = std.testing;
89const Allocator = std.mem.Allocator;
910
......@@ -295,6 +296,99 @@ test "listen on a unix socket, send bytes, receive bytes" {
295296 try client_task.await(io);
296297}
297298
299test "listen on a unix socket, pass file descriptor" {
300 if (builtin.os.tag == .windows or builtin.os.tag == .wasi) {
301 // Windows and WASI don't have the concept of control/ancillary data.
302 return error.SkipZigTest;
303 }
304
305 const io = testing.io;
306 const gpa = testing.allocator;
307
308 const socket_path = try generateFileName(gpa, io, "socket.unix");
309 defer gpa.free(socket_path);
310 const temp_file_path = try generateFileName(gpa, io, "temp_file");
311 defer gpa.free(temp_file_path);
312
313 defer Io.Dir.cwd().deleteFile(io, socket_path) catch {};
314 defer Io.Dir.cwd().deleteFile(io, temp_file_path) catch {};
315
316 const socket_addr = try net.UnixAddress.init(socket_path);
317
318 var server = socket_addr.listen(io, .{}) catch |err| switch (err) {
319 error.AddressFamilyUnsupported => return error.SkipZigTest,
320 error.NetworkDown => return error.SkipZigTest,
321 else => |e| return e,
322 };
323 defer server.socket.close(io);
324
325 const S = struct {
326 fn clientFn(path: []const u8, file_path: []const u8) !void {
327 const temp_file = try Io.Dir.cwd().createFile(io, file_path, .{});
328 defer temp_file.close(io);
329
330 const server_path: net.UnixAddress = try .init(path);
331 var stream = try server_path.connect(io);
332 defer stream.close(io);
333
334 var cmsg_buf: [net.cmsg.space(@sizeOf(posix.fd_t))]u8 align(Io.net.cmsg_align) = @splat(0);
335
336 const header: *align(Io.net.cmsg_align) posix.cmsghdr = @ptrCast(&cmsg_buf);
337 header.* = .{
338 .len = net.cmsg.len(@sizeOf(posix.fd_t)),
339 .level = posix.SOL.SOCKET,
340 .type = posix.SCM.RIGHTS,
341 };
342
343 const fds: []posix.fd_t = @ptrCast(net.cmsg.data(header));
344 fds[0] = temp_file.handle;
345
346 var stream_writer = stream.writer(io, &.{});
347 stream_writer.control = &cmsg_buf;
348 try stream_writer.interface.writeAll("Hello world!");
349 }
350 };
351
352 var client_task = io.concurrent(S.clientFn, .{ socket_path, temp_file_path }) catch |err| switch (err) {
353 error.ConcurrencyUnavailable => return error.SkipZigTest,
354 };
355 defer client_task.cancel(io) catch {};
356
357 var stream = try server.accept(io);
358 defer stream.close(io);
359
360 var control_buf: [32]u8 align(Io.net.cmsg_align) = undefined;
361 var buf: [16]u8 = undefined;
362 var stream_reader = stream.readerWithControl(io, &.{}, &control_buf);
363
364 const n = try stream_reader.interface.readSliceShort(&buf);
365
366 try testing.expect(!stream_reader.control_truncated); // The control buffer should be big enough to receive the entire control message
367
368 try testing.expectEqual(12, n);
369 try testing.expectEqualStrings("Hello world!", buf[0..n]);
370
371 var it = stream_reader.controlIterator();
372 const control = it.next() orelse return error.TestUnexpectedResult;
373 try testing.expectEqual(null, it.next());
374
375 try testing.expectEqual(net.cmsg.len(@sizeOf(posix.fd_t)), control.header.len);
376 try testing.expectEqual(posix.SOL.SOCKET, control.header.level);
377 try testing.expectEqual(posix.SCM.RIGHTS, control.header.type);
378
379 const fds: []posix.fd_t = @ptrCast(control.data);
380
381 const temp_file: Io.File = .{
382 .handle = fds[0],
383 .flags = .{ .nonblocking = false },
384 };
385 defer temp_file.close(io);
386 var temp_file_writer = temp_file.writer(io, &.{});
387 try temp_file_writer.interface.writeAll("if this is a real file descriptor, this shouldn't fail");
388
389 try client_task.await(io);
390}
391
298392fn generateFileName(gpa: Allocator, io: Io, base_name: []const u8) ![]const u8 {
299393 const random_bytes_count = 12;
300394 const sub_path_len = comptime std.base64.url_safe.Encoder.calcSize(random_bytes_count);
lib/std/c.zig+75
......@@ -3373,6 +3373,19 @@ pub const Sigaction = switch (native_os) {
33733373 restorer: ?*const fn () callconv(.c) void = null,
33743374 mask: sigset_t,
33753375 } else common_linux_Sigaction,
3376 .sparc64 => if (builtin.abi == .gnu) extern struct {
3377 pub const handler_fn = *align(1) const fn (SIG) callconv(.c) void;
3378 pub const sigaction_fn = *const fn (SIG, *const siginfo_t, ?*anyopaque) callconv(.c) void;
3379
3380 handler: extern union {
3381 handler: ?handler_fn,
3382 sigaction: ?sigaction_fn,
3383 },
3384 mask: sigset_t,
3385 __glibc_reserved0: c_int = 0,
3386 flags: c_uint,
3387 restorer: ?*const fn () callconv(.c) void = null,
3388 } else common_linux_Sigaction,
33763389 else => common_linux_Sigaction,
33773390 },
33783391 .emscripten => emscripten.Sigaction,
......@@ -4432,6 +4445,68 @@ const posix_cmsghdr = extern struct {
44324445 type: c_int,
44334446};
44344447
4448// Alignment used by POSIX specified CMSG_* Macros
4449// https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_socket.h.html
4450pub const cmsg_align = switch (native_os) {
4451 .linux => linux.cmsg_align,
4452 // https://github.com/emscripten-core/emscripten/blob/96371ed7888fc78c040179f4d4faa82a6a07a116/system/lib/libc/musl/include/sys/socket.h#L362
4453 .emscripten => @sizeOf(usize),
4454 // https://github.com/freebsd/freebsd-src/blob/b197d2abcb6895d78bc9df8404e374397aa44748/sys/sys/socket.h#L584
4455 // https://github.com/freebsd/freebsd-src/blob/d2018cedb414ef17e77b7fc2fa19fd81328da46b/sys/sys/_align.h#L30
4456 .freebsd => @sizeOf(*anyopaque),
4457 // https://github.com/DragonFlyBSD/DragonFlyBSD/blob/d1f4fb943c73e2b61ddabff6aa48ce7551db72f4/sys/sys/socket.h#L441
4458 // https://github.com/DragonFlyBSD/DragonFlyBSD/blob/d1f4fb943c73e2b61ddabff6aa48ce7551db72f4/sys/cpu/x86_64/include/alignbytes.h#L35
4459 .dragonfly => switch (builtin.cpu.arch) {
4460 .x86_64 => @sizeOf(c_long),
4461 else => {},
4462 },
4463 // https://github.com/NetBSD/src/blob/ba8e1774fd9c0c26ecca461c07bc95d9ebb69579/sys/sys/socket.h#L544
4464 .netbsd => switch (builtin.cpu.arch) {
4465 // https://github.com/NetBSD/src/blob/ac016822f750dc9166c84b6d2657479992622192/sys/arch/arm/include/cdefs.h#L63
4466 .aarch64, .aarch64_be => @sizeOf(i128),
4467 .arm, .armeb => @sizeOf(c_longlong),
4468 // https://github.com/NetBSD/src/blob/ac016822f750dc9166c84b6d2657479992622192/sys/arch/i386/include/cdefs.h#L9
4469 .x86 => @sizeOf(c_int),
4470 // https://github.com/NetBSD/src/blob/ac016822f750dc9166c84b6d2657479992622192/sys/arch/amd64/include/cdefs.h#L6
4471 .x86_64 => @sizeOf(c_long),
4472 // https://github.com/NetBSD/src/blob/ac016822f750dc9166c84b6d2657479992622192/sys/arch/mips/include/cdefs.h#L74
4473 .mips, .mips64, .mipsel, .mips64el => 8,
4474 // https://github.com/NetBSD/src/blob/ac016822f750dc9166c84b6d2657479992622192/sys/arch/sparc/include/cdefs.h#L8
4475 .sparc64 => 16,
4476 // https://github.com/NetBSD/src/blob/ac016822f750dc9166c84b6d2657479992622192/sys/arch/sparc/include/cdefs.h#L10
4477 .sparc => 8,
4478 // https://github.com/NetBSD/src/blob/ac016822f750dc9166c84b6d2657479992622192/sys/arch/alpha/include/cdefs.h#L6
4479 .alpha => 8,
4480 // https://github.com/NetBSD/src/blob/ac016822f750dc9166c84b6d2657479992622192/sys/arch/m68k/include/cdefs.h#L6
4481 .m68k => @sizeOf(c_int),
4482 // https://github.com/NetBSD/src/blob/ac016822f750dc9166c84b6d2657479992622192/sys/arch/hppa/include/cdefs.h#L12
4483 .hppa => 8,
4484 // https://github.com/NetBSD/src/blob/ac016822f750dc9166c84b6d2657479992622192/sys/arch/riscv/include/cdefs.h#L5
4485 .riscv32, .riscv32be, .riscv64, .riscv64be => @as(comptime_int, builtin.target.cMaxIntAlignment()),
4486 // https://github.com/NetBSD/src/blob/ac016822f750dc9166c84b6d2657479992622192/sys/arch/powerpc/include/cdefs.h#L6
4487 .powerpc, .powerpcle, .powerpc64, .powerpc64le => @sizeOf(f64),
4488 // https://github.com/NetBSD/src/blob/ac016822f750dc9166c84b6d2657479992622192/sys/arch/or1k/include/cdefs.h#L6
4489 .or1k => @as(comptime_int, builtin.target.cMaxIntAlignment()),
4490 else => {},
4491 },
4492 // https://github.com/openbsd/src/blob/4a7ecdb29021f26ee0ef397afdd2931e20e63071/sys/sys/socket.h#L564
4493 // https://github.com/openbsd/src/blob/4a7ecdb29021f26ee0ef397afdd2931e20e63071/sys/arch/amd64/include/_types.h#L50
4494 .openbsd => @sizeOf(c_long),
4495 // https://github.com/illumos/illumos-gate/blob/c1e950d976948602134f0e0e5dadf3d48a7ee996/usr/src/uts/common/sys/socket.h#L469
4496 .illumos => 4,
4497 // https://github.com/haiku/haiku/blob/b54f586058fd6623645512e4631468cede9933b9/headers/posix/sys/socket.h#L152
4498 // https://github.com/haiku/haiku/blob/6059d64cb7cd145f0f1eb5b89c383f71e4b6bebf/headers/posix/sys/param.h#L28
4499 .haiku => @sizeOf(c_long),
4500 // https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/sys/socket.h#L1077
4501 .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => 4,
4502 else => {},
4503};
4504comptime {
4505 if (@TypeOf(cmsg_align) != void and @TypeOf(cmsghdr) != void) {
4506 assert(cmsg_align >= @alignOf(cmsghdr));
4507 }
4508}
4509
44354510pub const nfds_t = switch (native_os) {
44364511 .linux => linux.nfds_t,
44374512 .emscripten => emscripten.nfds_t,
lib/std/os/linux.zig+3
......@@ -11244,6 +11244,9 @@ pub const cmsghdr = extern struct {
1124411244 type: i32,
1124511245};
1124611246
11247// https://github.com/torvalds/linux/blob/72d3fcf802c45d00b300f25b848a93c3a2bd7c7e/include/linux/socket.h#L133
11248pub const cmsg_align = @sizeOf(c_long);
11249
1124711250pub const riscv_hwprobe = extern struct {
1124811251 key: i64,
1124911252 value: u64,
lib/std/posix.zig+2
......@@ -150,6 +150,8 @@ pub const blkcnt_t = system.blkcnt_t;
150150pub const blksize_t = system.blksize_t;
151151pub const clock_t = system.clock_t;
152152pub const clockid_t = system.clockid_t;
153pub const cmsghdr = system.cmsghdr;
154pub const cmsg_align = system.cmsg_align;
153155pub const timerfd_clockid_t = system.timerfd_clockid_t;
154156pub const cpu_set_t = system.cpu_set_t;
155157pub const dev_t = system.dev_t;