mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
Merge pull request #23601 from rootbeer/sig-split
Split glibc and linux sigset_t ABIs and the accessor functions
This commit is contained in:
commit
ad9cb40112
22 changed files with 393 additions and 155 deletions
|
|
@ -410,9 +410,9 @@ pub fn start(options: Options) Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (have_sigwinch) {
|
if (have_sigwinch) {
|
||||||
var act: posix.Sigaction = .{
|
const act: posix.Sigaction = .{
|
||||||
.handler = .{ .sigaction = handleSigWinch },
|
.handler = .{ .sigaction = handleSigWinch },
|
||||||
.mask = posix.empty_sigset,
|
.mask = posix.sigemptyset(),
|
||||||
.flags = (posix.SA.SIGINFO | posix.SA.RESTART),
|
.flags = (posix.SA.SIGINFO | posix.SA.RESTART),
|
||||||
};
|
};
|
||||||
posix.sigaction(posix.SIG.WINCH, &act, null);
|
posix.sigaction(posix.SIG.WINCH, &act, null);
|
||||||
|
|
|
||||||
|
|
@ -3115,6 +3115,21 @@ pub const SYS = switch (native_os) {
|
||||||
.linux => linux.SYS,
|
.linux => linux.SYS,
|
||||||
else => void,
|
else => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// A common format for the Sigaction struct across a variety of Linux flavors.
|
||||||
|
const common_linux_Sigaction = extern struct {
|
||||||
|
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;
|
||||||
|
|
||||||
|
handler: extern union {
|
||||||
|
handler: ?handler_fn,
|
||||||
|
sigaction: ?sigaction_fn,
|
||||||
|
},
|
||||||
|
mask: sigset_t,
|
||||||
|
flags: c_uint,
|
||||||
|
restorer: ?*const fn () callconv(.c) void = null, // C library will fill this in
|
||||||
|
};
|
||||||
|
|
||||||
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name.
|
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name.
|
||||||
pub const Sigaction = switch (native_os) {
|
pub const Sigaction = switch (native_os) {
|
||||||
.linux => switch (native_arch) {
|
.linux => switch (native_arch) {
|
||||||
|
|
@ -3123,7 +3138,7 @@ pub const Sigaction = switch (native_os) {
|
||||||
.mips64,
|
.mips64,
|
||||||
.mips64el,
|
.mips64el,
|
||||||
=> if (builtin.target.abi.isMusl())
|
=> if (builtin.target.abi.isMusl())
|
||||||
linux.Sigaction
|
common_linux_Sigaction
|
||||||
else if (builtin.target.ptrBitWidth() == 64) extern struct {
|
else if (builtin.target.ptrBitWidth() == 64) extern 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;
|
||||||
|
|
@ -3160,8 +3175,8 @@ pub const Sigaction = switch (native_os) {
|
||||||
flags: c_uint,
|
flags: c_uint,
|
||||||
restorer: ?*const fn () callconv(.c) void = null,
|
restorer: ?*const fn () callconv(.c) void = null,
|
||||||
mask: sigset_t,
|
mask: sigset_t,
|
||||||
} else linux.Sigaction,
|
} else common_linux_Sigaction,
|
||||||
else => linux.Sigaction,
|
else => common_linux_Sigaction,
|
||||||
},
|
},
|
||||||
.emscripten => emscripten.Sigaction,
|
.emscripten => emscripten.Sigaction,
|
||||||
.netbsd, .macos, .ios, .tvos, .watchos, .visionos => extern struct {
|
.netbsd, .macos, .ios, .tvos, .watchos, .visionos => extern struct {
|
||||||
|
|
@ -4518,27 +4533,18 @@ pub const siginfo_t = switch (native_os) {
|
||||||
else => void,
|
else => void,
|
||||||
};
|
};
|
||||||
pub const sigset_t = switch (native_os) {
|
pub const sigset_t = switch (native_os) {
|
||||||
.linux => linux.sigset_t,
|
.linux => [1024 / @bitSizeOf(c_ulong)]c_ulong, // glibc and musl present a 1024-bit sigset_t, while kernel's is 128-bit or less.
|
||||||
.emscripten => emscripten.sigset_t,
|
.emscripten => emscripten.sigset_t,
|
||||||
// https://github.com/SerenityOS/serenity/blob/ec492a1a0819e6239ea44156825c4ee7234ca3db/Kernel/API/POSIX/signal.h#L19
|
// https://github.com/SerenityOS/serenity/blob/ec492a1a0819e6239ea44156825c4ee7234ca3db/Kernel/API/POSIX/signal.h#L19
|
||||||
.openbsd, .macos, .ios, .tvos, .watchos, .visionos, .serenity => u32,
|
.openbsd, .serenity => u32,
|
||||||
|
.macos, .ios, .tvos, .watchos, .visionos => darwin.sigset_t,
|
||||||
.dragonfly, .netbsd, .solaris, .illumos, .freebsd => extern struct {
|
.dragonfly, .netbsd, .solaris, .illumos, .freebsd => extern struct {
|
||||||
__bits: [SIG.WORDS]u32,
|
__bits: [SIG.WORDS]u32,
|
||||||
},
|
},
|
||||||
.haiku => u64,
|
.haiku => u64,
|
||||||
else => u0,
|
else => u0,
|
||||||
};
|
};
|
||||||
pub const empty_sigset: sigset_t = switch (native_os) {
|
|
||||||
.linux => linux.empty_sigset,
|
|
||||||
.emscripten => emscripten.empty_sigset,
|
|
||||||
.dragonfly, .netbsd, .solaris, .illumos, .freebsd => .{ .__bits = [_]u32{0} ** SIG.WORDS },
|
|
||||||
else => 0,
|
|
||||||
};
|
|
||||||
pub const filled_sigset = switch (native_os) {
|
|
||||||
.linux => linux.filled_sigset,
|
|
||||||
.haiku => ~@as(sigset_t, 0),
|
|
||||||
else => 0,
|
|
||||||
};
|
|
||||||
pub const sigval = switch (native_os) {
|
pub const sigval = switch (native_os) {
|
||||||
.linux => linux.sigval,
|
.linux => linux.sigval,
|
||||||
// https://github.com/SerenityOS/serenity/blob/ec492a1a0819e6239ea44156825c4ee7234ca3db/Kernel/API/POSIX/signal.h#L22-L25
|
// https://github.com/SerenityOS/serenity/blob/ec492a1a0819e6239ea44156825c4ee7234ca3db/Kernel/API/POSIX/signal.h#L22-L25
|
||||||
|
|
@ -6665,7 +6671,7 @@ pub const timezone = switch (native_os) {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const ucontext_t = switch (native_os) {
|
pub const ucontext_t = switch (native_os) {
|
||||||
.linux => linux.ucontext_t,
|
.linux => linux.ucontext_t, // std.os.linux.ucontext_t is currently glibc-compatible, but it should probably not be.
|
||||||
.emscripten => emscripten.ucontext_t,
|
.emscripten => emscripten.ucontext_t,
|
||||||
.macos, .ios, .tvos, .watchos, .visionos => extern struct {
|
.macos, .ios, .tvos, .watchos, .visionos => extern struct {
|
||||||
onstack: c_int,
|
onstack: c_int,
|
||||||
|
|
@ -9596,6 +9602,7 @@ pub const NSIG = switch (native_os) {
|
||||||
.windows => 23,
|
.windows => 23,
|
||||||
.haiku => 65,
|
.haiku => 65,
|
||||||
.netbsd, .freebsd => 32,
|
.netbsd, .freebsd => 32,
|
||||||
|
.macos => darwin.NSIG,
|
||||||
.solaris, .illumos => 75,
|
.solaris, .illumos => 75,
|
||||||
// https://github.com/SerenityOS/serenity/blob/046c23f567a17758d762a33bdf04bacbfd088f9f/Kernel/API/POSIX/signal_numbers.h#L42
|
// https://github.com/SerenityOS/serenity/blob/046c23f567a17758d762a33bdf04bacbfd088f9f/Kernel/API/POSIX/signal_numbers.h#L42
|
||||||
.openbsd, .serenity => 33,
|
.openbsd, .serenity => 33,
|
||||||
|
|
@ -10345,6 +10352,11 @@ pub const sigfillset = switch (native_os) {
|
||||||
else => private.sigfillset,
|
else => private.sigfillset,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const sigaddset = private.sigaddset;
|
||||||
|
pub const sigemptyset = private.sigemptyset;
|
||||||
|
pub const sigdelset = private.sigdelset;
|
||||||
|
pub const sigismember = private.sigismember;
|
||||||
|
|
||||||
pub const sigprocmask = switch (native_os) {
|
pub const sigprocmask = switch (native_os) {
|
||||||
.netbsd => private.__sigprocmask14,
|
.netbsd => private.__sigprocmask14,
|
||||||
else => private.sigprocmask,
|
else => private.sigprocmask,
|
||||||
|
|
@ -11025,7 +11037,6 @@ pub const pthread_attr_set_qos_class_np = darwin.pthread_attr_set_qos_class_np;
|
||||||
pub const pthread_get_qos_class_np = darwin.pthread_get_qos_class_np;
|
pub const pthread_get_qos_class_np = darwin.pthread_get_qos_class_np;
|
||||||
pub const pthread_set_qos_class_self_np = darwin.pthread_set_qos_class_self_np;
|
pub const pthread_set_qos_class_self_np = darwin.pthread_set_qos_class_self_np;
|
||||||
pub const ptrace = darwin.ptrace;
|
pub const ptrace = darwin.ptrace;
|
||||||
pub const sigaddset = darwin.sigaddset;
|
|
||||||
pub const task_for_pid = darwin.task_for_pid;
|
pub const task_for_pid = darwin.task_for_pid;
|
||||||
pub const task_get_exception_ports = darwin.task_get_exception_ports;
|
pub const task_get_exception_ports = darwin.task_get_exception_ports;
|
||||||
pub const task_info = darwin.task_info;
|
pub const task_info = darwin.task_info;
|
||||||
|
|
@ -11148,7 +11159,11 @@ const private = struct {
|
||||||
extern "c" fn sched_yield() c_int;
|
extern "c" fn sched_yield() c_int;
|
||||||
extern "c" fn sendfile(out_fd: fd_t, in_fd: fd_t, offset: ?*off_t, count: usize) isize;
|
extern "c" fn sendfile(out_fd: fd_t, in_fd: fd_t, offset: ?*off_t, count: usize) isize;
|
||||||
extern "c" fn sigaction(sig: c_int, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) c_int;
|
extern "c" fn sigaction(sig: c_int, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) c_int;
|
||||||
extern "c" fn sigfillset(set: ?*sigset_t) void;
|
extern "c" fn sigdelset(set: ?*sigset_t, signo: c_int) c_int;
|
||||||
|
extern "c" fn sigaddset(set: ?*sigset_t, signo: c_int) c_int;
|
||||||
|
extern "c" fn sigfillset(set: ?*sigset_t) c_int;
|
||||||
|
extern "c" fn sigemptyset(set: ?*sigset_t) c_int;
|
||||||
|
extern "c" fn sigismember(set: ?*const sigset_t, signo: c_int) c_int;
|
||||||
extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;
|
extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;
|
||||||
extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int;
|
extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int;
|
||||||
extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *Stat) c_int;
|
extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *Stat) c_int;
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ const mode_t = std.c.mode_t;
|
||||||
const off_t = std.c.off_t;
|
const off_t = std.c.off_t;
|
||||||
const pid_t = std.c.pid_t;
|
const pid_t = std.c.pid_t;
|
||||||
const pthread_attr_t = std.c.pthread_attr_t;
|
const pthread_attr_t = std.c.pthread_attr_t;
|
||||||
const sigset_t = std.c.sigset_t;
|
|
||||||
const timespec = std.c.timespec;
|
const timespec = std.c.timespec;
|
||||||
const sf_hdtr = std.c.sf_hdtr;
|
const sf_hdtr = std.c.sf_hdtr;
|
||||||
|
|
||||||
|
|
@ -840,9 +839,11 @@ pub extern "c" fn sendfile(
|
||||||
flags: u32,
|
flags: u32,
|
||||||
) c_int;
|
) c_int;
|
||||||
|
|
||||||
pub fn sigaddset(set: *sigset_t, signo: u5) void {
|
// https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/sys/_types.h#L74
|
||||||
set.* |= @as(u32, 1) << (signo - 1);
|
pub const sigset_t = u32;
|
||||||
}
|
|
||||||
|
// https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/sys/signal.h#L76
|
||||||
|
pub const NSIG = 32;
|
||||||
|
|
||||||
pub const qos_class_t = enum(c_uint) {
|
pub const qos_class_t = enum(c_uint) {
|
||||||
/// highest priority QOS class for critical tasks
|
/// highest priority QOS class for critical tasks
|
||||||
|
|
|
||||||
|
|
@ -1387,12 +1387,11 @@ pub fn attachSegfaultHandler() void {
|
||||||
windows_segfault_handle = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows);
|
windows_segfault_handle = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var act = posix.Sigaction{
|
const act = posix.Sigaction{
|
||||||
.handler = .{ .sigaction = handleSegfaultPosix },
|
.handler = .{ .sigaction = handleSegfaultPosix },
|
||||||
.mask = posix.empty_sigset,
|
.mask = posix.sigemptyset(),
|
||||||
.flags = (posix.SA.SIGINFO | posix.SA.RESTART | posix.SA.RESETHAND),
|
.flags = (posix.SA.SIGINFO | posix.SA.RESTART | posix.SA.RESETHAND),
|
||||||
};
|
};
|
||||||
|
|
||||||
updateSegfaultHandler(&act);
|
updateSegfaultHandler(&act);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1404,9 +1403,9 @@ fn resetSegfaultHandler() void {
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var act = posix.Sigaction{
|
const act = posix.Sigaction{
|
||||||
.handler = .{ .handler = posix.SIG.DFL },
|
.handler = .{ .handler = posix.SIG.DFL },
|
||||||
.mask = posix.empty_sigset,
|
.mask = posix.sigemptyset(),
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
};
|
};
|
||||||
updateSegfaultHandler(&act);
|
updateSegfaultHandler(&act);
|
||||||
|
|
|
||||||
|
|
@ -560,7 +560,9 @@ pub const Sigaction = extern struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const sigset_t = [1024 / 32]u32;
|
pub const sigset_t = [1024 / 32]u32;
|
||||||
pub const empty_sigset = [_]u32{0} ** @typeInfo(sigset_t).array.len;
|
pub fn sigemptyset() sigset_t {
|
||||||
|
return [_]u32{0} ** @typeInfo(sigset_t).array.len;
|
||||||
|
}
|
||||||
pub const siginfo_t = extern struct {
|
pub const siginfo_t = extern struct {
|
||||||
signo: i32,
|
signo: i32,
|
||||||
errno: i32,
|
errno: i32,
|
||||||
|
|
|
||||||
|
|
@ -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,35 @@ 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.
|
/// Zig's version of sigemptyset. Returns initialized sigset_t.
|
||||||
pub const empty_sigset: sigset_t = [_]u32{0} ** sigset_len;
|
pub fn sigemptyset() sigset_t {
|
||||||
|
return [_]SigsetElement{0} ** sigset_len;
|
||||||
|
}
|
||||||
|
|
||||||
pub const filled_sigset: sigset_t = [_]u32{0x7fff_ffff} ++ [_]u32{0} ** (sigset_len - 1);
|
/// Zig's version of sigfillset. Returns initalized sigset_t.
|
||||||
|
pub fn sigfillset() sigset_t {
|
||||||
|
return [_]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)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3487,6 +3499,7 @@ pub const SIG = if (is_mips) struct {
|
||||||
pub const UNBLOCK = 2;
|
pub const UNBLOCK = 2;
|
||||||
pub const SETMASK = 3;
|
pub const SETMASK = 3;
|
||||||
|
|
||||||
|
// https://github.com/torvalds/linux/blob/ca91b9500108d4cf083a635c2e11c884d5dd20ea/arch/mips/include/uapi/asm/signal.h#L25
|
||||||
pub const HUP = 1;
|
pub const HUP = 1;
|
||||||
pub const INT = 2;
|
pub const INT = 2;
|
||||||
pub const QUIT = 3;
|
pub const QUIT = 3;
|
||||||
|
|
@ -3494,33 +3507,32 @@ pub const SIG = if (is_mips) struct {
|
||||||
pub const TRAP = 5;
|
pub const TRAP = 5;
|
||||||
pub const ABRT = 6;
|
pub const ABRT = 6;
|
||||||
pub const IOT = ABRT;
|
pub const IOT = ABRT;
|
||||||
pub const BUS = 7;
|
pub const EMT = 7;
|
||||||
pub const FPE = 8;
|
pub const FPE = 8;
|
||||||
pub const KILL = 9;
|
pub const KILL = 9;
|
||||||
pub const USR1 = 10;
|
pub const BUS = 10;
|
||||||
pub const SEGV = 11;
|
pub const SEGV = 11;
|
||||||
pub const USR2 = 12;
|
pub const SYS = 12;
|
||||||
pub const PIPE = 13;
|
pub const PIPE = 13;
|
||||||
pub const ALRM = 14;
|
pub const ALRM = 14;
|
||||||
pub const TERM = 15;
|
pub const TERM = 15;
|
||||||
pub const STKFLT = 16;
|
pub const USR1 = 16;
|
||||||
pub const CHLD = 17;
|
pub const USR2 = 17;
|
||||||
pub const CONT = 18;
|
pub const CHLD = 18;
|
||||||
pub const STOP = 19;
|
pub const PWR = 19;
|
||||||
pub const TSTP = 20;
|
pub const WINCH = 20;
|
||||||
pub const TTIN = 21;
|
pub const URG = 21;
|
||||||
pub const TTOU = 22;
|
pub const IO = 22;
|
||||||
pub const URG = 23;
|
pub const POLL = IO;
|
||||||
pub const XCPU = 24;
|
pub const STOP = 23;
|
||||||
pub const XFSZ = 25;
|
pub const TSTP = 24;
|
||||||
pub const VTALRM = 26;
|
pub const CONT = 25;
|
||||||
pub const PROF = 27;
|
pub const TTIN = 26;
|
||||||
pub const WINCH = 28;
|
pub const TTOU = 27;
|
||||||
pub const IO = 29;
|
pub const VTALRM = 28;
|
||||||
pub const POLL = 29;
|
pub const PROF = 29;
|
||||||
pub const PWR = 30;
|
pub const XCPU = 30;
|
||||||
pub const SYS = 31;
|
pub const XFZ = 31;
|
||||||
pub const UNUSED = SIG.SYS;
|
|
||||||
|
|
||||||
pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
|
pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
|
||||||
pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
|
pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
|
||||||
|
|
@ -5479,38 +5491,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 +5526,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 {
|
||||||
|
|
|
||||||
|
|
@ -289,7 +289,7 @@ pub const ucontext_t = extern struct {
|
||||||
flags: usize,
|
flags: usize,
|
||||||
link: ?*ucontext_t,
|
link: ?*ucontext_t,
|
||||||
stack: stack_t,
|
stack: stack_t,
|
||||||
sigmask: sigset_t,
|
sigmask: [1024 / @bitSizeOf(c_ulong)]c_ulong, // Currently a libc-compatible (1024-bit) sigmask
|
||||||
mcontext: mcontext_t,
|
mcontext: mcontext_t,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -337,7 +337,7 @@ pub const ucontext_t = extern struct {
|
||||||
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 libc-compatible (1024-bit) sigmask
|
||||||
regspace: [64]u64,
|
regspace: [64]u64,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -264,8 +264,7 @@ pub const ucontext_t = extern struct {
|
||||||
flags: c_ulong,
|
flags: c_ulong,
|
||||||
link: ?*ucontext_t,
|
link: ?*ucontext_t,
|
||||||
stack: stack_t,
|
stack: stack_t,
|
||||||
sigmask: sigset_t,
|
sigmask: [1024 / @bitSizeOf(c_ulong)]c_ulong, // Currently a libc-compatible (1024-bit) sigmask
|
||||||
_pad: [1024 / 8 - @sizeOf(sigset_t)]u8,
|
|
||||||
mcontext: mcontext_t,
|
mcontext: mcontext_t,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -341,7 +341,7 @@ pub const ucontext_t = extern struct {
|
||||||
stack: stack_t,
|
stack: stack_t,
|
||||||
pad: [7]i32,
|
pad: [7]i32,
|
||||||
regs: *mcontext_t,
|
regs: *mcontext_t,
|
||||||
sigmask: sigset_t,
|
sigmask: [1024 / @bitSizeOf(c_ulong)]c_ulong, // Currently a libc-compatible (1024-bit) sigmask
|
||||||
pad2: [3]i32,
|
pad2: [3]i32,
|
||||||
mcontext: mcontext_t,
|
mcontext: mcontext_t,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -337,7 +337,7 @@ pub const ucontext_t = extern struct {
|
||||||
flags: u32,
|
flags: u32,
|
||||||
link: ?*ucontext_t,
|
link: ?*ucontext_t,
|
||||||
stack: stack_t,
|
stack: stack_t,
|
||||||
sigmask: sigset_t,
|
sigmask: [1024 / @bitSizeOf(c_ulong)]c_ulong, // Currently a libc-compatible (1024-bit) sigmask
|
||||||
mcontext: mcontext_t,
|
mcontext: mcontext_t,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -273,7 +273,7 @@ pub const ucontext_t = extern struct {
|
||||||
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 libc-compatible (1024-bit) sigmask
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const mcontext_t = extern struct {
|
pub const mcontext_t = extern struct {
|
||||||
|
|
|
||||||
|
|
@ -454,7 +454,7 @@ pub const ucontext_t = extern struct {
|
||||||
sigmask: u64,
|
sigmask: u64,
|
||||||
mcontext: mcontext_t,
|
mcontext: mcontext_t,
|
||||||
stack: stack_t,
|
stack: stack_t,
|
||||||
sigset: sigset_t,
|
sigset: [1024 / @bitSizeOf(c_ulong)]c_ulong, // Currently a libc-compatible (1024-bit) sigmask
|
||||||
};
|
};
|
||||||
|
|
||||||
/// TODO
|
/// TODO
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,9 @@ test "fadvise" {
|
||||||
}
|
}
|
||||||
|
|
||||||
test "sigset_t" {
|
test "sigset_t" {
|
||||||
var sigset = linux.empty_sigset;
|
std.debug.assert(@sizeOf(linux.sigset_t) == (linux.NSIG / 8));
|
||||||
|
|
||||||
|
var sigset = linux.sigemptyset();
|
||||||
|
|
||||||
// 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
|
||||||
// remove them all, and then see that none are set.
|
// remove them all, and then see that none are set.
|
||||||
|
|
@ -138,7 +140,6 @@ 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.empty_sigset, @truncate(i)), false);
|
|
||||||
}
|
}
|
||||||
for (1..linux.NSIG) |i| {
|
for (1..linux.NSIG) |i| {
|
||||||
linux.sigdelset(&sigset, @truncate(i));
|
linux.sigdelset(&sigset, @truncate(i));
|
||||||
|
|
@ -147,22 +148,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);
|
||||||
|
if (sigset_len > 1) {
|
||||||
try expectEqual(sigset[1], 0);
|
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);
|
||||||
|
if (sigset_len > 1) {
|
||||||
try expectEqual(sigset[1], 0);
|
try expectEqual(sigset[1], 0);
|
||||||
|
}
|
||||||
|
|
||||||
linux.sigaddset(&sigset, 36);
|
linux.sigaddset(&sigset, 36);
|
||||||
|
if (sigset_elemis64) {
|
||||||
|
try expectEqual(sigset[0], 0x8_4000_0001);
|
||||||
|
} else {
|
||||||
try expectEqual(sigset[0], 0x4000_0001);
|
try expectEqual(sigset[0], 0x4000_0001);
|
||||||
try expectEqual(sigset[1], 0x8);
|
try expectEqual(sigset[1], 0x8);
|
||||||
|
}
|
||||||
|
|
||||||
linux.sigaddset(&sigset, 64);
|
linux.sigaddset(&sigset, 64);
|
||||||
|
if (sigset_elemis64) {
|
||||||
|
try expectEqual(sigset[0], 0x8000_0008_4000_0001);
|
||||||
|
} else {
|
||||||
try expectEqual(sigset[0], 0x4000_0001);
|
try expectEqual(sigset[0], 0x4000_0001);
|
||||||
try expectEqual(sigset[1], 0x8000_0008);
|
try expectEqual(sigset[1], 0x8000_0008);
|
||||||
try expectEqual(sigset[2], 0);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "sigfillset" {
|
||||||
|
// unlike the C library, all the signals are set in the kernel-level fillset
|
||||||
|
const sigset = linux.sigfillset();
|
||||||
|
for (1..linux.NSIG) |i| {
|
||||||
|
try expectEqual(linux.sigismember(&sigset, @truncate(i)), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "sigemptyset" {
|
||||||
|
const sigset = linux.sigemptyset();
|
||||||
|
for (1..linux.NSIG) |i| {
|
||||||
|
try expectEqual(linux.sigismember(&sigset, @truncate(i)), false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "sysinfo" {
|
test "sysinfo" {
|
||||||
|
|
|
||||||
|
|
@ -350,7 +350,7 @@ pub const ucontext_t = extern struct {
|
||||||
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 libc-compatible (1024-bit) sigmask
|
||||||
regspace: [64]u64,
|
regspace: [64]u64,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,6 @@ pub const SIG = struct {
|
||||||
pub const TTOU = 20;
|
pub const TTOU = 20;
|
||||||
};
|
};
|
||||||
pub const sigset_t = c_long;
|
pub const sigset_t = c_long;
|
||||||
pub const empty_sigset = 0;
|
|
||||||
pub const siginfo_t = c_long;
|
pub const siginfo_t = c_long;
|
||||||
// TODO plan9 doesn't have sigaction_fn. Sigaction is not a union, but we include it here to be compatible.
|
// TODO plan9 doesn't have sigaction_fn. Sigaction is not a union, but we include it here to be compatible.
|
||||||
pub const Sigaction = extern struct {
|
pub const Sigaction = extern struct {
|
||||||
|
|
@ -199,6 +198,10 @@ pub const Sigaction = extern struct {
|
||||||
pub const AT = struct {
|
pub const AT = struct {
|
||||||
pub const FDCWD = -100; // we just make up a constant; FDCWD and openat don't actually exist in plan9
|
pub const FDCWD = -100; // we just make up a constant; FDCWD and openat don't actually exist in plan9
|
||||||
};
|
};
|
||||||
|
// Plan 9 doesn't do signals. This is just needed to get through start.zig.
|
||||||
|
pub fn sigemptyset() sigset_t {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
// TODO implement sigaction
|
// TODO implement sigaction
|
||||||
// right now it is just a shim to allow using start.zig code
|
// right now it is just a shim to allow using start.zig code
|
||||||
pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) usize {
|
pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) usize {
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,7 @@ pub const MREMAP = system.MREMAP;
|
||||||
pub const MSF = system.MSF;
|
pub const MSF = system.MSF;
|
||||||
pub const MSG = system.MSG;
|
pub const MSG = system.MSG;
|
||||||
pub const NAME_MAX = system.NAME_MAX;
|
pub const NAME_MAX = system.NAME_MAX;
|
||||||
|
pub const NSIG = system.NSIG;
|
||||||
pub const O = system.O;
|
pub const O = system.O;
|
||||||
pub const PATH_MAX = system.PATH_MAX;
|
pub const PATH_MAX = system.PATH_MAX;
|
||||||
pub const POLL = system.POLL;
|
pub const POLL = system.POLL;
|
||||||
|
|
@ -126,10 +127,8 @@ pub const timerfd_clockid_t = system.timerfd_clockid_t;
|
||||||
pub const cpu_set_t = system.cpu_set_t;
|
pub const cpu_set_t = system.cpu_set_t;
|
||||||
pub const dev_t = system.dev_t;
|
pub const dev_t = system.dev_t;
|
||||||
pub const dl_phdr_info = system.dl_phdr_info;
|
pub const dl_phdr_info = system.dl_phdr_info;
|
||||||
pub const empty_sigset = system.empty_sigset;
|
|
||||||
pub const fd_t = system.fd_t;
|
pub const fd_t = system.fd_t;
|
||||||
pub const file_obj = system.file_obj;
|
pub const file_obj = system.file_obj;
|
||||||
pub const filled_sigset = system.filled_sigset;
|
|
||||||
pub const gid_t = system.gid_t;
|
pub const gid_t = system.gid_t;
|
||||||
pub const ifreq = system.ifreq;
|
pub const ifreq = system.ifreq;
|
||||||
pub const ino_t = system.ino_t;
|
pub const ino_t = system.ino_t;
|
||||||
|
|
@ -678,7 +677,8 @@ pub fn abort() noreturn {
|
||||||
raise(SIG.ABRT) catch {};
|
raise(SIG.ABRT) catch {};
|
||||||
|
|
||||||
// Disable all signal handlers.
|
// Disable all signal handlers.
|
||||||
sigprocmask(SIG.BLOCK, &linux.all_mask, null);
|
const filledset = linux.sigfillset();
|
||||||
|
sigprocmask(SIG.BLOCK, &filledset, null);
|
||||||
|
|
||||||
// Only one thread may proceed to the rest of abort().
|
// Only one thread may proceed to the rest of abort().
|
||||||
if (!builtin.single_threaded) {
|
if (!builtin.single_threaded) {
|
||||||
|
|
@ -691,14 +691,15 @@ pub fn abort() noreturn {
|
||||||
// Install default handler so that the tkill below will terminate.
|
// Install default handler so that the tkill below will terminate.
|
||||||
const sigact = Sigaction{
|
const sigact = Sigaction{
|
||||||
.handler = .{ .handler = SIG.DFL },
|
.handler = .{ .handler = SIG.DFL },
|
||||||
.mask = empty_sigset,
|
.mask = sigemptyset(),
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
};
|
};
|
||||||
sigaction(SIG.ABRT, &sigact, null);
|
sigaction(SIG.ABRT, &sigact, null);
|
||||||
|
|
||||||
_ = linux.tkill(linux.gettid(), SIG.ABRT);
|
_ = linux.tkill(linux.gettid(), SIG.ABRT);
|
||||||
|
|
||||||
const sigabrtmask: linux.sigset_t = [_]u32{0} ** 31 ++ [_]u32{1 << (SIG.ABRT - 1)};
|
var sigabrtmask = sigemptyset();
|
||||||
|
sigaddset(&sigabrtmask, SIG.ABRT);
|
||||||
sigprocmask(SIG.UNBLOCK, &sigabrtmask, null);
|
sigprocmask(SIG.UNBLOCK, &sigabrtmask, null);
|
||||||
|
|
||||||
// Beyond this point should be unreachable.
|
// Beyond this point should be unreachable.
|
||||||
|
|
@ -723,18 +724,13 @@ pub fn raise(sig: u8) RaiseError!void {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (native_os == .linux) {
|
if (native_os == .linux) {
|
||||||
// https://git.musl-libc.org/cgit/musl/commit/?id=0bed7e0acfd34e3fb63ca0e4d99b7592571355a9
|
// Block all signals so a `fork` (from a signal handler) between the gettid() and kill() syscalls
|
||||||
//
|
// cannot trigger an extra, unexpected, inter-process signal. Signal paranoia inherited from Musl.
|
||||||
// Unlike musl, libc-less Zig std does not have any internal signals for implementation purposes, so we
|
const filled = linux.sigfillset();
|
||||||
// need to block all signals on the assumption that any of them could potentially fork() in a handler.
|
var orig: sigset_t = undefined;
|
||||||
var set: sigset_t = undefined;
|
sigprocmask(SIG.BLOCK, &filled, &orig);
|
||||||
sigprocmask(SIG.BLOCK, &linux.all_mask, &set);
|
const rc = linux.tkill(linux.gettid(), sig);
|
||||||
|
sigprocmask(SIG.SETMASK, &orig, null);
|
||||||
const tid = linux.gettid();
|
|
||||||
const rc = linux.tkill(tid, sig);
|
|
||||||
|
|
||||||
// restore signal mask
|
|
||||||
sigprocmask(SIG.SETMASK, &set, null);
|
|
||||||
|
|
||||||
switch (errno(rc)) {
|
switch (errno(rc)) {
|
||||||
.SUCCESS => return,
|
.SUCCESS => return,
|
||||||
|
|
@ -5818,8 +5814,63 @@ pub fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) SigaltstackError!void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return a filled sigset_t.
|
||||||
|
pub fn sigfillset() sigset_t {
|
||||||
|
if (builtin.link_libc) {
|
||||||
|
var set: sigset_t = undefined;
|
||||||
|
switch (errno(system.sigfillset(&set))) {
|
||||||
|
.SUCCESS => return set,
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return system.sigfillset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return an empty sigset_t.
|
||||||
|
pub fn sigemptyset() sigset_t {
|
||||||
|
if (builtin.link_libc) {
|
||||||
|
var set: sigset_t = undefined;
|
||||||
|
switch (errno(system.sigemptyset(&set))) {
|
||||||
|
.SUCCESS => return set,
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return system.sigemptyset();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sigaddset(set: *sigset_t, sig: u8) void {
|
||||||
|
if (builtin.link_libc) {
|
||||||
|
switch (errno(system.sigaddset(set, sig))) {
|
||||||
|
.SUCCESS => return,
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
system.sigaddset(set, sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sigdelset(set: *sigset_t, sig: u8) void {
|
||||||
|
if (builtin.link_libc) {
|
||||||
|
switch (errno(system.sigdelset(set, sig))) {
|
||||||
|
.SUCCESS => return,
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
system.sigdelset(set, sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sigismember(set: *const sigset_t, sig: u8) bool {
|
||||||
|
if (builtin.link_libc) {
|
||||||
|
const rc = system.sigismember(set, sig);
|
||||||
|
switch (errno(rc)) {
|
||||||
|
.SUCCESS => return rc == 1,
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return system.sigismember(set, sig);
|
||||||
|
}
|
||||||
|
|
||||||
/// Examine and change a signal action.
|
/// Examine and change a signal action.
|
||||||
pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) void {
|
pub fn sigaction(sig: u8, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) void {
|
||||||
switch (errno(system.sigaction(sig, act, oact))) {
|
switch (errno(system.sigaction(sig, act, oact))) {
|
||||||
.SUCCESS => return,
|
.SUCCESS => return,
|
||||||
// EINVAL means the signal is either invalid or some signal that cannot have its action
|
// EINVAL means the signal is either invalid or some signal that cannot have its action
|
||||||
|
|
|
||||||
|
|
@ -859,12 +859,61 @@ test "shutdown socket" {
|
||||||
std.net.Stream.close(.{ .handle = sock });
|
std.net.Stream.close(.{ .handle = sock });
|
||||||
}
|
}
|
||||||
|
|
||||||
test "sigaction" {
|
test "sigset empty/full" {
|
||||||
if (native_os == .wasi or native_os == .windows)
|
if (native_os == .wasi or native_os == .windows)
|
||||||
return error.SkipZigTest;
|
return error.SkipZigTest;
|
||||||
|
|
||||||
// https://github.com/ziglang/zig/issues/7427
|
var set: posix.sigset_t = posix.sigemptyset();
|
||||||
if (native_os == .linux and builtin.target.cpu.arch == .x86)
|
for (1..posix.NSIG) |i| {
|
||||||
|
try expectEqual(false, posix.sigismember(&set, @truncate(i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// The C library can reserve some (unnamed) signals, so can't check the full
|
||||||
|
// NSIG set is defined, but just test a couple:
|
||||||
|
set = posix.sigfillset();
|
||||||
|
try expectEqual(true, posix.sigismember(&set, @truncate(posix.SIG.CHLD)));
|
||||||
|
try expectEqual(true, posix.sigismember(&set, @truncate(posix.SIG.INT)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some signals (32 - 34 on glibc/musl) are not allowed to be added to a
|
||||||
|
// sigset by the C library, so avoid testing them.
|
||||||
|
fn reserved_signo(i: usize) bool {
|
||||||
|
return builtin.link_libc and (i >= 32 and i <= 34);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "sigset add/del" {
|
||||||
|
if (native_os == .wasi or native_os == .windows)
|
||||||
|
return error.SkipZigTest;
|
||||||
|
|
||||||
|
var sigset: posix.sigset_t = posix.sigemptyset();
|
||||||
|
|
||||||
|
// See that none are set, then set each one, see that they're all set, then
|
||||||
|
// remove them all, and then see that none are set.
|
||||||
|
for (1..posix.NSIG) |i| {
|
||||||
|
try expectEqual(false, posix.sigismember(&sigset, @truncate(i)));
|
||||||
|
}
|
||||||
|
for (1..posix.NSIG) |i| {
|
||||||
|
if (!reserved_signo(i)) {
|
||||||
|
posix.sigaddset(&sigset, @truncate(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (1..posix.NSIG) |i| {
|
||||||
|
if (!reserved_signo(i)) {
|
||||||
|
try expectEqual(true, posix.sigismember(&sigset, @truncate(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (1..posix.NSIG) |i| {
|
||||||
|
if (!reserved_signo(i)) {
|
||||||
|
posix.sigdelset(&sigset, @truncate(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (1..posix.NSIG) |i| {
|
||||||
|
try expectEqual(false, posix.sigismember(&sigset, @truncate(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "sigaction" {
|
||||||
|
if (native_os == .wasi or native_os == .windows)
|
||||||
return error.SkipZigTest;
|
return error.SkipZigTest;
|
||||||
|
|
||||||
// https://github.com/ziglang/zig/issues/15381
|
// https://github.com/ziglang/zig/issues/15381
|
||||||
|
|
@ -872,66 +921,138 @@ test "sigaction" {
|
||||||
return error.SkipZigTest;
|
return error.SkipZigTest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const test_signo = posix.SIG.URG; // URG only because it is ignored by default in debuggers
|
||||||
|
|
||||||
const S = struct {
|
const S = struct {
|
||||||
var handler_called_count: u32 = 0;
|
var handler_called_count: u32 = 0;
|
||||||
|
|
||||||
fn handler(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*anyopaque) callconv(.c) void {
|
fn handler(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*anyopaque) callconv(.c) void {
|
||||||
_ = ctx_ptr;
|
_ = ctx_ptr;
|
||||||
// Check that we received the correct signal.
|
// Check that we received the correct signal.
|
||||||
switch (native_os) {
|
const info_sig = switch (native_os) {
|
||||||
.netbsd => {
|
.netbsd => info.info.signo,
|
||||||
if (sig == posix.SIG.USR1 and sig == info.info.signo)
|
else => info.signo,
|
||||||
|
};
|
||||||
|
if (sig == test_signo and sig == info_sig) {
|
||||||
handler_called_count += 1;
|
handler_called_count += 1;
|
||||||
},
|
|
||||||
else => {
|
|
||||||
if (sig == posix.SIG.USR1 and sig == info.signo)
|
|
||||||
handler_called_count += 1;
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var sa: posix.Sigaction = .{
|
var sa: posix.Sigaction = .{
|
||||||
.handler = .{ .sigaction = &S.handler },
|
.handler = .{ .sigaction = &S.handler },
|
||||||
.mask = posix.empty_sigset,
|
.mask = posix.sigemptyset(),
|
||||||
.flags = posix.SA.SIGINFO | posix.SA.RESETHAND,
|
.flags = posix.SA.SIGINFO | posix.SA.RESETHAND,
|
||||||
};
|
};
|
||||||
|
|
||||||
var old_sa: posix.Sigaction = undefined;
|
var old_sa: posix.Sigaction = undefined;
|
||||||
|
|
||||||
// Install the new signal handler.
|
// Install the new signal handler.
|
||||||
posix.sigaction(posix.SIG.USR1, &sa, null);
|
posix.sigaction(test_signo, &sa, null);
|
||||||
|
|
||||||
// Check that we can read it back correctly.
|
// Check that we can read it back correctly.
|
||||||
posix.sigaction(posix.SIG.USR1, null, &old_sa);
|
posix.sigaction(test_signo, null, &old_sa);
|
||||||
try testing.expectEqual(&S.handler, old_sa.handler.sigaction.?);
|
try testing.expectEqual(&S.handler, old_sa.handler.sigaction.?);
|
||||||
try testing.expect((old_sa.flags & posix.SA.SIGINFO) != 0);
|
try testing.expect((old_sa.flags & posix.SA.SIGINFO) != 0);
|
||||||
|
|
||||||
// Invoke the handler.
|
// Invoke the handler.
|
||||||
try posix.raise(posix.SIG.USR1);
|
try posix.raise(test_signo);
|
||||||
try testing.expect(S.handler_called_count == 1);
|
try testing.expectEqual(1, S.handler_called_count);
|
||||||
|
|
||||||
// Check if passing RESETHAND correctly reset the handler to SIG_DFL
|
// Check if passing RESETHAND correctly reset the handler to SIG_DFL
|
||||||
posix.sigaction(posix.SIG.USR1, null, &old_sa);
|
posix.sigaction(test_signo, null, &old_sa);
|
||||||
try testing.expectEqual(posix.SIG.DFL, old_sa.handler.handler);
|
try testing.expectEqual(posix.SIG.DFL, old_sa.handler.handler);
|
||||||
|
|
||||||
// Reinstall the signal w/o RESETHAND and re-raise
|
// Reinstall the signal w/o RESETHAND and re-raise
|
||||||
sa.flags = posix.SA.SIGINFO;
|
sa.flags = posix.SA.SIGINFO;
|
||||||
posix.sigaction(posix.SIG.USR1, &sa, null);
|
posix.sigaction(test_signo, &sa, null);
|
||||||
try posix.raise(posix.SIG.USR1);
|
try posix.raise(test_signo);
|
||||||
try testing.expect(S.handler_called_count == 2);
|
try testing.expectEqual(2, S.handler_called_count);
|
||||||
|
|
||||||
// Now set the signal to ignored
|
// Now set the signal to ignored
|
||||||
sa.handler = .{ .handler = posix.SIG.IGN };
|
sa.handler = .{ .handler = posix.SIG.IGN };
|
||||||
sa.flags = 0;
|
sa.flags = 0;
|
||||||
posix.sigaction(posix.SIG.USR1, &sa, null);
|
posix.sigaction(test_signo, &sa, null);
|
||||||
|
|
||||||
// Re-raise to ensure handler is actually ignored
|
// Re-raise to ensure handler is actually ignored
|
||||||
try posix.raise(posix.SIG.USR1);
|
try posix.raise(test_signo);
|
||||||
try testing.expect(S.handler_called_count == 2);
|
try testing.expectEqual(2, S.handler_called_count);
|
||||||
|
|
||||||
// Ensure that ignored state is returned when querying
|
// Ensure that ignored state is returned when querying
|
||||||
posix.sigaction(posix.SIG.USR1, null, &old_sa);
|
posix.sigaction(test_signo, null, &old_sa);
|
||||||
try testing.expectEqual(posix.SIG.IGN, old_sa.handler.handler.?);
|
try testing.expectEqual(posix.SIG.IGN, old_sa.handler.handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "sigset_t bits" {
|
||||||
|
if (native_os == .wasi or native_os == .windows)
|
||||||
|
return error.SkipZigTest;
|
||||||
|
|
||||||
|
const S = struct {
|
||||||
|
var expected_sig: i32 = undefined;
|
||||||
|
var handler_called_count: u32 = 0;
|
||||||
|
|
||||||
|
fn handler(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*anyopaque) callconv(.c) void {
|
||||||
|
_ = ctx_ptr;
|
||||||
|
|
||||||
|
const info_sig = switch (native_os) {
|
||||||
|
.netbsd => info.info.signo,
|
||||||
|
else => info.signo,
|
||||||
|
};
|
||||||
|
if (sig == expected_sig and sig == info_sig) {
|
||||||
|
handler_called_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const self_pid = posix.system.getpid();
|
||||||
|
|
||||||
|
// To check that sigset_t mapping matches kernel (think u32/u64 mismatches on
|
||||||
|
// big-endian), try sending a blocked signal to make sure the mask matches the
|
||||||
|
// signal. (Send URG and CHLD because they're ignored by default in the
|
||||||
|
// debugger, vs. USR1 or other named signals)
|
||||||
|
inline for ([_]usize{ posix.SIG.URG, posix.SIG.CHLD, 62, 94, 126 }) |test_signo| {
|
||||||
|
if (test_signo >= posix.NSIG) continue;
|
||||||
|
|
||||||
|
S.expected_sig = test_signo;
|
||||||
|
S.handler_called_count = 0;
|
||||||
|
|
||||||
|
const sa: posix.Sigaction = .{
|
||||||
|
.handler = .{ .sigaction = &S.handler },
|
||||||
|
.mask = posix.sigemptyset(),
|
||||||
|
.flags = posix.SA.SIGINFO | posix.SA.RESETHAND,
|
||||||
|
};
|
||||||
|
|
||||||
|
var old_sa: posix.Sigaction = undefined;
|
||||||
|
|
||||||
|
// Install the new signal handler.
|
||||||
|
posix.sigaction(test_signo, &sa, &old_sa);
|
||||||
|
|
||||||
|
// block the signal and see that its delayed until unblocked
|
||||||
|
var block_one: posix.sigset_t = posix.sigemptyset();
|
||||||
|
posix.sigaddset(&block_one, test_signo);
|
||||||
|
posix.sigprocmask(posix.SIG.BLOCK, &block_one, null);
|
||||||
|
|
||||||
|
// qemu maps target signals to host signals 1-to-1, so targets
|
||||||
|
// with more signals than the host will fail to send the signal.
|
||||||
|
const rc = posix.system.kill(self_pid, test_signo);
|
||||||
|
switch (posix.errno(rc)) {
|
||||||
|
.SUCCESS => {
|
||||||
|
// See that the signal is blocked, then unblocked
|
||||||
|
try testing.expectEqual(0, S.handler_called_count);
|
||||||
|
posix.sigprocmask(posix.SIG.UNBLOCK, &block_one, null);
|
||||||
|
try testing.expectEqual(1, S.handler_called_count);
|
||||||
|
},
|
||||||
|
.INVAL => {
|
||||||
|
// Signal won't get delviered. Just clean up.
|
||||||
|
posix.sigprocmask(posix.SIG.UNBLOCK, &block_one, null);
|
||||||
|
try testing.expectEqual(0, S.handler_called_count);
|
||||||
|
},
|
||||||
|
else => |errno| return posix.unexpectedErrno(errno),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore original handler
|
||||||
|
posix.sigaction(test_signo, &old_sa, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "dup & dup2" {
|
test "dup & dup2" {
|
||||||
|
|
|
||||||
|
|
@ -749,7 +749,7 @@ fn maybeIgnoreSigpipe() void {
|
||||||
// Set handler to a noop function instead of `SIG.IGN` to prevent
|
// Set handler to a noop function instead of `SIG.IGN` to prevent
|
||||||
// leaking signal disposition to a child process.
|
// leaking signal disposition to a child process.
|
||||||
.handler = .{ .handler = noopSigHandler },
|
.handler = .{ .handler = noopSigHandler },
|
||||||
.mask = posix.empty_sigset,
|
.mask = posix.sigemptyset(),
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
};
|
};
|
||||||
posix.sigaction(posix.SIG.PIPE, &act, null);
|
posix.sigaction(posix.SIG.PIPE, &act, null);
|
||||||
|
|
|
||||||
|
|
@ -175,12 +175,11 @@ pub fn attachSegfaultHandler() void {
|
||||||
_ = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows);
|
_ = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var act: posix.Sigaction = .{
|
const act: posix.Sigaction = .{
|
||||||
.handler = .{ .sigaction = handleSegfaultPosix },
|
.handler = .{ .sigaction = handleSegfaultPosix },
|
||||||
.mask = posix.empty_sigset,
|
.mask = posix.sigemptyset(),
|
||||||
.flags = (posix.SA.SIGINFO | posix.SA.RESTART | posix.SA.RESETHAND),
|
.flags = (posix.SA.SIGINFO | posix.SA.RESTART | posix.SA.RESETHAND),
|
||||||
};
|
};
|
||||||
|
|
||||||
debug.updateSegfaultHandler(&act);
|
debug.updateSegfaultHandler(&act);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ pub fn build(b: *std.build.Builder) !void {
|
||||||
{
|
{
|
||||||
const act = posix.Sigaction{
|
const act = posix.Sigaction{
|
||||||
.handler = .{ .handler = posix.SIG.DFL },
|
.handler = .{ .handler = posix.SIG.DFL },
|
||||||
.mask = posix.empty_sigset,
|
.mask = posix.sigemptyset(),
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
};
|
};
|
||||||
try posix.sigaction(posix.SIG.PIPE, &act, null);
|
try posix.sigaction(posix.SIG.PIPE, &act, null);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue