-
Notifications
You must be signed in to change notification settings - Fork 130
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
Use autoincrementing number for handler ids #105
Conversation
Instead of uuid, can we just have a i64 id that we just atomically increment when we need one? Would also mean no changes to anything but the platform backends. |
Valid point. We could do that, but imo if we did that we should definitely implement some sort of id reuse. The creation of the id reuse algorithm could take as much effort as switching Uuid, depending on the route taken. |
Why do we need id reuse? If a program allocated a new id every millisecond, it would take ~585 million years to exaust 2^64. I think that's a pretty good definition of "someone else's problem" ;) (1 per ns gives us 585 years, which is slightly more concerning, but only slightly.) |
Haha very vary true and a very good point... I though about that, and AFAIK you'd have to exhaust If the consensus is to use an auto incrementing |
It's (For production builds, it should produce the exact same machine code I think?) Either way, I think it will be more efficient and less invasive than using I'd say the actual Changing the handling of |
☔ The latest upstream changes (presumably #102) made this pull request unmergeable. Please resolve the merge conflicts. |
Use an Option<i64> for r_id instead of a plain i64, and use None instead of -1 to indicate the id does not exist in the handles.
eb72e53
to
b8fdf19
Compare
Updated to use an auto-incrementing |
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 code looks good :-) (Aside from minor optimisations -- see below.)
The PR title however doesn't fit any more; and perhaps more importantly, I'm a bit unhappy with the commit messages... The second commit in particular actually has three somewhat distinct changes: switching the type of the tokens returned by OsIpcReceiverSet.add()
/select()
to u64
, to delay potential integer overflow; factoring out the counter code from the inprocess
implementation into a generic Incrementor
facility, so it can be reused by the other back-ends; and decoupling the tokens used in the unix
implementation from the actual FD
s, to allow closing the FD
s without introducing race conditions due to FD
reuse. While I don't feel strongly about actually splitting these into separate commits (I don't think it substantially affects readability in this case), I think it would help a lot at least to explicitly mention and explain each of these changes in the commit message...
The third commit could mention that the FD
s are closed in select()
; and that this is to avoid them leaking. Also might want to point out that this is safe now with the previous changes.
The first patch ironically has the most explicit commit message, although it's the simplest change :-) Still, could add that this is in preparation for changing the type to u64
.
Sorry for picking on formalities like this. I'm just pedantic in general; and I really like a readable history :-) As usual, feel free to ignore these remarks if you think them silly...
On an unrelated note, it might be good to mention somewhere that the macos
implementation probably suffers from a similar leak? Though maybe that would be better placed in the issue tracker...
for fd in hangups.iter() { | ||
self.fdids.remove(fd); | ||
unsafe { | ||
libc::close(*fd); |
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.
While I do understand that we need to delay purging the entries from pollfds
, I can't think of any reason for delaying the FD closing?...
Also, I just realised that fdids
doesn't really need to be a HashMap
: you could just put the IDs in a positional vector parallel to pollfds
. Or if you keep it a HashMap
, you can drop the fdids
entries immediately; and then you won't need hangups
any more, as you can then just use fdids
to check which entries need to be retained in pollfds
. Not sure which is more efficient -- and with the mio
patch hopefully getting merged soon, it's probably not worth spending too much thought on it... Just pick whatever seems easier I'd say :-)
Uuid
instead of i64
for handler keysUse an auto incrementing u64 value as the OsIpcReceiver's id within the OsIpcReceiverSet in the inprocess and unix modules. - Change the type returned by OsIpcReceiverSet select and add to u64, to delay overflow. - Factor out the implementation of an auto-incrementing id inprocess into os::Incrementor, to be used by other platforms. - Use the Incrementor in the unix module to decouple the id of the OsIpcReceiver from the file descriptor to avoid race conditions due to file descriptor reuse.
Thanks again, great critiques! I clearly need to work on better commit messages 😄. |
} | ||
// Avoid the use of `self` in closue to avoid errors due to the | ||
// mutable borrow of `self` at line 483 | ||
let ids = &self.fdids; |
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 borrow checker has beaten me... I don't really like this, but this was the best workaround I could think of. If anyone can think of a better workaround, please let me know!
Either way... It's only temporary until the mio PR lands.
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.
What happens if instead of doing an inline closure in line 483, you make a let-binding of a closure and pass it in as an argument to retain
?
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.
Good idea! but sadly no :(
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 I understand the situation; I don't understand though why you consider it a problem?...
It's not exactly uncommon to create temporary bindings to get around borrow conflicts. I'm not sure this even deserves a comment: it doesn't seem like an obscure situation that requires much of an explanation?...
(BTW, including line numbers in a comment is a bad idea: these are bound to change :-) )
On the other hand, I for my part would be tempted to add a comment explaining that the entries that got removed from fdids
, because the channels got closed, also need to be purged from pollfds
. (And perhaps even mention that we can only do that after we finished iterating pollfds
?...) These are the kind of things that are probably not immediately obvious even to an experienced Rust programmer looking at this code for the first time.
(I am aware that the existing ipc-channel
code doesn't have much in the manner of such explanations... Which I personally consider a pity.)
On a more nit-picky note, I'd drop the blank line after the temporary binding -- these two lines very much belong together. Also, I think it would actually be preferable to name the temporary as fdids
as well...
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.
(BTW, including line numbers in a comment is a bad idea: these are bound to change :-) )
Ha true! good call... Removed the line numbers
I also added a comment above the retain detailing the reason for the placement.
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.
BTW, just for explanation (in case it isn't clear): the issue here isn't the borrow checker being dumb, but rather it's about the way how closures are handled. They automatically close over any binding used within the closure's code -- in this case the binding is self
. The compiler doesn't try to figure out that you are actually accessing only one sub-field. If you want only the sub-field to be closed over, you have to create an explicit binding for it... Which is precisely what you did :-)
2deca67
to
2e1081c
Compare
Looks good to me :-) Now we just need someone to approve it... |
@bors-servo r=antrik |
📌 Commit 2e1081c has been approved by |
Use autoincrementing number for handler ids Use `Uuid` instead of `i64` for the handler keys to ensure file descriptor number reuse doesn't cause errors, and make sure to close file descriptors. **NB:** The scope of the PR has changed to change the handler id's from a platform specific `i64` to an autoincrementing `u64`. `macos` has not yet been ported, and probably suffers from the same leak as the `unix` module did prior to this PR
☀️ Test successful - status-appveyor, status-travis |
Cool beans! I'll move back onto #94 |
Thanks for doing this work, it's awesome :) On Thu, Nov 10, 2016 at 05:22:13PM -0800, Dan Robertson wrote:
|
Use
Uuid
instead ofi64
for the handler keys to ensure file descriptor number reuse doesn't cause errors, and make sure to close file descriptors.NB: The scope of the PR has changed to change the handler id's from a platform specific
i64
to an autoincrementingu64
.macos
has not yet been ported, and probably suffers from the same leak as theunix
module did prior to this PR