-
Notifications
You must be signed in to change notification settings - Fork 673
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
implement signal BitOr and SigSet::from! #615
Conversation
I'm not a huge fan of using The only use case I see missing here is supporting nice initialization. What about something akin to the |
Additionally I'm not a fan of using |
I will admit that I'm very new to Rust so I'm not sure what the right semantics are (and am quite willing to learn on what the "right way" of defining interfaces is in the Rust ecosystem). Is
While the underyling interface isn't a bitfield (and is accessed through the super-clumsy |
That could also work I guess, though now users will have to use |
Additionally the value of One thing I'd like to see is that This is looking really good though, that's for taking this on! |
@Susurrus Done, PTAL? |
src/sys/signal.rs
Outdated
#[derive(Clone, Copy)] | ||
pub struct SigSet { | ||
sigset: libc::sigset_t | ||
} | ||
|
||
/// sigset is a macro that allows for far more idiomatic initalisation of SigSet. Note that while |
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.
I don't think we should have a sigset![]
macro at all. I don't see what it offers that the BitOr
operator doesn't allow. And the ergonomics with macros in Rust right now are less than that of regular functions or operators. Let's go ahead and just remove it.
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.
The downside is that it requires doing SigSet::empty() | Signal::SIGHUP
in order to "promote" a Signal
to a SigSet
.
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.
Yeah, that's a great point. I'm actually thinking that going back to implementing From<Signal> for SigSet
to be the right solution. Then we can rewrite all functions that take a SigSet
to instead take a T: Into<SigSet>
instead.
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.
Yeah, From<Signal> for SigSet
is a very reasonable thing to do IMO here. Agreed that it would be better to not have that macro unless it is really required.
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.
Alright, I'll go back to that. Do you want me to do the T: Into<SigSet>
here or in a separate patchset?
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.
Same patchset. It's fine to have the From
impl and the conversion of functions to use it as another commit.
src/sys/signal.rs
Outdated
|
||
// Currently there is only one definition of c_int in libc, as well as only one | ||
// type for signal constants. | ||
// We would prefer to use the libc::c_int alias in the repr attribute. Unfortunately | ||
// this is not (yet) possible. | ||
|
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.
Please remove this line.
Also, Signal
needs doc comments now that there's this new behavior where you can combine Signal
s into SigSet
s.
Alright, I've updated this to have |
I'm sad that you can't implement a trait for a generic type. It would be nice to be able to do impl<T: Into<SigSet>> BitOr<T> for T { /* ... */ } |
src/sys/signal.rs
Outdated
/// | ||
/// ``` | ||
/// # use ::nix::sys::signal::*; | ||
/// // Into and From promote a signal to a SigSet that has only the given signal inside it. |
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.
Please leave these comments out of the code example instead and separate these into two separate examples. It'll make it slightly easier reading. Something like:
/// Into and From promote a signal to a SigSet that has only the given signal inside it.
/// ```
/// # use ::nix::sys::signal::*;
/// let sigset_a: SigSet = Signal::SIGTERM.into();
/// let sigset_b = SigSet::from(Signal::SIGTERM);
///```
///
/// `SigSet`s of multiple signals can be created by using the `|` (`BitOr`) operator:
/// ```
/// # use ::nix::sys::signal::*;
/// let sigset = Signal::SIGTERM | Signal::SIGHUP;
/// ```
///
/// Existing `SigSet`s can be extended using the `|` (`BitOr`) or `|=` (`BitAssign`) operator as well:
/// ```
/// let mut sigset = SigSet::empty();
/// sigset |= Signal::SIGQUIT;
/// ```
src/sys/signal.rs
Outdated
@@ -218,11 +263,42 @@ pub enum SigmaskHow { | |||
SIG_SETMASK = libc::SIG_SETMASK, | |||
} | |||
|
|||
/// SigSet represents a set of signals and is a thin wrapper around the libc APIs for sigset_t. |
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.
Please put all types in "`" like sigset_t
, etc.
/// # Examples | ||
/// | ||
/// ``` | ||
/// # use ::nix::sys::signal::*; |
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.
Please simplify this example to one SigSet
. Maybe you should just copy/paste the relevant examples from the Signal
docs above.
src/sys/signal.rs
Outdated
/// let sigset_d = sigset_c | sigset_a; | ||
/// ``` | ||
/// | ||
/// The above would traditionally require far more finicking with SigSet::add, SigSet::extend and |
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.
I think the first sentence here doesn't add anything, let's remove it.
src/sys/signalfd.rs
Outdated
@@ -60,10 +60,10 @@ pub fn signalfd(fd: RawFd, mask: &SigSet, flags: SfdFlags) -> Result<RawFd> { | |||
/// # Examples | |||
/// | |||
/// ``` | |||
/// use nix::sys::signal::*; |
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.
Let's make these use
lines not appear in the docs by prepending with #
since we're modifying this example.
test/test_signalfd.rs
Outdated
@@ -11,8 +11,7 @@ use nix::unistd; | |||
fn main() { | |||
print!("test test_signalfd ... "); | |||
|
|||
let mut mask = signal::SigSet::empty(); | |||
mask.add(signal::SIGUSR1).unwrap(); | |||
let mask: signal::SigSet = signal::SIGUSR1.into(); |
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.
We should allow a Signal
to be passed directly into SignalFd::new()
and related functions. Could you add that?
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.
I tried to figure out how to do this and I've bumped up against the edges of my knowledge of Rust. Because SignalFd::new
(and the other various methods for SignalFd
) take &SigSet
, we can't easily do something like this:
let sigmask = Signal::SIGTERM;
SignalFd::new(sigmask);
// or
SignalFd::new(&sigmask);
impl From<&Signal> for &SigSet
won't work because of trait specialization not being implementated, but there's an even deeper issue. I was trying to get impl AsRef<SigSet> for Signal
but realised that it doesn't appear to be possible (given Rust's borrowing model) to return an immutable reference to something allocated in the function that you're returning from. As a simple example, this simply doesn't work for obvious reasons:
impl AsRef<SigSet> for Signal {
fn as_ref(&self) -> &SigSet {
&self.clone().into()
}
}
Is there a way to make that work? It seems quite silly that you can't convert &Into<T>
into Into<&T>
but there's probably some much harder problem here than I'm seeing.
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.
In particular, I'm not really convinced this particular characterbake makes sense:
pub fn signalfd<'a, T: Into<&'a SigSet>>(fd: RawFd, mask: T, flags: SfdFlags) -> Result<RawFd>
In particular, I'm not sure what will actually fulfill the bound Into<&'a SigSet>
other than &SigSet
-- making it just a waste of characters.
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.
That'd a good point. My question now is why doesn't ppoll
take a &SigSet
instead of by-value?
CHANGELOG.md
Outdated
@@ -16,6 +16,13 @@ This project adheres to [Semantic Versioning](http://semver.org/). | |||
([#551](https://github.com/nix-rust/nix/pull/551)) | |||
- Added `nix::pty::{grantpt, posix_openpt, ptsname/ptsname_r, unlockpt}` | |||
([#556](https://github.com/nix-rust/nix/pull/556) | |||
- Added `nix::sys::SigSet::From<Signal>` and refactored some APIs to allow |
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.
Since this is a change, it should be put down in the Changed
section.
Getting close now. Some documentation cleanups and a few more functions to convert to use |
@cyphar You still interested in pushing this over the finish line? |
Yes. The past few weeks have been my finals of this semester of university, so I've not been able to touch this. I'll rebase and fix up your comments in the coming days. Thanks. |
@cyphar I'd love to get this in the next release of nix. Will you have time coming up here to rebase this so we can get this merged? |
@Susurrus Sorry for the delays, other projects have been getting close to release. I've rebased, but we still haven't figured out how to handle #615 (comment). Should I just remove my |
The normal libc::sigset_t API is incredibly clunky when initialising SigSets. Since a SigSet semantically is a (mathematical) set of Signals, it makes sense to allow Signals to be promoted to a SigSet. This will also allow us to change our API to take Into<SigSet> rather than SigSet, making this even more idiomatic. let mut sigset = SigSet::empty(); sigset.add(Signal::SIGINT); // versus let sigset: SigSet = Signal::SIGINT.into(); let sigset = SigSet::from(Signal::SIGINT); Signed-off-by: Aleksa Sarai <[email protected]>
In order to make operating on libc::sigset_t even more idiomatic, define several BitOr (and BitOrAssign) implementations. This makes it possible to operate on SigSet much more easily without needing to use SigSet::extend() everywhere. let sigset_a = SigSet::from(Signal::SIGINT); let sigset_b = SigSet::from(Signal::SIGTERM); let mut sigset_c = SigSet::empty(); sigset_c.extend(&sigset_a); sigset_c.extend(&sigset_b); // versus let sigset = Signal::SIGINT | Signal::SIGTERM; Signed-off-by: Aleksa Sarai <[email protected]>
Since we now have From<SigSet> and Into<SigSet>::BitOr, we can make the SigSet API (and also internal usage) far easier to read and more idiomatic. Signed-off-by: Aleksa Sarai <[email protected]>
The old documentation and tests wouldn't compile due to using an old nix API. We probably should enable signalfd building in CI (which is the reason this wasn't caught). Signed-off-by: Aleksa Sarai <[email protected]>
Signed-off-by: Aleksa Sarai <[email protected]>
Rebased again. |
This needs another rebase (be sure to move the CHANGELOG entries into the new unreleased section) and there are some tests failing that need to be fixed. |
@cyphar Can you rebase this and fix the tests that were failing previously? |
There's been no update in almost 5 months, so I'm going to go ahead and close this PR. |
I didn't have a chance to rebase it because there was still the question about |
This allows for far more idiomatic initialisation of SigSet without
having to declare mut variables, as well as mirroring the vec![]
semantics (though arguably SigSet is closer to a bitfield than a
vector).
And the BitOr* operations futher make it much easier to idiomatically
work with SigSet and Signal, without having to use sigset![] and
SigSet::extend() everywhere.
Implements #609
Signed-off-by: Aleksa Sarai [email protected]