-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
wrapping libuv signal for use in Rust #9318
Conversation
This looks pretty good from a libuv-bindings perspective, but currently there is no safe method to use this. Right now you could register a handler, and then forget to unregister it, causing possible leaks or use-after-free situations. I'm not entirely certain about the semantics of our
Basically the main takeaway is that the main purpose of |
An example of how to implement a useful/safe signal handling API is the Go standard library's signal package: http://golang.org/pkg/os/signal/ The task can ask for a pipe on which to receive signals, and select on it. I expect you could also make a standalone signal object to select on. |
I actually always thought that Go's signals were pretty slick. We're definitely going to want selection over a number of events at some point, and if signals could fit into that list, it would be awesome. |
@alexcrichton |
YOu can get the |
@alexcrichton, @thestinger could you give me an example of how selection would work? |
I'm not entirely sure because I've never used them before, but it appears that you may be interested in |
None => { | ||
let chan = self.chan.clone(); | ||
let handler = ~do Handler::new(signum) |_, signum| { | ||
chan.send(signum); |
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.
SharedChan doesn't like send()
ing in a scheduler context (rtassert!
triggered at src/libstd/rt/comm.rs:118
). It seems that extern "C" fn
s are executed in the scheduler context (?). I have also tried to task::spawn
a new task and send()
in that task instead, but task::spawn
requires that it be called in a green task context (rtassert!
triggered at src/libstd/task/spawn.rs:561
). Could you point me to a fix, @brson ?
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.
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.
@olsonjeffery could you please confirm if I can delete the rtassert!
?
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.
IIRC, There actually are two things that need to happen:
- remove the
rtassert!
- use
send_deferred
instead ofsend
(that's what will actually cause a segfault if yousend
from aSchedTask
Can someone else verify this COA, though? @alexcrichton @brson ?
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.
Sadly I know very little about the runtime, so I won't be much help here :(
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.
@olsonjeffery I did not remove the rtassert!
. However, I switched to using SharedChan<T>::send_deferred()
instead of SharedChan<T>::send()
and the rtassert!
isn't triggered any more.
r? |
Signal handling is historically an incredibly tricky thing to get right. I would imaging that a lot of "the magic" is taken care for us by libuv, however. It would be nice to have very explicit documentation about the exact behavior of the signal handling in order to clarify what exactly it means to receive a signal. Right now there's a few things in this pull I think are missing. Some of them may just require clarification, but they should all be thought about and considered.
Those are the ones that I can think of off the top of my head, and I think that others would be alleviated with some more extensive documentation about the signal handling. |
Especially if you register a handler for the same signal in different schedulers (threads) on a platform without |
@alexcrichton Whenever I do |
I'm not sure if TESTNAME works for unit tests, I normally run |
|
@huonw thanks. It works. |
need-info r? |
It's a shame to let this keep sitting. Do we know what needs to happen to merge this? |
@brson: I'm worried that LLVM isn't implementing this in a way that's safe with multiple libuv instances around, and haven't looked into it deep enough to know for sure. |
@thestinger Could you elaborate? How can I check for this concern? |
I think that this is still missing the documentation necessary at the top of the file in docblocks or associated with the various functions as well. Additionally, I'm still not sure what the answers to a couple of my above questions are, so would you be willing to write up some documentation explaining what's going on? |
@alexcrichton I'm on it |
Interrupt = 2i, | ||
Break = 21i, | ||
HangUp = 1i, | ||
WindowSizeChange = 28i, |
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.
Could you add some documentation for when each of these signals are generated? It would also be useful to mention their posix equivalents (if they exist)
I was looking into libuv's implementation, and they appear to handle most of my concerns, so I'm not too worried about the semantics of signal handling. It looks like everything here is essentially "what we'd want to do" in the sense that it's all the right plumbing. The more concerning part to me is that the libuv types and implementation are exposed directly to That would involve making an I can touch up the documentation afterwards, I'm mostly concerned about the organization right now. Again, sorry this took awhile to get to, but now I feel like I'm up to speed with the runtime and feel comfortable doing an actual review :) |
@alexcrichton thank you for this detailed review. I will fix it up and make a commit shortly. |
r? |
} | ||
} | ||
|
||
impl GenericPort<Signum> for Listener { |
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'm a little unfamiliar with our concurrency primitives, but I imagine that doesn't expose the ability to select over the port receiving the signal, right? I think that it would be ok if port
was a public field accessible by consumers of the api so the full functionality of the port could be leveraged.
This is looking good, nice work! I had a few comments about how I think the Again though, thanks for doing all this, it's sorely needed! |
@alexcrichton thank you for your kind words. I have pushed the changes. r? |
@@ -154,3 +159,7 @@ pub trait RtioPipe { | |||
fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError>; | |||
fn write(&mut self, buf: &[u8]) -> Result<(), IoError>; | |||
} | |||
|
|||
pub trait RtioSignal { | |||
fn signal(&mut self, signal: Signum, channel: SharedChan<Signum>) -> Result<(), IoError>; |
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 not expose this as a function on the trait, but rather leave it up to the implementation. It's a little odd to have a blank trait, but I think that it's proper for now.
Looking really good! Would you mind adding a test for the case I mentioned earlier, along with a test which generates an error when you attempt to listen on an invalid signal? |
descriptive names easier-to-use api reorganize and document
@alexcrichton since there is an |
Looks great to me! I'm going to merge this along with #9901 in order to reduce the number of merge conflicts it's going to cause, thanks again! |
Thanks again for this! (still in the process of merging, but it'll be up on #9901 soon) |
@alexcrichton thanks 👍 |
Fix if_let_mutex not checking Mutexes behind refs Fixes rust-lang#9193 We can always peel references because we are looking for a method-call, for which autoderef applies. --- changelog: [`if_let_mutex`]: detect calls to `Mutex::lock()` if mutex is behind a ref changelog: [`if_let_mutex`]: Add labels to the two instances of the same Mutex that will deadlock
This pull request aims to create a wrapper for libuv's signal handling for use in Rust. Although it is still in an early stage, early feedback is much welcomed.