-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Split glibc and linux sigset_t ABIs and the accessor functions #23601
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Thanks for quick the review! I've got some test failures to dig into, in addition to your feedback to address. I'll bring this back from a draft when its ready for another look. |
Looks like I still have some work to do ...
So far all I know is that |
Dropped QEMU maps target signals onto host signals. When the target has more signals than the host, the extras signals are just not supported. See For future work, it might make sense to add an initializer to the Splitting up the |
Can you show a minimal diff of what this would look like? It can be follow-up work in any case; I'm just curious. |
I was thinking of something like this (these would be constructors on Sigaction):
The optimization is that these constructors can initialize the |
Makes sense. And yeah, I think I agree with your conclusion. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM other than the above comments.
And it looks like I've broken something with the latest update .. (I did run the tests locally! But not getting the same MIPS coverage? Or release?) ... Anyway, I'll be back with more patches soon ... |
To run non-native architectures locally, you have to pass |
Heh, I think the MIPS signal numbers were wrong. So the "safe" We have the technology to verify all these constants match their C equivalents. (And that field offsets and sizes match too.) But, AFAICT, there are no tests doing the equivalent of |
Export the sigset_t ops (sigaddset, etc) from the C library. Don't rely on the linux.zig defintions (which will be defined to use the kernel ABI). Move Darwin sigset and NSIG declarations into darwin.zig. Remove extraneous (?) sigaddset. The C library sigaddset can reject some signals being added, so need to defer to it.
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.
Unify the C library sigset_t and Linux native sigset_t and the accessor operations. Add tests that the various sigset_t operations are working. And clean up existing tests a bit.
When linking a libc, Zig should defer to the C library for sigset operations. The pre-filled constants signal sets (empty_sigset, filled_sigset) are not compatible with C library initialization, so remove them and use the runtime `sigemptyset` and `sigfillset` methods to initialize any sigset.
…gset_t By returning an initialized sigset (instead of taking the set as an output parameter), these functions can be used to directly initialize the `mask` parameter of a `Sigaction` instance.
All the existing code that manipulates `ucontext_t` expects there to be a glibc-compatible sigmask (1024-bit). The `ucontext_t` struct need to be cleaned up so the glibc-dependent format is only used when linking glibc/musl library, but that is a more involved change. In practice, no Zig code looks at the sigset field contents, so it just needs to be the right size.
Dunno why the MIPS signal numbers are different, or why Zig had them already special cased, but wrong. We have the technology to test these constants. We should use it.
I like the idea of this (and in fact do that in one of my personal projects), but there's the issue of what we do when So we need to actually decide on a direction for the project in this regard with all the relevant facts taken into account. Could you file an issue for this idea? I'll bring it up for discussion in one of the upcoming team meetings. |
Just a reminder to file a bug for this as well. |
Great work, thanks! |
Thanks for the reviews! I'll file the 2 bugs in the next couple days ... |
Zig's
c.zig
glibc/musl layer and thelinux.zig
kernel syscall wrapper layers both definesigset_t
. Currentlylinux.zig
uses a definition compatible with glibc/musl, and thenc.zig
imports that definition. The glibc ABI defines a 1024-bitsigset_t
. The linux kernel ABI generally defines a 64-bitsigset_t
(or 128-bit on MIPS). At run-time, glibc (and Zig) just presents the lowest bits of the largersigset_t
to the kernel. Glibc "needs" the extra space in its ABI so it can accommodate future kernels that support a larger number of signals. Zig does not need that compatibility unless linking the C library. Thelinux.zig
ABI should be able to define asigset_t
that matches the underlying kernel ABI.The array of words backing
sigset_t
array must match the kernel's layout. Two 32-bit words are not the same as one 64-bit word on a big-endian platform. The kernel headers useunsigned long
as the element, so I usedc_ulong
for consistency. This means the array is sometimes of 32-bit words, and sometimes made from 64-bit words. I added some tests that make sure blocking specific signals works to check we're getting the bit indexes correct. (In practice most signal numbers are less than 32, so this wasn't much of a practical problem.)The
sigfillset()
call needs to go through the dynamically linked C library, when one is present. The run-time library might decide to reserve some signals. Similarly,sigaddset()
might reject some signal numbers reserved by the C library. Also, Zig's pre-filledfilled_sigset
can't work when linking a C library, because Zig can't invoke external symbols in a static initializer (at least, that's what I understood the error I got to mean). This PR provides POSIX-likesigemptyset()
andsigfillset()
functions, but in Zig they return the initialized set (instead of taking the set as an output parameter). This PR also removeslinux.all_mask
.Sigaction
contains asigset_t
. In Zig this structure is already mapped (in thesigaction
wrapper) into ak_sigaction
that has a "restorer" field and an ad-hoc, right-sized signal mask field. With a properly definedsigset_t
, some differences instd.os.linx.Sigaction
versions collapse (e.g., the MIPS variations were just encapsulatingsigset_t
differences.) The Zig-onlySigaction
structure doesn't need a restorer, so remove that. Also doesn't need to be anextern
struct.The
context_t
structure also contains a glibc-compatiblesigset_t
. I made that explicit in this PR, and avoided fixing it for now, as I think there are deeper changes required around this structure.Using a
u6
for the signal number is too narrow. Signal numbers can go up to 128 on some platforms. Changed to au8
parameter since the actual boundary isn't always a power of two. Means we need to@truncate
when converting signal numbers into bit masks in some places.I am unclear about the darwin.zig changes. I'm not sure if the sigset accessors (
sigaddset()
,sigfillset()
, etc) are defined in the Darwin C library (but I assume they are?).Added a std.os.posix layer to hide differences (mostly just error handling) between C-library sigset manipulators and the direct linux kernel accessor. I can drop these if folks would rather not see new code added to posix, but they were handy for making tests to make sure all the implementations are consistent.
PR inspired by conversation on https://github.com/ziglang/zig/pull/23502\#discussion\_r2034064507