Remove extra indirection from cast (#2)
The cast from `mio::Poll` and `mio::windows::Binding` to local copies (see issue #1 for more details) had a bug--an extra `&`. Somehow it was working in debug, but in release the code panicked with "0xC000001D: Illegal Instruction. occurred". I replaced transmute with a regular cast (transmute was unnecessary), removed the extra indirection, changed the as_* functions to impls of AsRef, and added tests.
This commit is contained in:
Родитель
67c2c78511
Коммит
87a4a9970e
71
src/poll.rs
71
src/poll.rs
|
@ -49,7 +49,7 @@ pub fn new_registration(poll: &Poll, token: Token, ready: Ready, opt: PollOpt)
|
||||||
// I/O objects in this crate (UnixListener, UnixStream) to fully integrate with
|
// I/O objects in this crate (UnixListener, UnixStream) to fully integrate with
|
||||||
// the Binding and Overlapped types from mio::windows.
|
// the Binding and Overlapped types from mio::windows.
|
||||||
//
|
//
|
||||||
// The accessor functions in this module transmute the mio::windows types into
|
// The accessor functions in this module cast the mio::windows types into
|
||||||
// "skinny" types with an identical memory layout to gain access to internals.
|
// "skinny" types with an identical memory layout to gain access to internals.
|
||||||
//
|
//
|
||||||
// For example, when UnixStream::write_bufs needs to use the same scatter/gather
|
// For example, when UnixStream::write_bufs needs to use the same scatter/gather
|
||||||
|
@ -58,25 +58,29 @@ pub fn new_registration(poll: &Poll, token: Token, ready: Ready, opt: PollOpt)
|
||||||
// to verify that a Poll object isn't already registered to a different socket,
|
// to verify that a Poll object isn't already registered to a different socket,
|
||||||
// they use skinny::selector_id(poll).
|
// they use skinny::selector_id(poll).
|
||||||
//
|
//
|
||||||
// The transmute is obviously dangerous, but the alternative is to build up
|
// The cast is obviously dangerous, but the alternative is to build up a lot of
|
||||||
// a lot of machinery that already exists inside Binding and Overlapped (esp.
|
// machinery that already exists inside Binding and Overlapped (esp. Binding).
|
||||||
// Binding).
|
|
||||||
pub mod skinny {
|
pub mod skinny {
|
||||||
use std::mem;
|
|
||||||
use std::sync::{atomic::AtomicUsize, Arc, Condvar, Mutex};
|
use std::sync::{atomic::AtomicUsize, Arc, Condvar, Mutex};
|
||||||
use mio;
|
use mio;
|
||||||
|
|
||||||
|
fn reinterpret_cast<T, U>(obj: &T) -> &U {
|
||||||
|
unsafe { &*(obj as *const T as *const U) }
|
||||||
|
}
|
||||||
|
|
||||||
pub mod sys {
|
pub mod sys {
|
||||||
use std::mem;
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use lazycell::AtomicLazyCell;
|
use lazycell::AtomicLazyCell;
|
||||||
use mio::windows::Binding as MiowBinding;
|
use mio::windows::Binding as MiowBinding;
|
||||||
use miow::iocp::CompletionPort;
|
use miow::iocp::CompletionPort;
|
||||||
|
use super::reinterpret_cast;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct Binding {
|
struct Binding {
|
||||||
selector: AtomicLazyCell<Arc<SelectorInner>>,
|
selector: AtomicLazyCell<Arc<SelectorInner>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct BufferPool {
|
struct BufferPool {
|
||||||
pool: Vec<Vec<u8>>,
|
pool: Vec<Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
@ -99,6 +103,7 @@ pub mod skinny {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Selector {
|
pub struct Selector {
|
||||||
inner: Arc<SelectorInner>,
|
inner: Arc<SelectorInner>,
|
||||||
}
|
}
|
||||||
|
@ -110,6 +115,7 @@ pub mod skinny {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct SelectorInner {
|
struct SelectorInner {
|
||||||
/// Unique identifier of the `Selector`
|
/// Unique identifier of the `Selector`
|
||||||
id: usize,
|
id: usize,
|
||||||
|
@ -125,25 +131,44 @@ pub mod skinny {
|
||||||
buffers: Mutex<BufferPool>,
|
buffers: Mutex<BufferPool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_binding(binding: &MiowBinding) -> &Binding {
|
impl AsRef<Binding> for MiowBinding {
|
||||||
unsafe { mem::transmute(&binding as *const _ as * const _) }
|
fn as_ref(&self) -> &Binding {
|
||||||
|
reinterpret_cast(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_buffer(binding: &MiowBinding, size: usize) -> Vec<u8> {
|
pub fn get_buffer(binding: &MiowBinding, size: usize) -> Vec<u8> {
|
||||||
match as_binding(binding).selector.borrow() {
|
match binding.as_ref().selector.borrow() {
|
||||||
Some(i) => i.buffers.lock().unwrap().get(size),
|
Some(i) => i.buffers.lock().unwrap().get(size),
|
||||||
None => Vec::with_capacity(size),
|
None => Vec::with_capacity(size),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn put_buffer(binding: &MiowBinding, buf: Vec<u8>) {
|
pub fn put_buffer(binding: &MiowBinding, buf: Vec<u8>) {
|
||||||
if let Some(i) = as_binding(binding).selector.borrow() {
|
if let Some(i) = binding.as_ref().selector.borrow() {
|
||||||
i.buffers.lock().unwrap().put(buf);
|
i.buffers.lock().unwrap().put(buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use mio;
|
||||||
|
|
||||||
|
fn mem_addr<T>(obj: &T) -> usize {
|
||||||
|
obj as *const T as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn binding_as_ref_returns_ref_to_same_memory() {
|
||||||
|
let binding = &mio::windows::Binding::new();
|
||||||
|
let mybinding = binding.as_ref();
|
||||||
|
assert_eq!(mem_addr(binding), mem_addr(mybinding));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug)]
|
||||||
struct Poll {
|
struct Poll {
|
||||||
// Platform specific IO selector
|
// Platform specific IO selector
|
||||||
selector: sys::Selector,
|
selector: sys::Selector,
|
||||||
|
@ -162,21 +187,25 @@ pub mod skinny {
|
||||||
condvar: Condvar,
|
condvar: Condvar,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct ReadinessQueue {
|
struct ReadinessQueue {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
inner: Arc<ReadinessQueueInner>,
|
inner: Arc<ReadinessQueueInner>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct ReadinessQueueInner {}
|
struct ReadinessQueueInner {}
|
||||||
|
|
||||||
fn as_poll(poll: &mio::Poll) -> &Poll {
|
impl AsRef<Poll> for mio::Poll {
|
||||||
unsafe { mem::transmute(&poll as *const _ as *const _) }
|
fn as_ref(&self) -> &Poll {
|
||||||
|
reinterpret_cast(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// accessors
|
// accessors
|
||||||
|
|
||||||
pub fn selector_id(poll: &mio::Poll) -> usize {
|
pub fn selector_id(poll: &mio::Poll) -> usize {
|
||||||
as_poll(poll).selector.id()
|
poll.as_ref().selector.id()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_buffer(binding: &mio::windows::Binding, size: usize) -> Vec<u8> {
|
pub fn get_buffer(binding: &mio::windows::Binding, size: usize) -> Vec<u8> {
|
||||||
|
@ -186,4 +215,20 @@ pub mod skinny {
|
||||||
pub fn put_buffer(binding: &mio::windows::Binding, buf: Vec<u8>) {
|
pub fn put_buffer(binding: &mio::windows::Binding, buf: Vec<u8>) {
|
||||||
sys::put_buffer(binding, buf)
|
sys::put_buffer(binding, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use mio;
|
||||||
|
|
||||||
|
fn mem_addr<T>(obj: &T) -> usize {
|
||||||
|
obj as *const T as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn poll_as_ref_returns_ref_to_same_memory() {
|
||||||
|
let poll = &mio::Poll::new().unwrap();
|
||||||
|
let mypoll = poll.as_ref();
|
||||||
|
assert_eq!(mem_addr(poll), mem_addr(mypoll));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче