mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
std.os.linux: export kernel-sized sigset_t and operations
The kernel ABI sigset_t is smaller than the glibc one. Define the right-sized sigset_t and fixup the sigaction() wrapper to leverage it. The Sigaction wrapper here is not an ABI, so relax it (drop the "extern" and the "restorer" fields), the existing `k_sigaction` is the ABI sigaction struct. Linux defines `sigset_t` with a c_ulong, so it can be 32-bit or 64-bit, depending on the platform. This can make a difference on big-endian systems. Patch up `ucontext_t` so that this change doesn't impact its layout. AFAICT, its currently the glibc layout.
This commit is contained in:
parent
51654aea87
commit
298b1886b2
3 changed files with 88 additions and 42 deletions
|
|
@ -1745,8 +1745,9 @@ pub fn sigprocmask(flags: u32, noalias set: ?*const sigset_t, noalias oldset: ?*
|
||||||
return syscall4(.rt_sigprocmask, flags, @intFromPtr(set), @intFromPtr(oldset), NSIG / 8);
|
return syscall4(.rt_sigprocmask, flags, @intFromPtr(set), @intFromPtr(oldset), NSIG / 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) usize {
|
pub fn sigaction(sig: u8, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) usize {
|
||||||
assert(sig >= 1);
|
assert(sig > 0);
|
||||||
|
assert(sig < NSIG);
|
||||||
assert(sig != SIG.KILL);
|
assert(sig != SIG.KILL);
|
||||||
assert(sig != SIG.STOP);
|
assert(sig != SIG.STOP);
|
||||||
|
|
||||||
|
|
@ -1755,14 +1756,15 @@ pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigact
|
||||||
const mask_size = @sizeOf(@TypeOf(ksa.mask));
|
const mask_size = @sizeOf(@TypeOf(ksa.mask));
|
||||||
|
|
||||||
if (act) |new| {
|
if (act) |new| {
|
||||||
|
// Zig needs to install our arch restorer function with any signal handler, so
|
||||||
|
// must copy the Sigaction struct
|
||||||
const restorer_fn = if ((new.flags & SA.SIGINFO) != 0) &restore_rt else &restore;
|
const restorer_fn = if ((new.flags & SA.SIGINFO) != 0) &restore_rt else &restore;
|
||||||
ksa = k_sigaction{
|
ksa = k_sigaction{
|
||||||
.handler = new.handler.handler,
|
.handler = new.handler.handler,
|
||||||
.flags = new.flags | SA.RESTORER,
|
.flags = new.flags | SA.RESTORER,
|
||||||
.mask = undefined,
|
.mask = new.mask,
|
||||||
.restorer = @ptrCast(restorer_fn),
|
.restorer = @ptrCast(restorer_fn),
|
||||||
};
|
};
|
||||||
@memcpy(@as([*]u8, @ptrCast(&ksa.mask))[0..mask_size], @as([*]const u8, @ptrCast(&new.mask)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ksa_arg = if (act != null) @intFromPtr(&ksa) else 0;
|
const ksa_arg = if (act != null) @intFromPtr(&ksa) else 0;
|
||||||
|
|
@ -1777,8 +1779,8 @@ pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigact
|
||||||
|
|
||||||
if (oact) |old| {
|
if (oact) |old| {
|
||||||
old.handler.handler = oldksa.handler;
|
old.handler.handler = oldksa.handler;
|
||||||
old.flags = @as(c_uint, @truncate(oldksa.flags));
|
old.flags = oldksa.flags;
|
||||||
@memcpy(@as([*]u8, @ptrCast(&old.mask))[0..mask_size], @as([*]const u8, @ptrCast(&oldksa.mask)));
|
old.mask = oldksa.mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -1786,25 +1788,31 @@ pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigact
|
||||||
|
|
||||||
const usize_bits = @typeInfo(usize).int.bits;
|
const usize_bits = @typeInfo(usize).int.bits;
|
||||||
|
|
||||||
pub const sigset_t = [1024 / 32]u32;
|
/// Defined as one greater than the largest defined signal number.
|
||||||
|
pub const NSIG = if (is_mips) 128 else 65;
|
||||||
|
|
||||||
|
/// Linux kernel's sigset_t. This is logically 64-bit on most
|
||||||
|
/// architectures, but 128-bit on MIPS. Contrast with the 1024-bit
|
||||||
|
/// sigset_t exported by the glibc and musl library ABIs.
|
||||||
|
pub const sigset_t = [(NSIG - 1 + 7) / @bitSizeOf(SigsetElement)]SigsetElement;
|
||||||
|
|
||||||
|
const SigsetElement = c_ulong;
|
||||||
|
|
||||||
const sigset_len = @typeInfo(sigset_t).array.len;
|
const sigset_len = @typeInfo(sigset_t).array.len;
|
||||||
|
|
||||||
/// Empty set to initialize sigset_t instances from.
|
/// Empty set to initialize sigset_t instances from. No need for `sigemptyset`.
|
||||||
pub const empty_sigset: sigset_t = [_]u32{0} ** sigset_len;
|
pub const empty_sigset: sigset_t = [_]SigsetElement{0} ** sigset_len;
|
||||||
|
|
||||||
pub const filled_sigset: sigset_t = [_]u32{0x7fff_ffff} ++ [_]u32{0} ** (sigset_len - 1);
|
/// Filled set to initialize sigset_t instances from. No need for `sigfillset`.
|
||||||
|
pub const filled_sigset: sigset_t = [_]SigsetElement{~@as(SigsetElement, 0)} ** sigset_len;
|
||||||
|
|
||||||
pub const all_mask: sigset_t = [_]u32{0xffff_ffff} ** sigset_len;
|
fn sigset_bit_index(sig: usize) struct { word: usize, mask: SigsetElement } {
|
||||||
|
|
||||||
fn sigset_bit_index(sig: usize) struct { word: usize, mask: u32 } {
|
|
||||||
assert(sig > 0);
|
assert(sig > 0);
|
||||||
assert(sig < NSIG);
|
assert(sig < NSIG);
|
||||||
const bit = sig - 1;
|
const bit = sig - 1;
|
||||||
const shift = @as(u5, @truncate(bit % 32));
|
|
||||||
return .{
|
return .{
|
||||||
.word = bit / 32,
|
.word = bit / @bitSizeOf(SigsetElement),
|
||||||
.mask = @as(u32, 1) << shift,
|
.mask = @as(SigsetElement, 1) << @truncate(bit % @bitSizeOf(SigsetElement)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5479,38 +5487,33 @@ pub const TFD = switch (native_arch) {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// NSIG is the total number of signals defined.
|
|
||||||
/// As signal numbers are sequential, NSIG is one greater than the largest defined signal number.
|
|
||||||
pub const NSIG = if (is_mips) 128 else 65;
|
|
||||||
|
|
||||||
const k_sigaction_funcs = struct {
|
const k_sigaction_funcs = struct {
|
||||||
const handler = ?*align(1) const fn (i32) callconv(.c) void;
|
const handler = ?*align(1) const fn (i32) callconv(.c) void;
|
||||||
const restorer = *const fn () callconv(.c) void;
|
const restorer = *const fn () callconv(.c) void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Kernel sigaction struct, as expected by the `rt_sigaction` syscall. Includes restorer.
|
||||||
pub const k_sigaction = switch (native_arch) {
|
pub const k_sigaction = switch (native_arch) {
|
||||||
.mips, .mipsel => extern struct {
|
.mips, .mipsel, .mips64, .mips64el => extern struct {
|
||||||
flags: c_uint,
|
flags: c_uint,
|
||||||
handler: k_sigaction_funcs.handler,
|
handler: k_sigaction_funcs.handler,
|
||||||
mask: [4]c_ulong,
|
mask: sigset_t,
|
||||||
restorer: k_sigaction_funcs.restorer,
|
|
||||||
},
|
|
||||||
.mips64, .mips64el => extern struct {
|
|
||||||
flags: c_uint,
|
|
||||||
handler: k_sigaction_funcs.handler,
|
|
||||||
mask: [2]c_ulong,
|
|
||||||
restorer: k_sigaction_funcs.restorer,
|
restorer: k_sigaction_funcs.restorer,
|
||||||
},
|
},
|
||||||
else => extern struct {
|
else => extern struct {
|
||||||
handler: k_sigaction_funcs.handler,
|
handler: k_sigaction_funcs.handler,
|
||||||
flags: c_ulong,
|
flags: c_ulong,
|
||||||
restorer: k_sigaction_funcs.restorer,
|
restorer: k_sigaction_funcs.restorer,
|
||||||
mask: [2]c_uint,
|
mask: sigset_t,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Kernel Sigaction wrapper for the actual ABI `k_sigaction`. The Zig
|
||||||
|
/// linux.zig wrapper library still does some pre-processing on
|
||||||
|
/// sigaction() calls (to add the `restorer` field).
|
||||||
|
///
|
||||||
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
|
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
|
||||||
pub const Sigaction = extern struct {
|
pub const Sigaction = struct {
|
||||||
pub const handler_fn = *align(1) const fn (i32) callconv(.c) void;
|
pub const handler_fn = *align(1) const fn (i32) callconv(.c) void;
|
||||||
pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.c) void;
|
pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.c) void;
|
||||||
|
|
||||||
|
|
@ -5519,8 +5522,10 @@ pub const Sigaction = extern struct {
|
||||||
sigaction: ?sigaction_fn,
|
sigaction: ?sigaction_fn,
|
||||||
},
|
},
|
||||||
mask: sigset_t,
|
mask: sigset_t,
|
||||||
flags: c_uint,
|
flags: switch (native_arch) {
|
||||||
restorer: ?*const fn () callconv(.c) void = null,
|
.mips, .mipsel, .mips64, .mips64el => c_uint,
|
||||||
|
else => c_ulong,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const SFD = struct {
|
pub const SFD = struct {
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,8 @@ test "fadvise" {
|
||||||
}
|
}
|
||||||
|
|
||||||
test "sigset_t" {
|
test "sigset_t" {
|
||||||
|
std.debug.assert(@sizeOf(linux.sigset_t) == (linux.NSIG / 8));
|
||||||
|
|
||||||
var sigset = linux.empty_sigset;
|
var sigset = linux.empty_sigset;
|
||||||
|
|
||||||
// See that none are set, then set each one, see that they're all set, then
|
// See that none are set, then set each one, see that they're all set, then
|
||||||
|
|
@ -138,6 +140,7 @@ test "sigset_t" {
|
||||||
}
|
}
|
||||||
for (1..linux.NSIG) |i| {
|
for (1..linux.NSIG) |i| {
|
||||||
try expectEqual(linux.sigismember(&sigset, @truncate(i)), true);
|
try expectEqual(linux.sigismember(&sigset, @truncate(i)), true);
|
||||||
|
try expectEqual(linux.sigismember(&linux.filled_sigset, @truncate(i)), true);
|
||||||
try expectEqual(linux.sigismember(&linux.empty_sigset, @truncate(i)), false);
|
try expectEqual(linux.sigismember(&linux.empty_sigset, @truncate(i)), false);
|
||||||
}
|
}
|
||||||
for (1..linux.NSIG) |i| {
|
for (1..linux.NSIG) |i| {
|
||||||
|
|
@ -147,22 +150,52 @@ test "sigset_t" {
|
||||||
try expectEqual(linux.sigismember(&sigset, @truncate(i)), false);
|
try expectEqual(linux.sigismember(&sigset, @truncate(i)), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Kernel sigset_t is either 2+ 32-bit values or 1+ 64-bit value(s).
|
||||||
|
const sigset_len = @typeInfo(linux.sigset_t).array.len;
|
||||||
|
const sigset_elemis64 = 64 == @bitSizeOf(@typeInfo(linux.sigset_t).array.child);
|
||||||
|
|
||||||
linux.sigaddset(&sigset, 1);
|
linux.sigaddset(&sigset, 1);
|
||||||
try expectEqual(sigset[0], 1);
|
try expectEqual(sigset[0], 1);
|
||||||
try expectEqual(sigset[1], 0);
|
if (sigset_len > 1) {
|
||||||
|
try expectEqual(sigset[1], 0);
|
||||||
|
}
|
||||||
|
|
||||||
linux.sigaddset(&sigset, 31);
|
linux.sigaddset(&sigset, 31);
|
||||||
try expectEqual(sigset[0], 0x4000_0001);
|
try expectEqual(sigset[0], 0x4000_0001);
|
||||||
try expectEqual(sigset[1], 0);
|
if (sigset_len > 1) {
|
||||||
|
try expectEqual(sigset[1], 0);
|
||||||
|
}
|
||||||
|
|
||||||
linux.sigaddset(&sigset, 36);
|
linux.sigaddset(&sigset, 36);
|
||||||
try expectEqual(sigset[0], 0x4000_0001);
|
if (sigset_elemis64) {
|
||||||
try expectEqual(sigset[1], 0x8);
|
try expectEqual(sigset[0], 0x8_4000_0001);
|
||||||
|
} else {
|
||||||
|
try expectEqual(sigset[0], 0x4000_0001);
|
||||||
|
try expectEqual(sigset[1], 0x8);
|
||||||
|
}
|
||||||
|
|
||||||
linux.sigaddset(&sigset, 64);
|
linux.sigaddset(&sigset, 64);
|
||||||
try expectEqual(sigset[0], 0x4000_0001);
|
if (sigset_elemis64) {
|
||||||
try expectEqual(sigset[1], 0x8000_0008);
|
try expectEqual(sigset[0], 0x8000_0008_4000_0001);
|
||||||
try expectEqual(sigset[2], 0);
|
} else {
|
||||||
|
try expectEqual(sigset[0], 0x4000_0001);
|
||||||
|
try expectEqual(sigset[1], 0x8000_0008);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "filled_sigset" {
|
||||||
|
// unlike the C library, all the signals are set in the kernel-level fillset
|
||||||
|
const sigset = linux.filled_sigset;
|
||||||
|
for (1..linux.NSIG) |i| {
|
||||||
|
try expectEqual(linux.sigismember(&sigset, @truncate(i)), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "empty_sigset" {
|
||||||
|
const sigset = linux.empty_sigset;
|
||||||
|
for (1..linux.NSIG) |i| {
|
||||||
|
try expectEqual(linux.sigismember(&sigset, @truncate(i)), false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "sysinfo" {
|
test "sysinfo" {
|
||||||
|
|
|
||||||
|
|
@ -369,13 +369,21 @@ pub const mcontext_t = extern struct {
|
||||||
reserved1: [8]usize = undefined,
|
reserved1: [8]usize = undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// ucontext_t is part of the state pushed on the stack by the kernel for
|
||||||
|
/// a signal handler. And also a subset of the state returned from the
|
||||||
|
/// makecontext/getcontext/swapcontext POSIX APIs.
|
||||||
|
///
|
||||||
|
/// Currently this structure matches the glibc/musl layout. It contains a
|
||||||
|
/// 1024-bit signal mask, and `fpregs_mem`. This structure should be
|
||||||
|
/// split into one for the kernel ABI and c.zig should define a glibc/musl
|
||||||
|
/// compatible structure.
|
||||||
pub const ucontext_t = extern struct {
|
pub const ucontext_t = extern struct {
|
||||||
flags: usize,
|
flags: usize,
|
||||||
link: ?*ucontext_t,
|
link: ?*ucontext_t,
|
||||||
stack: stack_t,
|
stack: stack_t,
|
||||||
mcontext: mcontext_t,
|
mcontext: mcontext_t,
|
||||||
sigmask: sigset_t,
|
sigmask: [1024 / @bitSizeOf(c_ulong)]c_ulong, // Currently a glibc-compatible (1024-bit) sigmask.
|
||||||
fpregs_mem: [64]usize,
|
fpregs_mem: [64]usize, // Not part of kernel ABI, only part of glibc ucontext_t
|
||||||
};
|
};
|
||||||
|
|
||||||
fn gpRegisterOffset(comptime reg_index: comptime_int) usize {
|
fn gpRegisterOffset(comptime reg_index: comptime_int) usize {
|
||||||
|
|
@ -455,7 +463,7 @@ fn getContextInternal() callconv(.naked) usize {
|
||||||
[stack_offset] "i" (@offsetOf(ucontext_t, "stack")),
|
[stack_offset] "i" (@offsetOf(ucontext_t, "stack")),
|
||||||
[sigprocmask] "i" (@intFromEnum(linux.SYS.rt_sigprocmask)),
|
[sigprocmask] "i" (@intFromEnum(linux.SYS.rt_sigprocmask)),
|
||||||
[sigmask_offset] "i" (@offsetOf(ucontext_t, "sigmask")),
|
[sigmask_offset] "i" (@offsetOf(ucontext_t, "sigmask")),
|
||||||
[sigset_size] "i" (linux.NSIG / 8),
|
[sigset_size] "i" (@sizeOf(sigset_t)),
|
||||||
: "cc", "memory", "rax", "rcx", "rdx", "rdi", "rsi", "r8", "r10", "r11"
|
: "cc", "memory", "rax", "rcx", "rdx", "rdi", "rsi", "r8", "r10", "r11"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue