<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

extern crate devicemapper;
extern crate libstratis;
extern crate loopdev;
extern crate tempdir;

mod util;

use std::fs::OpenOptions;
use std::io::{Seek, Write, SeekFrom};
use std::path::{Path, PathBuf};

use devicemapper::Bytes;
use loopdev::{LoopControl, LoopDevice};
use tempdir::TempDir;

use libstratis::consts::IEC;

use util::simple_tests::test_force_flag_dirty;
use util::simple_tests::test_force_flag_stratis;
use util::simple_tests::test_linear_device;
use util::simple_tests::test_pool_blockdevs;
use util::simple_tests::test_thinpool_device;
use util::simple_tests::test_variable_length_metadata_times;

/// Setup count loop backed devices in dir.
/// Make sure each loop device is backed by a 1 GiB file.
fn get_devices(count: u8, dir: &TempDir) -> Vec<LoopDevice> {
    let lc = LoopControl::open().unwrap();
    let mut loop_devices = Vec::new();

    let length = Bytes(IEC::Gi as u64);
    for index in 0..count {
        let subdir = TempDir::new_in(dir, &index.to_string()).unwrap();
        let path = subdir.path().join("store");
        let mut f = OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();

        // the proper way to do this is fallocate, but nix doesn't implement yet.
        // TODO: see https://github.com/nix-rust/nix/issues/596
        f.seek(SeekFrom::Start(*length)).unwrap();
        f.write(&[0]).unwrap();
        f.flush().unwrap();

        let ld = lc.next_free().unwrap();
        ld.attach(path, 0).unwrap();
        loop_devices.push(ld);
    }
    loop_devices
}

/// Set up count loopbacked devices.
/// Then, run the designated test.
/// Then, take down the loop devices.
fn test_with_spec<F>(count: u8, test: F) -> ()
    where F: Fn(&[&Path]) -> ()
{
    let tmpdir = TempDir::new("stratis").unwrap();
    let loop_devices: Vec<LoopDevice> = get_devices(count, &tmpdir);
    let device_paths: Vec<PathBuf> = loop_devices.iter().map(|x| x.get_path().unwrap()).collect();
    let device_paths: Vec<&Path> = device_paths.iter().map(|x| x.as_path()).collect();

    test(&device_paths);

    for dev in loop_devices {
        dev.detach().unwrap();
    }
}

#[test]
pub fn loop_test_force_flag_stratis() {
    test_with_spec(2, test_force_flag_stratis);
    test_with_spec(3, test_force_flag_stratis);
}

#[test]
pub fn loop_test_linear_device() {
    test_with_spec(2, test_linear_device);
    test_with_spec(3, test_linear_device);
}

#[test]
pub fn loop_test_thinpool_device() {
    test_with_spec(3, test_thinpool_device);
}

#[test]
pub fn loop_test_pool_blockdevs() {
    test_with_spec(3, test_pool_blockdevs);
}

#[test]
pub fn loop_test_force_flag_dirty() {
    test_with_spec(3, test_force_flag_dirty);
}

#[test]
pub fn loop_test_variable_length_metadata_times() {
    test_with_spec(3, test_variable_length_metadata_times);
}
<commit_msg>Explicitly delete the temporary directory for loop devices<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

extern crate devicemapper;
extern crate libstratis;
extern crate loopdev;
extern crate tempdir;

mod util;

use std::fs::OpenOptions;
use std::io::{Seek, Write, SeekFrom};
use std::path::{Path, PathBuf};

use devicemapper::Bytes;
use loopdev::{LoopControl, LoopDevice};
use tempdir::TempDir;

use libstratis::consts::IEC;

use util::simple_tests::test_force_flag_dirty;
use util::simple_tests::test_force_flag_stratis;
use util::simple_tests::test_linear_device;
use util::simple_tests::test_pool_blockdevs;
use util::simple_tests::test_thinpool_device;
use util::simple_tests::test_variable_length_metadata_times;

/// Setup count loop backed devices in dir.
/// Make sure each loop device is backed by a 1 GiB file.
fn get_devices(count: u8, dir: &TempDir) -> Vec<LoopDevice> {
    let lc = LoopControl::open().unwrap();
    let mut loop_devices = Vec::new();

    let length = Bytes(IEC::Gi as u64);
    for index in 0..count {
        let subdir = TempDir::new_in(dir, &index.to_string()).unwrap();
        let path = subdir.path().join("store");
        let mut f = OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();

        // the proper way to do this is fallocate, but nix doesn't implement yet.
        // TODO: see https://github.com/nix-rust/nix/issues/596
        f.seek(SeekFrom::Start(*length)).unwrap();
        f.write(&[0]).unwrap();
        f.flush().unwrap();

        let ld = lc.next_free().unwrap();
        ld.attach(path, 0).unwrap();
        loop_devices.push(ld);
    }
    loop_devices
}

/// Set up count loopbacked devices.
/// Then, run the designated test.
/// Then, take down the loop devices.
fn test_with_spec<F>(count: u8, test: F) -> ()
    where F: Fn(&[&Path]) -> ()
{
    let tmpdir = TempDir::new("stratis").unwrap();
    let loop_devices: Vec<LoopDevice> = get_devices(count, &tmpdir);
    let device_paths: Vec<PathBuf> = loop_devices.iter().map(|x| x.get_path().unwrap()).collect();
    let device_paths: Vec<&Path> = device_paths.iter().map(|x| x.as_path()).collect();

    test(&device_paths);

    for dev in loop_devices {
        dev.detach().unwrap();
    }

    // Explicitly delete the temporary directory with all its contents.
    // Allowing it to be deleted on drop will cause any errors to be suppressed.
    // This may alert us to some problem with the underlying infrastructure
    // of the tests.
    tmpdir.close().unwrap();
}

#[test]
pub fn loop_test_force_flag_stratis() {
    test_with_spec(2, test_force_flag_stratis);
    test_with_spec(3, test_force_flag_stratis);
}

#[test]
pub fn loop_test_linear_device() {
    test_with_spec(2, test_linear_device);
    test_with_spec(3, test_linear_device);
}

#[test]
pub fn loop_test_thinpool_device() {
    test_with_spec(3, test_thinpool_device);
}

#[test]
pub fn loop_test_pool_blockdevs() {
    test_with_spec(3, test_pool_blockdevs);
}

#[test]
pub fn loop_test_force_flag_dirty() {
    test_with_spec(3, test_force_flag_dirty);
}

#[test]
pub fn loop_test_variable_length_metadata_times() {
    test_with_spec(3, test_variable_length_metadata_times);
}
<|endoftext|>


<commit_before>use std::collections::VecDeque;
use std::ptr;
use std::sync::Arc;
use std::os::raw::c_void;

use ash::vk;
use ash::extensions as ext;

use hal;
use hal::format::Format;

#[cfg(feature = "winit")]
use winit;

use {conv, native};
use {VK_ENTRY, Backend, Instance, PhysicalDevice, QueueFamily, RawInstance};

pub struct Surface {
    // Vk (EXT) specs [29.2.7 Platform-Independent Information]
    // For vkDestroySurfaceKHR: Host access to surface must be externally synchronized
    pub(crate) raw: Arc<RawSurface>,
    pub(crate) width: u32,
    pub(crate) height: u32,
}

pub struct RawSurface {
    pub(crate) handle: vk::SurfaceKHR,
    functor: ext::Surface,
    pub(crate) instance: Arc<RawInstance>,
}

impl Drop for RawSurface {
    fn drop(&mut self) {
        unsafe {
            self.functor.destroy_surface_khr(self.handle, None);
        }
    }
}

impl Instance {
    #[cfg(unix)]
    pub fn create_surface_from_xlib(&self, display: *mut c_void, window: usize) -> Surface {
        let entry = VK_ENTRY
            .as_ref()
            .expect("Unable to load Vulkan entry points");

        if !self.extensions.contains(&vk::VK_KHR_XLIB_SURFACE_EXTENSION_NAME) {
            panic!("Vulkan driver does not support VK_KHR_XLIB_SURFACE");
        }

        let surface = {
            let xlib_loader = ext::XlibSurface::new(entry, &self.raw.0)
                                .expect("XlibSurface failed");

            let info = vk::XlibSurfaceCreateInfoKHR {
                s_type: vk::StructureType::XlibSurfaceCreateInfoKhr,
                p_next: ptr::null(),
                flags: vk::XlibSurfaceCreateFlagsKHR::empty(),
                window: window as _,
                dpy: display as *mut _,
            };

            unsafe { xlib_loader.create_xlib_surface_khr(&info, None) }
                .expect("XlibSurface failed")
        };

        let (width, height) = unsafe {
            use x11::xlib::{XGetWindowAttributes, XWindowAttributes};
            use std::mem::zeroed;
            let mut attribs: XWindowAttributes = zeroed();
            let result = XGetWindowAttributes(display as *mut _, window as _, &mut attribs);
            if result == 0 {
                panic!("XGetGeometry failed");
            }
            (attribs.width as u32, attribs.height as u32)
        };

        self.create_surface_from_vk_surface_khr(surface, width, height)
    }

    #[cfg(unix)]
    pub fn create_surface_from_wayland(&self, display: *mut c_void, surface: *mut c_void, width: u32, height: u32) -> Surface {
        let entry = VK_ENTRY
            .as_ref()
            .expect("Unable to load Vulkan entry points");

        if !self.extensions.contains(&vk::VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME) {
            panic!("Vulkan driver does not support VK_KHR_WAYLAND_SURFACE");
        }

        let surface = {
            let w_loader = ext::WaylandSurface::new(entry, &self.raw.0)
                                .expect("WaylandSurface failed");

            let info = vk::WaylandSurfaceCreateInfoKHR {
                s_type: vk::StructureType::WaylandSurfaceCreateInfoKhr,
                p_next: ptr::null(),
                flags: vk::WaylandSurfaceCreateFlagsKHR::empty(),
                display: display as *mut _,
                surface: surface as *mut _,
            };

            unsafe { w_loader.create_wayland_surface_khr(&info, None) }
                .expect("WaylandSurface failed")
        };

        self.create_surface_from_vk_surface_khr(surface, width, height)
    }

    #[cfg(windows)]
    pub fn create_surface_from_hwnd(&self, hwnd: *mut c_void) -> Surface {
        let entry = VK_ENTRY
            .as_ref()
            .expect("Unable to load Vulkan entry points");

        if !self.extensions.contains(&vk::VK_KHR_WIN32_SURFACE_EXTENSION_NAME) {
            panic!("Vulkan driver does not support VK_KHR_WIN32_SURFACE");
        }

        let surface = {
            use kernel32;

            let win32_loader = ext::Win32Surface::new(entry, &self.raw.0)
                .expect("Unable to load win32 surface functions");

            unsafe {
                let info = vk::Win32SurfaceCreateInfoKHR {
                    s_type: vk::StructureType::Win32SurfaceCreateInfoKhr,
                    p_next: ptr::null(),
                    flags: vk::Win32SurfaceCreateFlagsKHR::empty(),
                    hinstance: kernel32::GetModuleHandleW(ptr::null()) as *mut _,
                    hwnd: hwnd as *mut _,
                };

                win32_loader.create_win32_surface_khr(&info, None)
                    .expect("Unable to create Win32 surface")
            }
        };

        let (width, height) = unsafe {
            use winapi::RECT;
            use user32::GetClientRect;
            use std::mem::zeroed;
            let mut rect: RECT = zeroed();
            if GetClientRect(hwnd as *mut _, &mut rect as *mut RECT) == 0 {
                panic!("GetClientRect failed");
            }
            ((rect.right - rect.left) as u32, (rect.bottom - rect.top) as u32)
        };

        self.create_surface_from_vk_surface_khr(surface, width, height)
    }

    #[cfg(feature = "winit")]
    pub fn create_surface(&self, window: &winit::Window) -> Surface {
        #[cfg(unix)]
        {
            use winit::os::unix::WindowExt;

            if self.extensions.contains(&vk::VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME) {
                if let Some(display) = window.get_wayland_display() {
                    let display: *mut c_void = display as *mut _;
                    let surface: *mut c_void = window.get_wayland_surface().unwrap() as *mut _;
                    let (width, height) = window.get_inner_size().unwrap();
                    return self.create_surface_from_wayland(display, surface, width, height);
                }
            }
            if self.extensions.contains(&vk::VK_KHR_XLIB_SURFACE_EXTENSION_NAME) {
                if let Some(display) = window.get_xlib_display() {
                    let display: *mut c_void = display as *mut _;
                    let window: usize = window.get_xlib_window().unwrap() as _;
                    return self.create_surface_from_xlib(display, window);
                }
            }
            panic!("The Vulkan driver does not support surface creation!");
        }
        #[cfg(windows)]
        {
            use winit::os::windows::WindowExt;
            self.create_surface_from_hwnd(window.get_hwnd() as *mut _)
        }
    }

    fn create_surface_from_vk_surface_khr(&self, surface: vk::SurfaceKHR, width: u32, height: u32) -> Surface {
        let entry = VK_ENTRY
            .as_ref()
            .expect("Unable to load Vulkan entry points");

        let functor = ext::Surface::new(entry, &self.raw.0)
            .expect("Unable to load surface functions");

        let raw = Arc::new(RawSurface {
            handle: surface,
            functor,
            instance: self.raw.clone(),
        });

        Surface { raw, width, height }
    }
}

impl hal::Surface<Backend> for Surface {
    fn get_kind(&self) -> hal::image::Kind {
        use hal::image::Size;

        let aa = hal::image::AaMode::Single;
        hal::image::Kind::D2(self.width as Size, self.height as Size, aa)
    }

    fn capabilities_and_formats(&self, physical_device: &PhysicalDevice) -> (hal::SurfaceCapabilities, Vec<Format>) {
        // Capabilities
        let caps =
            self.raw.functor.get_physical_device_surface_capabilities_khr(
                physical_device.handle,
                self.raw.handle,
            )
            .expect("Unable to query surface capabilities");

        // If image count is 0, the support number of images is unlimited.
        let max_images = if caps.max_image_count == 0 { !0 } else { caps.max_image_count };

        // `0xFFFFFFFF` indicates that the extent depends on the created swapchain.
        let current_extent =
            if caps.current_extent.width != 0xFFFFFFFF && caps.current_extent.height != 0xFFFFFFFF {
                Some(hal::window::Extent2d {
                    width: caps.current_extent.width,
                    height: caps.current_extent.height,
                })
            } else {
                None
            };

        let min_extent = hal::window::Extent2d {
            width: caps.min_image_extent.width,
            height: caps.min_image_extent.height,
        };

        let max_extent = hal::window::Extent2d {
            width: caps.max_image_extent.width,
            height: caps.max_image_extent.height,
        };

        let capabilities = hal::SurfaceCapabilities {
            image_count: caps.min_image_count..max_images,
            current_extent,
            extents: min_extent..max_extent,
            max_image_layers: caps.max_image_array_layers,
        };

        // Swapchain formats
        let formats =
            self.raw.functor.get_physical_device_surface_formats_khr(
                physical_device.handle,
                self.raw.handle,
            ).expect("Unable to query surface formats");

        let formats = formats
            .iter()
            .filter_map(|sf| {
                conv::map_vk_format(sf.format)
                    .map(|(surface, channel)| Format(surface, channel))
            })
            .collect();

        (capabilities, formats)
    }

    fn supports_queue_family(&self, queue_family: &QueueFamily) -> bool {
        self.raw.functor.get_physical_device_surface_support_khr(
            queue_family.device,
            queue_family.index,
            self.raw.handle,
        )
    }
}

pub struct Swapchain {
    pub(crate) raw: vk::SwapchainKHR,
    pub(crate) functor: ext::Swapchain,
    // Queued up frames for presentation
    pub(crate) frame_queue: VecDeque<usize>,
}

impl hal::Swapchain<Backend> for Swapchain {
    fn acquire_frame(&mut self, sync: hal::FrameSync<Backend>) -> hal::Frame {
        let (semaphore, fence) = match sync {
            hal::FrameSync::Semaphore(semaphore) => (semaphore.0, vk::Fence::null()),
            hal::FrameSync::Fence(fence) => (vk::Semaphore::null(), fence.0),
        };

        let index = unsafe {
            // will block if no image is available
            self.functor.acquire_next_image_khr(self.raw, !0, semaphore, fence)
        }.expect("Unable to acquire a swapchain image");

        self.frame_queue.push_back(index as usize);
        hal::Frame::new(index as usize)
    }

    fn present<C>(
        &mut self,
        present_queue: &mut hal::CommandQueue<Backend, C>,
        wait_semaphores: &[&native::Semaphore],
    ) {
        let frame = self.frame_queue.pop_front().expect(
            "No frame currently queued up. Need to acquire a frame first.",
        );

        let semaphores = wait_semaphores.iter().map(|sem| sem.0).collect::<Vec<_>>();

        // TODO: wait semaphores
        let info = vk::PresentInfoKHR {
            s_type: vk::StructureType::PresentInfoKhr,
            p_next: ptr::null(),
            wait_semaphore_count: semaphores.len() as u32,
            p_wait_semaphores: semaphores.as_ptr(),
            swapchain_count: 1,
            p_swapchains: &self.raw,
            p_image_indices: &(frame as u32),
            p_results: ptr::null_mut(),
        };

        assert_eq!(Ok(()), unsafe {
            self.functor
                .queue_present_khr(*present_queue.as_raw().raw, &info)
        });
        // TODO: handle result and return code
    }
}
<commit_msg>vk: win32: Custom hinstance on surface creation<commit_after>use std::collections::VecDeque;
use std::ptr;
use std::sync::Arc;
use std::os::raw::c_void;

use ash::vk;
use ash::extensions as ext;

use hal;
use hal::format::Format;

#[cfg(feature = "winit")]
use winit;

use {conv, native};
use {VK_ENTRY, Backend, Instance, PhysicalDevice, QueueFamily, RawInstance};

pub struct Surface {
    // Vk (EXT) specs [29.2.7 Platform-Independent Information]
    // For vkDestroySurfaceKHR: Host access to surface must be externally synchronized
    pub(crate) raw: Arc<RawSurface>,
    pub(crate) width: u32,
    pub(crate) height: u32,
}

pub struct RawSurface {
    pub(crate) handle: vk::SurfaceKHR,
    functor: ext::Surface,
    pub(crate) instance: Arc<RawInstance>,
}

impl Drop for RawSurface {
    fn drop(&mut self) {
        unsafe {
            self.functor.destroy_surface_khr(self.handle, None);
        }
    }
}

impl Instance {
    #[cfg(unix)]
    pub fn create_surface_from_xlib(&self, display: *mut c_void, window: usize) -> Surface {
        let entry = VK_ENTRY
            .as_ref()
            .expect("Unable to load Vulkan entry points");

        if !self.extensions.contains(&vk::VK_KHR_XLIB_SURFACE_EXTENSION_NAME) {
            panic!("Vulkan driver does not support VK_KHR_XLIB_SURFACE");
        }

        let surface = {
            let xlib_loader = ext::XlibSurface::new(entry, &self.raw.0)
                                .expect("XlibSurface failed");

            let info = vk::XlibSurfaceCreateInfoKHR {
                s_type: vk::StructureType::XlibSurfaceCreateInfoKhr,
                p_next: ptr::null(),
                flags: vk::XlibSurfaceCreateFlagsKHR::empty(),
                window: window as _,
                dpy: display as *mut _,
            };

            unsafe { xlib_loader.create_xlib_surface_khr(&info, None) }
                .expect("XlibSurface failed")
        };

        let (width, height) = unsafe {
            use x11::xlib::{XGetWindowAttributes, XWindowAttributes};
            use std::mem::zeroed;
            let mut attribs: XWindowAttributes = zeroed();
            let result = XGetWindowAttributes(display as *mut _, window as _, &mut attribs);
            if result == 0 {
                panic!("XGetGeometry failed");
            }
            (attribs.width as u32, attribs.height as u32)
        };

        self.create_surface_from_vk_surface_khr(surface, width, height)
    }

    #[cfg(unix)]
    pub fn create_surface_from_wayland(&self, display: *mut c_void, surface: *mut c_void, width: u32, height: u32) -> Surface {
        let entry = VK_ENTRY
            .as_ref()
            .expect("Unable to load Vulkan entry points");

        if !self.extensions.contains(&vk::VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME) {
            panic!("Vulkan driver does not support VK_KHR_WAYLAND_SURFACE");
        }

        let surface = {
            let w_loader = ext::WaylandSurface::new(entry, &self.raw.0)
                                .expect("WaylandSurface failed");

            let info = vk::WaylandSurfaceCreateInfoKHR {
                s_type: vk::StructureType::WaylandSurfaceCreateInfoKhr,
                p_next: ptr::null(),
                flags: vk::WaylandSurfaceCreateFlagsKHR::empty(),
                display: display as *mut _,
                surface: surface as *mut _,
            };

            unsafe { w_loader.create_wayland_surface_khr(&info, None) }
                .expect("WaylandSurface failed")
        };

        self.create_surface_from_vk_surface_khr(surface, width, height)
    }

    #[cfg(windows)]
    pub fn create_surface_from_hwnd(&self, hinstance: *mut c_void, hwnd: *mut c_void) -> Surface {
        let entry = VK_ENTRY
            .as_ref()
            .expect("Unable to load Vulkan entry points");

        if !self.extensions.contains(&vk::VK_KHR_WIN32_SURFACE_EXTENSION_NAME) {
            panic!("Vulkan driver does not support VK_KHR_WIN32_SURFACE");
        }

        let surface = {
            let win32_loader = ext::Win32Surface::new(entry, &self.raw.0)
                .expect("Unable to load win32 surface functions");

            unsafe {
                let info = vk::Win32SurfaceCreateInfoKHR {
                    s_type: vk::StructureType::Win32SurfaceCreateInfoKhr,
                    p_next: ptr::null(),
                    flags: vk::Win32SurfaceCreateFlagsKHR::empty(),
                    hinstance: hinstance as *mut _,
                    hwnd: hwnd as *mut _,
                };

                win32_loader.create_win32_surface_khr(&info, None)
                    .expect("Unable to create Win32 surface")
            }
        };

        let (width, height) = unsafe {
            use winapi::RECT;
            use user32::GetClientRect;
            use std::mem::zeroed;
            let mut rect: RECT = zeroed();
            if GetClientRect(hwnd as *mut _, &mut rect as *mut RECT) == 0 {
                panic!("GetClientRect failed");
            }
            ((rect.right - rect.left) as u32, (rect.bottom - rect.top) as u32)
        };

        self.create_surface_from_vk_surface_khr(surface, width, height)
    }

    #[cfg(feature = "winit")]
    pub fn create_surface(&self, window: &winit::Window) -> Surface {
        #[cfg(unix)]
        {
            use winit::os::unix::WindowExt;

            if self.extensions.contains(&vk::VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME) {
                if let Some(display) = window.get_wayland_display() {
                    let display: *mut c_void = display as *mut _;
                    let surface: *mut c_void = window.get_wayland_surface().unwrap() as *mut _;
                    let (width, height) = window.get_inner_size().unwrap();
                    return self.create_surface_from_wayland(display, surface, width, height);
                }
            }
            if self.extensions.contains(&vk::VK_KHR_XLIB_SURFACE_EXTENSION_NAME) {
                if let Some(display) = window.get_xlib_display() {
                    let display: *mut c_void = display as *mut _;
                    let window: usize = window.get_xlib_window().unwrap() as _;
                    return self.create_surface_from_xlib(display, window);
                }
            }
            panic!("The Vulkan driver does not support surface creation!");
        }
        #[cfg(windows)]
        {
            use kernel32;
            use winit::os::windows::WindowExt;
            let hinstance = unsafe { kernel32::GetModuleHandleW(ptr::null()) };
            let hwnd = window.get_hwnd();
            self.create_surface_from_hwnd(hinstance as *mut _, hwnd as *mut _)
        }
    }

    fn create_surface_from_vk_surface_khr(&self, surface: vk::SurfaceKHR, width: u32, height: u32) -> Surface {
        let entry = VK_ENTRY
            .as_ref()
            .expect("Unable to load Vulkan entry points");

        let functor = ext::Surface::new(entry, &self.raw.0)
            .expect("Unable to load surface functions");

        let raw = Arc::new(RawSurface {
            handle: surface,
            functor,
            instance: self.raw.clone(),
        });

        Surface { raw, width, height }
    }
}

impl hal::Surface<Backend> for Surface {
    fn get_kind(&self) -> hal::image::Kind {
        use hal::image::Size;

        let aa = hal::image::AaMode::Single;
        hal::image::Kind::D2(self.width as Size, self.height as Size, aa)
    }

    fn capabilities_and_formats(&self, physical_device: &PhysicalDevice) -> (hal::SurfaceCapabilities, Vec<Format>) {
        // Capabilities
        let caps =
            self.raw.functor.get_physical_device_surface_capabilities_khr(
                physical_device.handle,
                self.raw.handle,
            )
            .expect("Unable to query surface capabilities");

        // If image count is 0, the support number of images is unlimited.
        let max_images = if caps.max_image_count == 0 { !0 } else { caps.max_image_count };

        // `0xFFFFFFFF` indicates that the extent depends on the created swapchain.
        let current_extent =
            if caps.current_extent.width != 0xFFFFFFFF && caps.current_extent.height != 0xFFFFFFFF {
                Some(hal::window::Extent2d {
                    width: caps.current_extent.width,
                    height: caps.current_extent.height,
                })
            } else {
                None
            };

        let min_extent = hal::window::Extent2d {
            width: caps.min_image_extent.width,
            height: caps.min_image_extent.height,
        };

        let max_extent = hal::window::Extent2d {
            width: caps.max_image_extent.width,
            height: caps.max_image_extent.height,
        };

        let capabilities = hal::SurfaceCapabilities {
            image_count: caps.min_image_count..max_images,
            current_extent,
            extents: min_extent..max_extent,
            max_image_layers: caps.max_image_array_layers,
        };

        // Swapchain formats
        let formats =
            self.raw.functor.get_physical_device_surface_formats_khr(
                physical_device.handle,
                self.raw.handle,
            ).expect("Unable to query surface formats");

        let formats = formats
            .iter()
            .filter_map(|sf| {
                conv::map_vk_format(sf.format)
                    .map(|(surface, channel)| Format(surface, channel))
            })
            .collect();

        (capabilities, formats)
    }

    fn supports_queue_family(&self, queue_family: &QueueFamily) -> bool {
        self.raw.functor.get_physical_device_surface_support_khr(
            queue_family.device,
            queue_family.index,
            self.raw.handle,
        )
    }
}

pub struct Swapchain {
    pub(crate) raw: vk::SwapchainKHR,
    pub(crate) functor: ext::Swapchain,
    // Queued up frames for presentation
    pub(crate) frame_queue: VecDeque<usize>,
}

impl hal::Swapchain<Backend> for Swapchain {
    fn acquire_frame(&mut self, sync: hal::FrameSync<Backend>) -> hal::Frame {
        let (semaphore, fence) = match sync {
            hal::FrameSync::Semaphore(semaphore) => (semaphore.0, vk::Fence::null()),
            hal::FrameSync::Fence(fence) => (vk::Semaphore::null(), fence.0),
        };

        let index = unsafe {
            // will block if no image is available
            self.functor.acquire_next_image_khr(self.raw, !0, semaphore, fence)
        }.expect("Unable to acquire a swapchain image");

        self.frame_queue.push_back(index as usize);
        hal::Frame::new(index as usize)
    }

    fn present<C>(
        &mut self,
        present_queue: &mut hal::CommandQueue<Backend, C>,
        wait_semaphores: &[&native::Semaphore],
    ) {
        let frame = self.frame_queue.pop_front().expect(
            "No frame currently queued up. Need to acquire a frame first.",
        );

        let semaphores = wait_semaphores.iter().map(|sem| sem.0).collect::<Vec<_>>();

        // TODO: wait semaphores
        let info = vk::PresentInfoKHR {
            s_type: vk::StructureType::PresentInfoKhr,
            p_next: ptr::null(),
            wait_semaphore_count: semaphores.len() as u32,
            p_wait_semaphores: semaphores.as_ptr(),
            swapchain_count: 1,
            p_swapchains: &self.raw,
            p_image_indices: &(frame as u32),
            p_results: ptr::null_mut(),
        };

        assert_eq!(Ok(()), unsafe {
            self.functor
                .queue_present_khr(*present_queue.as_raw().raw, &info)
        });
        // TODO: handle result and return code
    }
}
<|endoftext|>


<commit_before>use core::str::FromStr;

use string::String;

use ffi::CString;

use cell::GlobalCellMutRef;

use hal::xen::store::{Result, Error};

use super::imp::{XenStoreImpl, RequestBuilder, XsdSockmsgType};

/// A transaction with the Xen Store
///
/// Note: the transaction is automatically ended on `Drop` if not already
/// down.
pub struct Transaction<'a> {
    ended: bool,
    tx_id: u32,
    imp: GlobalCellMutRef<'a, XenStoreImpl>,
}

impl<'a> Transaction<'a> {
    #[doc(hidden)]
    pub fn new(mut imp: GlobalCellMutRef<'a, XenStoreImpl>) -> Result<Transaction<'a>> {
        let tx_req = {
            RequestBuilder::new(0).set_msg_type(XsdSockmsgType::TransactionStart)
        };

        imp.send(tx_req).and_then(|data| {
            match String::from_utf8(data) {
                Err(..) => Err(Error::Conversion),
                Ok(s) => match u32::from_str(&s[..]) {
                    Err(..) => Err(Error::Conversion),
                    Ok(id) => Ok(Transaction {
                        ended: false,
                        tx_id: id,
                        imp: imp,
                    }),
                },
            }
        })
    }

    /// Read the value pointed by `key`
    pub fn read(&mut self, key: CString) -> Result<String> {
        let req = RequestBuilder::new(self.tx_id).set_msg_type(XsdSockmsgType::Read)
                                                 .append_data(key.as_bytes_with_nul());

        self.imp.send(req).and_then(|data| {
            match String::from_utf8(data) {
                Err(..) => Err(Error::Conversion),
                Ok(s) => Ok(s),
            }
        })
    }

    /// Write the value of `key`
    pub fn write(&mut self, key: CString, value: CString) -> Result<()> {
        let req = {
            RequestBuilder::new(self.tx_id).set_msg_type(XsdSockmsgType::Write)
                                           .append_data(key.as_bytes_with_nul())
                                           .append_data(value.as_bytes_with_nul())
        };

        self.imp.send(req).map(|_| ())
    }

    fn _end(&mut self, data: CString) -> Result<()> {
        let req = {
            RequestBuilder::new(self.tx_id).set_msg_type(XsdSockmsgType::TransactionEnd)
                                           .append_data(data.as_bytes_with_nul())
        };

        self.imp.send(req).and_then(|data| {
            match String::from_utf8(data) {
                Err(..) => Err(Error::Conversion),
                Ok(s) => {
                    match s.as_ref() {
                        "OK" => {
                            self.ended = true;
                            Ok(())
                        }
                        _ => Err(Error::Unknown),
                    }
                }
            }
        })
    }

    /// End the transaction
    pub fn end(&mut self) -> Result<()> {
        self._end(CString::new("T").unwrap())
    }

    /// Abort the transaction
    pub fn abort(&mut self) -> Result<()> {
        self._end(CString::new("F").unwrap())
    }
}

impl<'a> Drop for Transaction<'a> {
    fn drop(&mut self) {
        if !self.ended {
            self.abort().unwrap();
        }
    }
}
<commit_msg>xen/store: Send a null byte on transaction start<commit_after>use core::str::FromStr;

use string::String;

use ffi::CString;

use cell::GlobalCellMutRef;

use hal::xen::store::{Result, Error};

use super::imp::{XenStoreImpl, RequestBuilder, XsdSockmsgType};

/// A transaction with the Xen Store
///
/// Note: the transaction is automatically ended on `Drop` if not already
/// down.
pub struct Transaction<'a> {
    ended: bool,
    tx_id: u32,
    imp: GlobalCellMutRef<'a, XenStoreImpl>,
}

impl<'a> Transaction<'a> {
    #[doc(hidden)]
    pub fn new(mut imp: GlobalCellMutRef<'a, XenStoreImpl>) -> Result<Transaction<'a>> {
        let empty_data = CString::new("").unwrap();

        let tx_req = {
            RequestBuilder::new(0).set_msg_type(XsdSockmsgType::TransactionStart)
                                  .append_data(empty_data.as_bytes_with_nul())
        };

        imp.send(tx_req).and_then(|data| {
            match String::from_utf8(data) {
                Err(..) => Err(Error::Conversion),
                Ok(s) => match u32::from_str(&s[..]) {
                    Err(..) => Err(Error::Conversion),
                    Ok(id) => Ok(Transaction {
                        ended: false,
                        tx_id: id,
                        imp: imp,
                    }),
                },
            }
        })
    }

    /// Read the value pointed by `key`
    pub fn read(&mut self, key: CString) -> Result<String> {
        let req = RequestBuilder::new(self.tx_id).set_msg_type(XsdSockmsgType::Read)
                                                 .append_data(key.as_bytes_with_nul());

        self.imp.send(req).and_then(|data| {
            match String::from_utf8(data) {
                Err(..) => Err(Error::Conversion),
                Ok(s) => Ok(s),
            }
        })
    }

    /// Write the value of `key`
    pub fn write(&mut self, key: CString, value: CString) -> Result<()> {
        let req = {
            RequestBuilder::new(self.tx_id).set_msg_type(XsdSockmsgType::Write)
                                           .append_data(key.as_bytes_with_nul())
                                           .append_data(value.as_bytes_with_nul())
        };

        self.imp.send(req).map(|_| ())
    }

    fn _end(&mut self, data: CString) -> Result<()> {
        let req = {
            RequestBuilder::new(self.tx_id).set_msg_type(XsdSockmsgType::TransactionEnd)
                                           .append_data(data.as_bytes_with_nul())
        };

        self.imp.send(req).and_then(|data| {
            match String::from_utf8(data) {
                Err(..) => Err(Error::Conversion),
                Ok(s) => {
                    match s.as_ref() {
                        "OK" => {
                            self.ended = true;
                            Ok(())
                        }
                        _ => Err(Error::Unknown),
                    }
                }
            }
        })
    }

    /// End the transaction
    pub fn end(&mut self) -> Result<()> {
        self._end(CString::new("T").unwrap())
    }

    /// Abort the transaction
    pub fn abort(&mut self) -> Result<()> {
        self._end(CString::new("F").unwrap())
    }
}

impl<'a> Drop for Transaction<'a> {
    fn drop(&mut self) {
        if !self.ended {
            self.abort().unwrap();
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

mod inst {
    use option::{None, Option, Some};

    #[allow(non_camel_case_types)]
    pub type IMPL_T<A> = Option<A>;

    #[inline(always)]
    pub pure fn EACH<A>(self: &IMPL_T<A>, f: fn(v: &A) -> bool) {
        match *self {
            None => (),
            Some(ref a) => { f(a); }
        }
    }

    #[inline(always)]
    pub pure fn SIZE_HINT<A>(self: &IMPL_T<A>) -> Option<uint> {
        match *self {
            None => Some(0),
            Some(_) => Some(1)
        }
    }
}
<commit_msg>auto merge of #5284 : thestinger/rust/iter-trait, r=brson<commit_after><|endoftext|>


<commit_before>use core::prelude::*;
use alloc::boxed::Box;
use collections::string::String;
use core::{ptr, mem, raw, fmt};
use core::ptr::RawMutPtr;
use core::any::{Any, AnyRefExt};
use core::fmt::Show;
use core::iter;
use libc::{c_void, c_char};
use core::borrow::IntoCow;
use collections::vec::Vec;
use collections::str::MaybeOwned;

use jni::{jobject, jclass, jmethodID, jfieldID, JNIEnv, jint, jstring, jvalue, JNINativeMethod, JavaVM};
#[cfg(target_word_size = "64")] use jni::jlong;
use jni_constants::*;

use log::{logi, loge};

use glinit::GLInit;
use drawevent::Events;
use glcommon::MString;
use libc::types::os::arch::posix88::pid_t;

use rustrt;

extern "C" {
    pub fn gettid() -> pid_t;
}

mod macros;
pub mod texturethread;
pub mod android_bitmap;
pub mod gldataclasses;
pub mod motionevent;

#[cfg(target_word_size = "32")]
#[allow(non_camel_case_types)]
pub type jpointer = jint;
#[cfg(target_word_size = "64")]
#[allow(non_camel_case_types)]
pub type jpointer = jlong;

struct CaseClass {
    constructor: jmethodID,
    class: jclass,
}

struct GLInitEvents<'a> {
    glinit: GLInit<'a>,
    events: Events<'a>,
    jni_undo_callback: JNIUndoCallback,
    owning_thread: pid_t,
}

#[deriving(Copy)]
pub struct JNIUndoCallback {
    callback_obj: jobject,
    callback_method: jmethodID,
}

pub struct JNICallbackClosure<'a> {
    undo_callback: &'a JNIUndoCallback,
    env: *mut JNIEnv,
}

impl JNIUndoCallback {
    pub unsafe fn new(env: *mut JNIEnv, obj: jobject) -> JNIUndoCallback {
        let obj = ((**env).NewGlobalRef)(env, obj);
        let objclass = ((**env).GetObjectClass)(env, obj);
        let method = ((**env).GetMethodID)(env, objclass, cstr!("undoBufferChanged"), cstr!("(I)V"));
        JNIUndoCallback { callback_obj: obj, callback_method: method }
    }

    pub unsafe fn call(&self, env: *mut JNIEnv, new_undo_size: i32) {
        ((**env).CallVoidMethod)(env, self.callback_obj, self.callback_method, new_undo_size as jint);
    }

    pub unsafe fn destroy(self, env: *mut JNIEnv) {
        ((**env).DeleteGlobalRef)(env, self.callback_obj);
    }
    pub fn create_closure(&self, env: *mut JNIEnv) -> JNICallbackClosure {
        JNICallbackClosure { undo_callback: self, env: env }
    }
}

impl CaseClass {
    pub unsafe fn new(env: *mut JNIEnv, name: *const c_char, sig: *const c_char) -> CaseClass {
        let class = ((**env).FindClass)(env, name);
        let constructor = ((**env).GetMethodID)(env, class, cstr!("<init>"), sig);
        let globalclass = ((**env).NewGlobalRef)(env, class);

        CaseClass { constructor: constructor, class: globalclass }
    }
    pub unsafe fn construct(&self, env: *mut JNIEnv, arg: &mut [jvalue]) -> jobject {
        ((**env).NewObjectA)(env, self.class, self.constructor, arg.as_mut_ptr())
    }
    pub unsafe fn destroy(&mut self, env: *mut JNIEnv) {
        ((**env).DeleteGlobalRef)(env, self.class);
    }
}

unsafe fn get_string(env: *mut JNIEnv, string: jstring) -> Option<String> {
    let string = try_opt!(string.as_mut());
    let c = try_opt!(((**env).GetStringChars)(env, string, ptr::null_mut()).as_ref());
    let len = ((**env).GetStringLength)(env, string);
    let strslice: &[u16] = mem::transmute(raw::Slice { data: c, len: len as uint });
    let ruststr = String::from_utf16(strslice);
    ((**env).ReleaseStringChars)(env, string as jstring, strslice.as_ptr());
    Some(try_opt!(ruststr))
}

unsafe fn get_mstring(env: *mut JNIEnv, string: jstring) -> Option<MString> {
    match get_string(env, string) {
        Some(s) => Some(s.into_cow()),
        None => None,
    }
}

unsafe fn str_to_jstring(env: *mut JNIEnv, s: &str) -> jstring {
    let u16msg: Vec<u16> = s.utf16_units().collect();
    ((**env).NewString)(env, u16msg.as_ptr(), u16msg.len() as i32)
}

pub unsafe fn register_classmethods(env: *mut JNIEnv, classname: *const i8, methods: &[JNINativeMethod]) {
    let class = ((**env).FindClass)(env, classname);
    ((**env).RegisterNatives)(env, class, methods.as_ptr(), methods.len() as i32);
}

fn get_safe_data<'a>(data: jpointer) -> &'a mut GLInitEvents<'a> {
    unsafe {
        let data: &'a mut GLInitEvents<'a> = mem::transmute(data);
        assert_eq!(gettid(), data.owning_thread);
        data
    }
}

#[cfg(target_word_size = "32")]
#[inline(always)]
unsafe fn get_jpointer(env: *mut JNIEnv, obj: jobject, field: jfieldID) -> jpointer {
    ((**env).GetIntField)(env, obj, field)
}
#[cfg(target_word_size = "64")]
#[inline(always)]
unsafe fn get_jpointer(env: *mut JNIEnv, obj: jobject, field: jfieldID) -> jpointer {
    ((**env).GetLongField)(env, obj, field)
}

//#[cfg(target_word_size = "32")]
//#[inline(always)]
//fn set_jpointer(env: *mut JNIEnv, obj: jobject, field: jfieldID) -> jpointer {
    //((**env).SetIntField)(env, obj, field)
//}
//#[cfg(target_word_size = "64")]
//#[inline(always)]
//fn set_jpointer(env: *mut JNIEnv, obj: jobject, field: jfieldID) -> jpointer {
    //((**env).SetLongField)(env, obj, field)
//}

fn on_unwind(msg: &(Any + Send), file: &'static str, line: uint) {
    use core::fmt::FormatWriter;
    // as far as I know there's no way to identify traits that can be cast to Show at runtime
    if let Some(s) = msg.downcast_ref::<&Show>() {
        loge!("fatal error in {}:{} as &Show: {}", file, line, s);
    } else if let Some(s) = msg.downcast_ref::<Box<Show>>() {
        loge!("fatal error in {}:{} as Box<Show>: {}", file, line, &**s);
    } else if let Some(s) = msg.downcast_ref::<&str>() {
        loge!("fatal error in {}:{} as &str: {}", file, line, s);
    } else if let Some(s) = msg.downcast_ref::<String>() {
        loge!("fatal error in {}:{} as String: {}", file, line, s);
    } else if let Some(s) = msg.downcast_ref::<MaybeOwned<'static>>() {
        loge!("fatal error in {}:{} as MaybeOwned: {}", file, line, s);
    } else {
        loge!("fatal error in {}:{}: unknown error message type {}!", file, line, msg.get_type_id());
        loge!("Printing start:");
        unsafe {
            let mut line = Vec::new();
            // stolen from unwind.rs
            struct VecWriter<'a> { v: &'a mut Vec<u8> }
            impl<'a> ::core::fmt::FormatWriter for VecWriter<'a> {
                fn write(&mut self, buf: &[u8]) -> fmt::Result {
                    self.v.push_all(buf);
                    Ok(())
                }
            }

            let width = 32;
            let raw::TraitObject { data: msgptr, vtable: _ } = mem::transmute(msg);
            let msgslice: &[u8] = mem::transmute(raw::Slice { data: msgptr as *const (), len: 1000 });
            let poscounter = iter::count(msgptr as u32, width as u32);
            for (chunk, pos) in msgslice.chunks(width).zip(poscounter) {
                {
                    let mut writer = VecWriter { v: &mut line };
                    let _ = write!(&mut writer, "{:08x}: ", pos);
                    for byte in chunk.iter() {
                        let _ = write!(&mut writer, "{} ", byte);
                    }
                }
                loge!(::core::str::from_utf8_unchecked(line.as_slice().init()));
                line.clear();
            }
        }
    }
}

#[allow(non_snake_case, unused_variables)]
#[no_mangle]
pub unsafe extern "C" fn JNI_OnLoad(vm: *mut JavaVM, reserved: *mut c_void) -> jint {
    logi!("jni onload!!");
    let mut env: *mut c_void = ptr::null_mut();
    if ((**vm).GetEnv)(vm, (&mut env as *mut *mut c_void), JNI_VERSION_1_6) != JNI_OK {
        return -1;
    }
    let env = env as *mut JNIEnv;
    logi!("got environment!: {}", env);

    texturethread::init(env);
    texturethread::init(env);
    android_bitmap::init(env);
    gldataclasses::init(env);
    motionevent::init(env);

    //rustrt::init(1, ["rustjni".as_ptr()].as_ptr());
    rustrt::unwind::register(on_unwind);

    logi!("finished jni_onload");
    JNI_VERSION_1_2
}

#[allow(non_snake_case, unused_variables)]
#[no_mangle]
pub unsafe extern "C" fn JNI_OnUnload(vm: *mut JavaVM, reserved: *mut c_void) {
    logi!("jni onload!!");
    let mut env: *mut c_void = ptr::null_mut();
    if ((**vm).GetEnv)(vm, (&mut env as *mut *mut c_void), JNI_VERSION_1_6) != JNI_OK {
        return;
    }
    let env = env as *mut JNIEnv;
    texturethread::destroy(env);
    texturethread::destroy(env);
    android_bitmap::destroy(env);
    gldataclasses::destroy(env);
    motionevent::destroy(env);
}
<commit_msg>deliberately segfault in on_unwind<commit_after>use core::prelude::*;
use alloc::boxed::Box;
use collections::string::String;
use core::{ptr, mem, raw, fmt};
use core::ptr::RawMutPtr;
use core::any::{Any, AnyRefExt};
use core::fmt::Show;
use core::iter;
use libc::{c_void, c_char};
use core::borrow::IntoCow;
use collections::vec::Vec;
use collections::str::MaybeOwned;

use jni::{jobject, jclass, jmethodID, jfieldID, JNIEnv, jint, jstring, jvalue, JNINativeMethod, JavaVM};
#[cfg(target_word_size = "64")] use jni::jlong;
use jni_constants::*;

use log::{logi, loge};

use glinit::GLInit;
use drawevent::Events;
use glcommon::MString;
use libc::types::os::arch::posix88::pid_t;

use rustrt;

extern "C" {
    pub fn gettid() -> pid_t;
}

mod macros;
pub mod texturethread;
pub mod android_bitmap;
pub mod gldataclasses;
pub mod motionevent;

#[cfg(target_word_size = "32")]
#[allow(non_camel_case_types)]
pub type jpointer = jint;
#[cfg(target_word_size = "64")]
#[allow(non_camel_case_types)]
pub type jpointer = jlong;

struct CaseClass {
    constructor: jmethodID,
    class: jclass,
}

struct GLInitEvents<'a> {
    glinit: GLInit<'a>,
    events: Events<'a>,
    jni_undo_callback: JNIUndoCallback,
    owning_thread: pid_t,
}

#[deriving(Copy)]
pub struct JNIUndoCallback {
    callback_obj: jobject,
    callback_method: jmethodID,
}

pub struct JNICallbackClosure<'a> {
    undo_callback: &'a JNIUndoCallback,
    env: *mut JNIEnv,
}

impl JNIUndoCallback {
    pub unsafe fn new(env: *mut JNIEnv, obj: jobject) -> JNIUndoCallback {
        let obj = ((**env).NewGlobalRef)(env, obj);
        let objclass = ((**env).GetObjectClass)(env, obj);
        let method = ((**env).GetMethodID)(env, objclass, cstr!("undoBufferChanged"), cstr!("(I)V"));
        JNIUndoCallback { callback_obj: obj, callback_method: method }
    }

    pub unsafe fn call(&self, env: *mut JNIEnv, new_undo_size: i32) {
        ((**env).CallVoidMethod)(env, self.callback_obj, self.callback_method, new_undo_size as jint);
    }

    pub unsafe fn destroy(self, env: *mut JNIEnv) {
        ((**env).DeleteGlobalRef)(env, self.callback_obj);
    }
    pub fn create_closure(&self, env: *mut JNIEnv) -> JNICallbackClosure {
        JNICallbackClosure { undo_callback: self, env: env }
    }
}

impl CaseClass {
    pub unsafe fn new(env: *mut JNIEnv, name: *const c_char, sig: *const c_char) -> CaseClass {
        let class = ((**env).FindClass)(env, name);
        let constructor = ((**env).GetMethodID)(env, class, cstr!("<init>"), sig);
        let globalclass = ((**env).NewGlobalRef)(env, class);

        CaseClass { constructor: constructor, class: globalclass }
    }
    pub unsafe fn construct(&self, env: *mut JNIEnv, arg: &mut [jvalue]) -> jobject {
        ((**env).NewObjectA)(env, self.class, self.constructor, arg.as_mut_ptr())
    }
    pub unsafe fn destroy(&mut self, env: *mut JNIEnv) {
        ((**env).DeleteGlobalRef)(env, self.class);
    }
}

unsafe fn get_string(env: *mut JNIEnv, string: jstring) -> Option<String> {
    let string = try_opt!(string.as_mut());
    let c = try_opt!(((**env).GetStringChars)(env, string, ptr::null_mut()).as_ref());
    let len = ((**env).GetStringLength)(env, string);
    let strslice: &[u16] = mem::transmute(raw::Slice { data: c, len: len as uint });
    let ruststr = String::from_utf16(strslice);
    ((**env).ReleaseStringChars)(env, string as jstring, strslice.as_ptr());
    Some(try_opt!(ruststr))
}

unsafe fn get_mstring(env: *mut JNIEnv, string: jstring) -> Option<MString> {
    match get_string(env, string) {
        Some(s) => Some(s.into_cow()),
        None => None,
    }
}

unsafe fn str_to_jstring(env: *mut JNIEnv, s: &str) -> jstring {
    let u16msg: Vec<u16> = s.utf16_units().collect();
    ((**env).NewString)(env, u16msg.as_ptr(), u16msg.len() as i32)
}

pub unsafe fn register_classmethods(env: *mut JNIEnv, classname: *const i8, methods: &[JNINativeMethod]) {
    let class = ((**env).FindClass)(env, classname);
    ((**env).RegisterNatives)(env, class, methods.as_ptr(), methods.len() as i32);
}

fn get_safe_data<'a>(data: jpointer) -> &'a mut GLInitEvents<'a> {
    unsafe {
        let data: &'a mut GLInitEvents<'a> = mem::transmute(data);
        assert_eq!(gettid(), data.owning_thread);
        data
    }
}

#[cfg(target_word_size = "32")]
#[inline(always)]
unsafe fn get_jpointer(env: *mut JNIEnv, obj: jobject, field: jfieldID) -> jpointer {
    ((**env).GetIntField)(env, obj, field)
}
#[cfg(target_word_size = "64")]
#[inline(always)]
unsafe fn get_jpointer(env: *mut JNIEnv, obj: jobject, field: jfieldID) -> jpointer {
    ((**env).GetLongField)(env, obj, field)
}

//#[cfg(target_word_size = "32")]
//#[inline(always)]
//fn set_jpointer(env: *mut JNIEnv, obj: jobject, field: jfieldID) -> jpointer {
    //((**env).SetIntField)(env, obj, field)
//}
//#[cfg(target_word_size = "64")]
//#[inline(always)]
//fn set_jpointer(env: *mut JNIEnv, obj: jobject, field: jfieldID) -> jpointer {
    //((**env).SetLongField)(env, obj, field)
//}

fn on_unwind(msg: &(Any + Send), file: &'static str, line: uint) {
    use core::fmt::FormatWriter;
    // as far as I know there's no way to identify traits that can be cast to Show at runtime
    if let Some(s) = msg.downcast_ref::<&Show>() {
        loge!("fatal error in {}:{} as &Show: {}", file, line, s);
    } else if let Some(s) = msg.downcast_ref::<Box<Show>>() {
        loge!("fatal error in {}:{} as Box<Show>: {}", file, line, &**s);
    } else if let Some(s) = msg.downcast_ref::<&str>() {
        loge!("fatal error in {}:{} as &str: {}", file, line, s);
    } else if let Some(s) = msg.downcast_ref::<String>() {
        loge!("fatal error in {}:{} as String: {}", file, line, s);
    } else if let Some(s) = msg.downcast_ref::<MaybeOwned<'static>>() {
        loge!("fatal error in {}:{} as MaybeOwned: {}", file, line, s);
    } else {
        loge!("fatal error in {}:{}: unknown error message type {}!", file, line, msg.get_type_id());
        loge!("Printing start:");
        unsafe {
            let mut line = Vec::new();
            // stolen from unwind.rs
            struct VecWriter<'a> { v: &'a mut Vec<u8> }
            impl<'a> ::core::fmt::FormatWriter for VecWriter<'a> {
                fn write(&mut self, buf: &[u8]) -> fmt::Result {
                    self.v.push_all(buf);
                    Ok(())
                }
            }

            let width = 32;
            let raw::TraitObject { data: msgptr, vtable: _ } = mem::transmute(msg);
            let msgslice: &[u8] = mem::transmute(raw::Slice { data: msgptr as *const (), len: 1000 });
            let poscounter = iter::count(msgptr as u32, width as u32);
            for (chunk, pos) in msgslice.chunks(width).zip(poscounter) {
                {
                    let mut writer = VecWriter { v: &mut line };
                    let _ = write!(&mut writer, "{:08x}: ", pos);
                    for byte in chunk.iter() {
                        let _ = write!(&mut writer, "{} ", byte);
                    }
                }
                loge!(::core::str::from_utf8_unchecked(line.as_slice().init()));
                line.clear();
            }
        }
    }
    // Unwinding always fails, but not before messing up android's crash report backtrace.
    // So, commit suicide before that can happen.
    unsafe {
        let null: *mut u16 = ptr::null_mut();
        *null = 0xdead;
    }
}

#[allow(non_snake_case, unused_variables)]
#[no_mangle]
pub unsafe extern "C" fn JNI_OnLoad(vm: *mut JavaVM, reserved: *mut c_void) -> jint {
    logi!("jni onload!!");
    let mut env: *mut c_void = ptr::null_mut();
    if ((**vm).GetEnv)(vm, (&mut env as *mut *mut c_void), JNI_VERSION_1_6) != JNI_OK {
        return -1;
    }
    let env = env as *mut JNIEnv;
    logi!("got environment!: {}", env);

    texturethread::init(env);
    texturethread::init(env);
    android_bitmap::init(env);
    gldataclasses::init(env);
    motionevent::init(env);

    //rustrt::init(1, ["rustjni".as_ptr()].as_ptr());
    rustrt::unwind::register(on_unwind);

    logi!("finished jni_onload");
    JNI_VERSION_1_2
}

#[allow(non_snake_case, unused_variables)]
#[no_mangle]
pub unsafe extern "C" fn JNI_OnUnload(vm: *mut JavaVM, reserved: *mut c_void) {
    logi!("jni onload!!");
    let mut env: *mut c_void = ptr::null_mut();
    if ((**vm).GetEnv)(vm, (&mut env as *mut *mut c_void), JNI_VERSION_1_6) != JNI_OK {
        return;
    }
    let env = env as *mut JNIEnv;
    texturethread::destroy(env);
    texturethread::destroy(env);
    android_bitmap::destroy(env);
    gldataclasses::destroy(env);
    motionevent::destroy(env);
}
<|endoftext|>


<commit_before>mod linux;
mod macos;

use crate::*;
use rustc::mir;
use rustc::ty::layout::{Align, LayoutOf, Size};

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn emulate_foreign_item_by_name(
        &mut self,
        link_name: &str,
        args: &[OpTy<'tcx, Tag>],
        dest: PlaceTy<'tcx, Tag>,
        ret: mir::BasicBlock,
    ) -> InterpResult<'tcx, bool> {
        let this = self.eval_context_mut();
        let tcx = &{ this.tcx.tcx };

        match link_name {
            // Environment related shims
            "getenv" => {
                let result = this.getenv(args[0])?;
                this.write_scalar(result, dest)?;
            }

            "unsetenv" => {
                let result = this.unsetenv(args[0])?;
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            "setenv" => {
                let result = this.setenv(args[0], args[1])?;
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            "getcwd" => {
                let result = this.getcwd(args[0], args[1])?;
                this.write_scalar(result, dest)?;
            }

            "chdir" => {
                let result = this.chdir(args[0])?;
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            // File related shims
            "open" | "open64" => {
                let result = this.open(args[0], args[1])?;
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            "fcntl" => {
                let result = this.fcntl(args[0], args[1], args.get(2).cloned())?;
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            "read" => {
                let result = this.read(args[0], args[1], args[2])?;
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            "write" => {
                let fd = this.read_scalar(args[0])?.to_i32()?;
                let buf = this.read_scalar(args[1])?.not_undef()?;
                let n = this.read_scalar(args[2])?.to_machine_usize(tcx)?;
                trace!("Called write({:?}, {:?}, {:?})", fd, buf, n);
                let result = if fd == 1 || fd == 2 {
                    // stdout/stderr
                    use std::io::{self, Write};

                    let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(n))?;
                    // We need to flush to make sure this actually appears on the screen
                    let res = if fd == 1 {
                        // Stdout is buffered, flush to make sure it appears on the screen.
                        // This is the write() syscall of the interpreted program, we want it
                        // to correspond to a write() syscall on the host -- there is no good
                        // in adding extra buffering here.
                        let res = io::stdout().write(buf_cont);
                        io::stdout().flush().unwrap();
                        res
                    } else {
                        // No need to flush, stderr is not buffered.
                        io::stderr().write(buf_cont)
                    };
                    match res {
                        Ok(n) => n as i64,
                        Err(_) => -1,
                    }
                } else {
                    this.write(args[0], args[1], args[2])?
                };
                // Now, `result` is the value we return back to the program.
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            "unlink" => {
                let result = this.unlink(args[0])?;
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            "symlink" => {
                let result = this.symlink(args[0], args[1])?;
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            "rename" => {
                let result = this.rename(args[0], args[1])?;
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            "mkdir" => {
                let result = this.mkdir(args[0], args[1])?;
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            "rmdir" => {
                let result = this.rmdir(args[0])?;
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            "closedir" => {
                let result = this.closedir(args[0])?;
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            "lseek" | "lseek64" => {
                let result = this.lseek64(args[0], args[1], args[2])?;
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            // Other shims
            "posix_memalign" => {
                let ret = this.deref_operand(args[0])?;
                let align = this.read_scalar(args[1])?.to_machine_usize(this)?;
                let size = this.read_scalar(args[2])?.to_machine_usize(this)?;
                // Align must be power of 2, and also at least ptr-sized (POSIX rules).
                if !align.is_power_of_two() {
                    throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align));
                }
                if align < this.pointer_size().bytes() {
                    throw_ub_format!(
                        "posix_memalign: alignment must be at least the size of a pointer, but is {}",
                        align,
                    );
                }

                if size == 0 {
                    this.write_null(ret.into())?;
                } else {
                    let ptr = this.memory.allocate(
                        Size::from_bytes(size),
                        Align::from_bytes(align).unwrap(),
                        MiriMemoryKind::C.into(),
                    );
                    this.write_scalar(ptr, ret.into())?;
                }
                this.write_null(dest)?;
            }

            "dlsym" => {
                let _handle = this.read_scalar(args[0])?;
                let symbol = this.read_scalar(args[1])?.not_undef()?;
                let symbol_name = this.memory.read_c_str(symbol)?;
                let err = format!("bad c unicode symbol: {:?}", symbol_name);
                let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err);
                if let Some(dlsym) = Dlsym::from_str(symbol_name)? {
                    let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym));
                    this.write_scalar(Scalar::from(ptr), dest)?;
                } else {
                    this.write_null(dest)?;
                }
            }

            // Hook pthread calls that go to the thread-local storage memory subsystem.
            "pthread_key_create" => {
                let key_place = this.deref_operand(args[0])?;

                // Extract the function type out of the signature (that seems easier than constructing it ourselves).
                let dtor = match this.test_null(this.read_scalar(args[1])?.not_undef()?)? {
                    Some(dtor_ptr) => Some(this.memory.get_fn(dtor_ptr)?.as_instance()?),
                    None => None,
                };

                // Figure out how large a pthread TLS key actually is.
                // This is `libc::pthread_key_t`.
                let key_type = args[0].layout.ty
                    .builtin_deref(true)
                    .ok_or_else(|| err_ub_format!(
                        "wrong signature used for `pthread_key_create`: first argument must be a raw pointer."
                    ))?
                    .ty;
                let key_layout = this.layout_of(key_type)?;

                // Create key and write it into the memory where `key_ptr` wants it.
                let key = this.machine.tls.create_tls_key(dtor) as u128;
                if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128)
                {
                    throw_unsup!(OutOfTls);
                }

                this.write_scalar(Scalar::from_uint(key, key_layout.size), key_place.into())?;

                // Return success (`0`).
                this.write_null(dest)?;
            }
            "pthread_key_delete" => {
                let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
                this.machine.tls.delete_tls_key(key)?;
                // Return success (0)
                this.write_null(dest)?;
            }
            "pthread_getspecific" => {
                let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
                let ptr = this.machine.tls.load_tls(key, tcx)?;
                this.write_scalar(ptr, dest)?;
            }
            "pthread_setspecific" => {
                let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
                let new_ptr = this.read_scalar(args[1])?.not_undef()?;
                this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?;

                // Return success (`0`).
                this.write_null(dest)?;
            }

            // Stack size/address stuff.
            | "pthread_attr_init"
            | "pthread_attr_destroy"
            | "pthread_self"
            | "pthread_attr_setstacksize" => {
                this.write_null(dest)?;
            }
            "pthread_attr_getstack" => {
                let addr_place = this.deref_operand(args[1])?;
                let size_place = this.deref_operand(args[2])?;

                this.write_scalar(
                    Scalar::from_uint(STACK_ADDR, addr_place.layout.size),
                    addr_place.into(),
                )?;
                this.write_scalar(
                    Scalar::from_uint(STACK_SIZE, size_place.layout.size),
                    size_place.into(),
                )?;

                // Return success (`0`).
                this.write_null(dest)?;
            }

            // We don't support threading.
            "pthread_create" => {
                throw_unsup_format!("Miri does not support threading");
            }

            // Stub out calls for condvar, mutex and rwlock, to just return `0`.
            | "pthread_mutexattr_init"
            | "pthread_mutexattr_settype"
            | "pthread_mutex_init"
            | "pthread_mutexattr_destroy"
            | "pthread_mutex_lock"
            | "pthread_mutex_unlock"
            | "pthread_mutex_destroy"
            | "pthread_rwlock_rdlock"
            | "pthread_rwlock_unlock"
            | "pthread_rwlock_wrlock"
            | "pthread_rwlock_destroy"
            | "pthread_condattr_init"
            | "pthread_condattr_setclock"
            | "pthread_cond_init"
            | "pthread_condattr_destroy"
            | "pthread_cond_destroy"
            => {
                this.write_null(dest)?;
            }

            // We don't support fork so we don't have to do anything for atfork.
            "pthread_atfork" => {
                this.write_null(dest)?;
            }

            // Some things needed for `sys::thread` initialization to go through.
            | "signal"
            | "sigaction"
            | "sigaltstack"
            => {
                this.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?;
            }

            "sysconf" => {
                let name = this.read_scalar(args[0])?.to_i32()?;

                trace!("sysconf() called with name {}", name);
                // TODO: Cache the sysconf integers via Miri's global cache.
                let paths = &[
                    (&["libc", "_SC_PAGESIZE"], Scalar::from_int(PAGE_SIZE, dest.layout.size)),
                    (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)),
                    (
                        &["libc", "_SC_NPROCESSORS_ONLN"],
                        Scalar::from_int(NUM_CPUS, dest.layout.size),
                    ),
                ];
                let mut result = None;
                for &(path, path_value) in paths {
                    if let Some(val) = this.eval_path_scalar(path)? {
                        let val = val.to_i32()?;
                        if val == name {
                            result = Some(path_value);
                            break;
                        }
                    }
                }
                if let Some(result) = result {
                    this.write_scalar(result, dest)?;
                } else {
                    throw_unsup_format!("Unimplemented sysconf name: {}", name)
                }
            }

            "isatty" => {
                this.write_null(dest)?;
            }

            "posix_fadvise" => {
                // fadvise is only informational, we can ignore it.
                this.write_null(dest)?;
            }

            "mmap" => {
                // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value.
                let addr = this.read_scalar(args[0])?.not_undef()?;
                this.write_scalar(addr, dest)?;
            }

            "mprotect" => {
                this.write_null(dest)?;
            }

            _ => {
                match this.tcx.sess.target.target.target_os.as_str() {
                    "linux" => return linux::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret),
                    "macos" => return macos::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret),
                    _ => unreachable!(),
                }
            }
        };

        Ok(true)
    }
}
<commit_msg>avoid Scalar::to_bits<commit_after>mod linux;
mod macos;

use crate::*;
use rustc::mir;
use rustc::ty::layout::{Align, LayoutOf, Size};

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn emulate_foreign_item_by_name(
        &mut self,
        link_name: &str,
        args: &[OpTy<'tcx, Tag>],
        dest: PlaceTy<'tcx, Tag>,
        ret: mir::BasicBlock,
    ) -> InterpResult<'tcx, bool> {
        let this = self.eval_context_mut();
        let tcx = &{ this.tcx.tcx };

        match link_name {
            // Environment related shims
            "getenv" => {
                let result = this.getenv(args[0])?;
                this.write_scalar(result, dest)?;
            }

            "unsetenv" => {
                let result = this.unsetenv(args[0])?;
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            "setenv" => {
                let result = this.setenv(args[0], args[1])?;
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            "getcwd" => {
                let result = this.getcwd(args[0], args[1])?;
                this.write_scalar(result, dest)?;
            }

            "chdir" => {
                let result = this.chdir(args[0])?;
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            // File related shims
            "open" | "open64" => {
                let result = this.open(args[0], args[1])?;
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            "fcntl" => {
                let result = this.fcntl(args[0], args[1], args.get(2).cloned())?;
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            "read" => {
                let result = this.read(args[0], args[1], args[2])?;
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            "write" => {
                let fd = this.read_scalar(args[0])?.to_i32()?;
                let buf = this.read_scalar(args[1])?.not_undef()?;
                let n = this.read_scalar(args[2])?.to_machine_usize(tcx)?;
                trace!("Called write({:?}, {:?}, {:?})", fd, buf, n);
                let result = if fd == 1 || fd == 2 {
                    // stdout/stderr
                    use std::io::{self, Write};

                    let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(n))?;
                    // We need to flush to make sure this actually appears on the screen
                    let res = if fd == 1 {
                        // Stdout is buffered, flush to make sure it appears on the screen.
                        // This is the write() syscall of the interpreted program, we want it
                        // to correspond to a write() syscall on the host -- there is no good
                        // in adding extra buffering here.
                        let res = io::stdout().write(buf_cont);
                        io::stdout().flush().unwrap();
                        res
                    } else {
                        // No need to flush, stderr is not buffered.
                        io::stderr().write(buf_cont)
                    };
                    match res {
                        Ok(n) => n as i64,
                        Err(_) => -1,
                    }
                } else {
                    this.write(args[0], args[1], args[2])?
                };
                // Now, `result` is the value we return back to the program.
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            "unlink" => {
                let result = this.unlink(args[0])?;
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            "symlink" => {
                let result = this.symlink(args[0], args[1])?;
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            "rename" => {
                let result = this.rename(args[0], args[1])?;
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            "mkdir" => {
                let result = this.mkdir(args[0], args[1])?;
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            "rmdir" => {
                let result = this.rmdir(args[0])?;
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            "closedir" => {
                let result = this.closedir(args[0])?;
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            "lseek" | "lseek64" => {
                let result = this.lseek64(args[0], args[1], args[2])?;
                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
            }

            // Other shims
            "posix_memalign" => {
                let ret = this.deref_operand(args[0])?;
                let align = this.read_scalar(args[1])?.to_machine_usize(this)?;
                let size = this.read_scalar(args[2])?.to_machine_usize(this)?;
                // Align must be power of 2, and also at least ptr-sized (POSIX rules).
                if !align.is_power_of_two() {
                    throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align));
                }
                if align < this.pointer_size().bytes() {
                    throw_ub_format!(
                        "posix_memalign: alignment must be at least the size of a pointer, but is {}",
                        align,
                    );
                }

                if size == 0 {
                    this.write_null(ret.into())?;
                } else {
                    let ptr = this.memory.allocate(
                        Size::from_bytes(size),
                        Align::from_bytes(align).unwrap(),
                        MiriMemoryKind::C.into(),
                    );
                    this.write_scalar(ptr, ret.into())?;
                }
                this.write_null(dest)?;
            }

            "dlsym" => {
                let _handle = this.read_scalar(args[0])?;
                let symbol = this.read_scalar(args[1])?.not_undef()?;
                let symbol_name = this.memory.read_c_str(symbol)?;
                let err = format!("bad c unicode symbol: {:?}", symbol_name);
                let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err);
                if let Some(dlsym) = Dlsym::from_str(symbol_name)? {
                    let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym));
                    this.write_scalar(Scalar::from(ptr), dest)?;
                } else {
                    this.write_null(dest)?;
                }
            }

            // Hook pthread calls that go to the thread-local storage memory subsystem.
            "pthread_key_create" => {
                let key_place = this.deref_operand(args[0])?;

                // Extract the function type out of the signature (that seems easier than constructing it ourselves).
                let dtor = match this.test_null(this.read_scalar(args[1])?.not_undef()?)? {
                    Some(dtor_ptr) => Some(this.memory.get_fn(dtor_ptr)?.as_instance()?),
                    None => None,
                };

                // Figure out how large a pthread TLS key actually is.
                // This is `libc::pthread_key_t`.
                let key_type = args[0].layout.ty
                    .builtin_deref(true)
                    .ok_or_else(|| err_ub_format!(
                        "wrong signature used for `pthread_key_create`: first argument must be a raw pointer."
                    ))?
                    .ty;
                let key_layout = this.layout_of(key_type)?;

                // Create key and write it into the memory where `key_ptr` wants it.
                let key = this.machine.tls.create_tls_key(dtor) as u128;
                if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128)
                {
                    throw_unsup!(OutOfTls);
                }

                this.write_scalar(Scalar::from_uint(key, key_layout.size), key_place.into())?;

                // Return success (`0`).
                this.write_null(dest)?;
            }
            "pthread_key_delete" => {
                let key = this.force_bits(this.read_scalar(args[0])?.not_undef()?, args[0].layout.size)?;
                this.machine.tls.delete_tls_key(key)?;
                // Return success (0)
                this.write_null(dest)?;
            }
            "pthread_getspecific" => {
                let key = this.force_bits(this.read_scalar(args[0])?.not_undef()?, args[0].layout.size)?;
                let ptr = this.machine.tls.load_tls(key, tcx)?;
                this.write_scalar(ptr, dest)?;
            }
            "pthread_setspecific" => {
                let key = this.force_bits(this.read_scalar(args[0])?.not_undef()?, args[0].layout.size)?;
                let new_ptr = this.read_scalar(args[1])?.not_undef()?;
                this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?;

                // Return success (`0`).
                this.write_null(dest)?;
            }

            // Stack size/address stuff.
            | "pthread_attr_init"
            | "pthread_attr_destroy"
            | "pthread_self"
            | "pthread_attr_setstacksize" => {
                this.write_null(dest)?;
            }
            "pthread_attr_getstack" => {
                let addr_place = this.deref_operand(args[1])?;
                let size_place = this.deref_operand(args[2])?;

                this.write_scalar(
                    Scalar::from_uint(STACK_ADDR, addr_place.layout.size),
                    addr_place.into(),
                )?;
                this.write_scalar(
                    Scalar::from_uint(STACK_SIZE, size_place.layout.size),
                    size_place.into(),
                )?;

                // Return success (`0`).
                this.write_null(dest)?;
            }

            // We don't support threading.
            "pthread_create" => {
                throw_unsup_format!("Miri does not support threading");
            }

            // Stub out calls for condvar, mutex and rwlock, to just return `0`.
            | "pthread_mutexattr_init"
            | "pthread_mutexattr_settype"
            | "pthread_mutex_init"
            | "pthread_mutexattr_destroy"
            | "pthread_mutex_lock"
            | "pthread_mutex_unlock"
            | "pthread_mutex_destroy"
            | "pthread_rwlock_rdlock"
            | "pthread_rwlock_unlock"
            | "pthread_rwlock_wrlock"
            | "pthread_rwlock_destroy"
            | "pthread_condattr_init"
            | "pthread_condattr_setclock"
            | "pthread_cond_init"
            | "pthread_condattr_destroy"
            | "pthread_cond_destroy"
            => {
                this.write_null(dest)?;
            }

            // We don't support fork so we don't have to do anything for atfork.
            "pthread_atfork" => {
                this.write_null(dest)?;
            }

            // Some things needed for `sys::thread` initialization to go through.
            | "signal"
            | "sigaction"
            | "sigaltstack"
            => {
                this.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?;
            }

            "sysconf" => {
                let name = this.read_scalar(args[0])?.to_i32()?;

                trace!("sysconf() called with name {}", name);
                // TODO: Cache the sysconf integers via Miri's global cache.
                let paths = &[
                    (&["libc", "_SC_PAGESIZE"], Scalar::from_int(PAGE_SIZE, dest.layout.size)),
                    (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)),
                    (
                        &["libc", "_SC_NPROCESSORS_ONLN"],
                        Scalar::from_int(NUM_CPUS, dest.layout.size),
                    ),
                ];
                let mut result = None;
                for &(path, path_value) in paths {
                    if let Some(val) = this.eval_path_scalar(path)? {
                        let val = val.to_i32()?;
                        if val == name {
                            result = Some(path_value);
                            break;
                        }
                    }
                }
                if let Some(result) = result {
                    this.write_scalar(result, dest)?;
                } else {
                    throw_unsup_format!("Unimplemented sysconf name: {}", name)
                }
            }

            "isatty" => {
                this.write_null(dest)?;
            }

            "posix_fadvise" => {
                // fadvise is only informational, we can ignore it.
                this.write_null(dest)?;
            }

            "mmap" => {
                // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value.
                let addr = this.read_scalar(args[0])?.not_undef()?;
                this.write_scalar(addr, dest)?;
            }

            "mprotect" => {
                this.write_null(dest)?;
            }

            _ => {
                match this.tcx.sess.target.target.target_os.as_str() {
                    "linux" => return linux::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret),
                    "macos" => return macos::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret),
                    _ => unreachable!(),
                }
            }
        };

        Ok(true)
    }
}
<|endoftext|>


<commit_before>use alloc::boxed::Box;

use core::intrinsics::atomic_singlethreadfence;
use core::u32;

use drivers::pciconfig::PciConfig;

use schemes::KScheme;

const HBA_PxCMD_CR: u32 = 1 << 15;
const HBA_PxCMD_FR: u32 = 1 << 14;
const HBA_PxCMD_FRE: u32 = 1 << 4;
const HBA_PxCMD_ST: u32 = 1;

#[repr(packed)]
struct HBAPort {
    clb: u32,
    clbu: u32,
    fb: u32,
    fbu: u32,
    is: u32,
    ie: u32,
    cmd: u32,
    rsv0: u32,
    tfd: u32,
    sig: u32,
    ssts: u32,
    sctl: u32,
    serr: u32,
    sact: u32,
    ci: u32,
    sntf: u32,
    fbs: u32,
    rsv1: [u32; 11],
    vendor: [u32; 4]
}

#[derive(Debug)]
enum HBAPortType {
    None,
    Unknown(u32),
    SATA,
    SATAPI,
    PM,
    SEMB,
}

const HBA_PORT_PRESENT: u32 = 0x13;
const SATA_SIG_ATA: u32 = 0x00000101;
const SATA_SIG_ATAPI: u32 = 0xEB140101;
const SATA_SIG_PM: u32 = 0x96690101;
const SATA_SIG_SEMB: u32 = 0xC33C0101;

impl HBAPort {
    pub fn probe(&self) -> HBAPortType {
        if self.ssts & HBA_PORT_PRESENT != HBA_PORT_PRESENT {
            HBAPortType::None
        } else {
            match self.sig {
                SATA_SIG_ATA => HBAPortType::SATA,
                SATA_SIG_ATAPI => HBAPortType::SATAPI,
                SATA_SIG_PM => HBAPortType::PM,
                SATA_SIG_SEMB => HBAPortType::SEMB,
                _ => HBAPortType::Unknown(self.sig)
            }
        }
    }

    pub fn start(&mut self) {
        loop {
            if self.cmd & HBA_PxCMD_CR == 0 {
                break;
            }
            unsafe { atomic_singlethreadfence() };
        }

        self.cmd |= HBA_PxCMD_FRE;
        self.cmd |= HBA_PxCMD_ST;
    }

    pub fn stop(&mut self) {
    	self.cmd &= u32::MAX - HBA_PxCMD_ST;

    	loop {
    		if self.cmd & (HBA_PxCMD_FR | HBA_PxCMD_CR) == 0 {
                break;
            }
            unsafe { atomic_singlethreadfence() };
    	}

    	self.cmd &= u32::MAX - HBA_PxCMD_FRE;
    }

    pub fn slot(&self) -> Option<u32> {
        let slots = self.sact | self.ci;
        for i in 0..32 {
            if slots & 1 << i == 0 {
                return Some(i);
            }
        }
        None
    }
}

#[repr(packed)]
struct HBAMem {
    cap: u32,
    ghc: u32,
    is: u32,
    pi: u32,
    vs: u32,
    ccc_ctl: u32,
    ccc_pts: u32,
    em_loc: u32,
    em_ctl: u32,
    cap2: u32,
    bohc: u32,
    rsv: [u8; 116],
    vendor: [u8; 96],
    ports: [HBAPort; 32]
}

const FIS_TYPE_REG_H2D: u8 = 0x27;	// Register FIS - host to device
const FIS_TYPE_REG_D2H: u8 = 0x34;	// Register FIS - device to host
const FIS_TYPE_DMA_ACT: u8 = 0x39;	// DMA activate FIS - device to host
const FIS_TYPE_DMA_SETUP: u8 = 0x41;	// DMA setup FIS - bidirectional
const FIS_TYPE_DATA: u8 = 0x46;	// Data FIS - bidirectional
const FIS_TYPE_BIST: u8 = 0x58;	// BIST activate FIS - bidirectional
const FIS_TYPE_PIO_SETUP: u8 = 0x5F;	// PIO setup FIS - device to host
const FIS_TYPE_DEV_BITS: u8 = 0xA1;	// Set device bits FIS - device to host

#[repr(packed)]
#[derive(Copy, Clone, Debug, Default)]
struct FisRegH2D{
	// DWORD 0
	fis_type: u8,	// FIS_TYPE_REG_H2D

	pm: u8,	       // Port multiplier, 1: Command, 0: Control

	command: u8,	// Command register
	featurel: u8,	// Feature register, 7:0

	// DWORD 1
	lba0: u8,		// LBA low register, 7:0
	lba1: u8,		// LBA mid register, 15:8
	lba2: u8,		// LBA high register, 23:16
	device: u8,		// Device register

	// DWORD 2
	lba3: u8,		// LBA register, 31:24
	lba4: u8,		// LBA register, 39:32
	lba5: u8,		// LBA register, 47:40
	featureh: u8,	// Feature register, 15:8

	// DWORD 3
	countl: u8,		// Count register, 7:0
	counth: u8,		// Count register, 15:8
	icc: u8,		// Isochronous command completion
	control: u8,	// Control register

	// DWORD 4
	rsv1: [u8; 4],  // Reserved
}

#[repr(packed)]
#[derive(Copy, Clone, Debug, Default)]
struct FisRegD2H {
	// DWORD 0
	fis_type: u8,    // FIS_TYPE_REG_D2H

	pm: u8,          // Port multiplier, Interrupt bit: 2

	status: u8,      // Status register
	error: u8,       // Error register

	// DWORD 1
	lba0: u8,        // LBA low register, 7:0
	lba1: u8,        // LBA mid register, 15:8
	lba2: u8,        // LBA high register, 23:16
	device: u8,      // Device register

	// DWORD 2
	lba3: u8,        // LBA register, 31:24
	lba4: u8,        // LBA register, 39:32
	lba5: u8,        // LBA register, 47:40
	rsv2: u8,        // Reserved

	// DWORD 3
	countl: u8,      // Count register, 7:0
	counth: u8,      // Count register, 15:8
	rsv3: [u8; 2],   // Reserved

	// DWORD 4
	rsv4: [u8; 4],   // Reserved
}

#[repr(packed)]
#[derive(Copy, Clone, Debug, Default)]
struct FisData {
	// DWORD 0
	fis_type: u8,	// FIS_TYPE_DATA

	pm: u8,	        // Port multiplier

	rsv1: [u8; 2],	// Reserved

	// DWORD 1 ~ N
	data: u32,      // Payload
}

#[repr(packed)]
#[derive(Copy, Clone, Debug, Default)]
struct FisPioSetup {
	// DWORD 0
	fis_type: u8,	// FIS_TYPE_PIO_SETUP

	pm: u8,      	// Port multiplier, direction: 4 - device to host, interrupt: 2

	status: u8,		// Status register
	error: u8,		// Error register

	// DWORD 1
	lba0: u8,		// LBA low register, 7:0
	lba1: u8,		// LBA mid register, 15:8
	lba2: u8,		// LBA high register, 23:16
	device: u8,		// Device register

	// DWORD 2
	lba3: u8,		// LBA register, 31:24
	lba4: u8,		// LBA register, 39:32
	lba5: u8,		// LBA register, 47:40
	rsv2: u8,		// Reserved

	// DWORD 3
	countl: u8,		// Count register, 7:0
	counth: u8,		// Count register, 15:8
	rsv3: u8,		// Reserved
	e_status: u8,	// New value of status register

	// DWORD 4
	tc: u16,		// Transfer count
	rsv4: [u8; 2],	// Reserved
}

#[repr(packed)]
#[derive(Copy, Clone, Debug, Default)]
struct FisDmaSetup {
	// DWORD 0
	fis_type: u8,	     // FIS_TYPE_DMA_SETUP

	pm: u8,	             // Port multiplier, direction: 4 - device to host, interrupt: 2, auto-activate: 1

    rsv1: [u8; 2],       // Reserved

	//DWORD 1&2
    DMAbufferID: u64,    // DMA Buffer Identifier. Used to Identify DMA buffer in host memory. SATA Spec says host specific and not in Spec. Trying AHCI spec might work.

    //DWORD 3
    rsv3: u32,           //More reserved

    //DWORD 4
    DMAbufOffset: u32,   //Byte offset into buffer. First 2 bits must be 0

    //DWORD 5
    TransferCount: u32,  //Number of bytes to transfer. Bit 0 must be 0

    //DWORD 6
    rsv6: u32,          //Reserved
}

pub struct Ahci {
    pci: PciConfig,
    mem: *mut HBAMem,
    irq: u8,
}

impl Ahci {
    pub fn new(mut pci: PciConfig) -> Box<Self> {
        let base = unsafe { (pci.read(0x24) & 0xFFFFFFF0) as usize };
        let irq = unsafe { (pci.read(0x3C) & 0xF) as u8 };

        let mut module = box Ahci {
            pci: pci,
            mem: base as *mut HBAMem,
            irq: irq,
        };

        module.init();

        module
    }

    fn init(&mut self) {
        debugln!("AHCI on: {:X} IRQ: {:X}", self.mem as usize, self.irq);

        let mem = unsafe { &mut * self.mem };

        for i in 0..32 {
            if mem.pi & 1 << i == 1 << i {
                debugln!("Port {}: {:X} {:?}", i, mem.ports[i].ssts, mem.ports[i].probe());
            }
        }
    }
}

impl KScheme for Ahci {
    fn on_irq(&mut self, irq: u8) {
        if irq == self.irq {
            debugln!("AHCI IRQ");
        }
    }

    fn on_poll(&mut self) {
    }
}
<commit_msg>More memory structures<commit_after>use alloc::boxed::Box;

use core::intrinsics::atomic_singlethreadfence;
use core::u32;

use drivers::pciconfig::PciConfig;

use schemes::KScheme;

const HBA_PxCMD_CR: u32 = 1 << 15;
const HBA_PxCMD_FR: u32 = 1 << 14;
const HBA_PxCMD_FRE: u32 = 1 << 4;
const HBA_PxCMD_ST: u32 = 1;

#[repr(packed)]
struct HbaPort {
    clb: u32,
    clbu: u32,
    fb: u32,
    fbu: u32,
    is: u32,
    ie: u32,
    cmd: u32,
    rsv0: u32,
    tfd: u32,
    sig: u32,
    ssts: u32,
    sctl: u32,
    serr: u32,
    sact: u32,
    ci: u32,
    sntf: u32,
    fbs: u32,
    rsv1: [u32; 11],
    vendor: [u32; 4]
}

#[derive(Debug)]
enum HbaPortType {
    None,
    Unknown(u32),
    SATA,
    SATAPI,
    PM,
    SEMB,
}

const HBA_PORT_PRESENT: u32 = 0x13;
const SATA_SIG_ATA: u32 = 0x00000101;
const SATA_SIG_ATAPI: u32 = 0xEB140101;
const SATA_SIG_PM: u32 = 0x96690101;
const SATA_SIG_SEMB: u32 = 0xC33C0101;

impl HbaPort {
    pub fn probe(&self) -> HbaPortType {
        if self.ssts & HBA_PORT_PRESENT != HBA_PORT_PRESENT {
            HbaPortType::None
        } else {
            match self.sig {
                SATA_SIG_ATA => HbaPortType::SATA,
                SATA_SIG_ATAPI => HbaPortType::SATAPI,
                SATA_SIG_PM => HbaPortType::PM,
                SATA_SIG_SEMB => HbaPortType::SEMB,
                _ => HbaPortType::Unknown(self.sig)
            }
        }
    }

    pub fn start(&mut self) {
        loop {
            if self.cmd & HBA_PxCMD_CR == 0 {
                break;
            }
            unsafe { atomic_singlethreadfence() };
        }

        self.cmd |= HBA_PxCMD_FRE;
        self.cmd |= HBA_PxCMD_ST;
    }

    pub fn stop(&mut self) {
    	self.cmd &= u32::MAX - HBA_PxCMD_ST;

    	loop {
    		if self.cmd & (HBA_PxCMD_FR | HBA_PxCMD_CR) == 0 {
                break;
            }
            unsafe { atomic_singlethreadfence() };
    	}

    	self.cmd &= u32::MAX - HBA_PxCMD_FRE;
    }

    pub fn slot(&self) -> Option<u32> {
        let slots = self.sact | self.ci;
        for i in 0..32 {
            if slots & 1 << i == 0 {
                return Some(i);
            }
        }
        None
    }
}

#[repr(packed)]
struct HbaMem {
    cap: u32,
    ghc: u32,
    is: u32,
    pi: u32,
    vs: u32,
    ccc_ctl: u32,
    ccc_pts: u32,
    em_loc: u32,
    em_ctl: u32,
    cap2: u32,
    bohc: u32,
    rsv: [u8; 116],
    vendor: [u8; 96],
    ports: [HbaPort; 32]
}

const FIS_TYPE_REG_H2D: u8 = 0x27;	// Register FIS - host to device
const FIS_TYPE_REG_D2H: u8 = 0x34;	// Register FIS - device to host
const FIS_TYPE_DMA_ACT: u8 = 0x39;	// DMA activate FIS - device to host
const FIS_TYPE_DMA_SETUP: u8 = 0x41;	// DMA setup FIS - bidirectional
const FIS_TYPE_DATA: u8 = 0x46;	// Data FIS - bidirectional
const FIS_TYPE_BIST: u8 = 0x58;	// BIST activate FIS - bidirectional
const FIS_TYPE_PIO_SETUP: u8 = 0x5F;	// PIO setup FIS - device to host
const FIS_TYPE_DEV_BITS: u8 = 0xA1;	// Set device bits FIS - device to host

#[repr(packed)]
#[derive(Copy, Clone, Debug, Default)]
struct FisRegH2D{
	// DWORD 0
	fis_type: u8,	// FIS_TYPE_REG_H2D

	pm: u8,	       // Port multiplier, 1: Command, 0: Control

	command: u8,	// Command register
	featurel: u8,	// Feature register, 7:0

	// DWORD 1
	lba0: u8,		// LBA low register, 7:0
	lba1: u8,		// LBA mid register, 15:8
	lba2: u8,		// LBA high register, 23:16
	device: u8,		// Device register

	// DWORD 2
	lba3: u8,		// LBA register, 31:24
	lba4: u8,		// LBA register, 39:32
	lba5: u8,		// LBA register, 47:40
	featureh: u8,	// Feature register, 15:8

	// DWORD 3
	countl: u8,		// Count register, 7:0
	counth: u8,		// Count register, 15:8
	icc: u8,		// Isochronous command completion
	control: u8,	// Control register

	// DWORD 4
	rsv1: [u8; 4],  // Reserved
}

#[repr(packed)]
#[derive(Copy, Clone, Debug, Default)]
struct FisRegD2H {
	// DWORD 0
	fis_type: u8,    // FIS_TYPE_REG_D2H

	pm: u8,          // Port multiplier, Interrupt bit: 2

	status: u8,      // Status register
	error: u8,       // Error register

	// DWORD 1
	lba0: u8,        // LBA low register, 7:0
	lba1: u8,        // LBA mid register, 15:8
	lba2: u8,        // LBA high register, 23:16
	device: u8,      // Device register

	// DWORD 2
	lba3: u8,        // LBA register, 31:24
	lba4: u8,        // LBA register, 39:32
	lba5: u8,        // LBA register, 47:40
	rsv2: u8,        // Reserved

	// DWORD 3
	countl: u8,      // Count register, 7:0
	counth: u8,      // Count register, 15:8
	rsv3: [u8; 2],   // Reserved

	// DWORD 4
	rsv4: [u8; 4],   // Reserved
}

#[repr(packed)]
#[derive(Copy, Clone, Debug, Default)]
struct FisData<T> {
	// DWORD 0
	fis_type: u8,	// FIS_TYPE_DATA

	pm: u8,	        // Port multiplier

	rsv1: [u8; 2],	// Reserved

	// DWORD 1 ~ N
	data: T,      // Payload
}

#[repr(packed)]
#[derive(Copy, Clone, Debug, Default)]
struct FisPioSetup {
	// DWORD 0
	fis_type: u8,	// FIS_TYPE_PIO_SETUP

	pm: u8,      	// Port multiplier, direction: 4 - device to host, interrupt: 2

	status: u8,		// Status register
	error: u8,		// Error register

	// DWORD 1
	lba0: u8,		// LBA low register, 7:0
	lba1: u8,		// LBA mid register, 15:8
	lba2: u8,		// LBA high register, 23:16
	device: u8,		// Device register

	// DWORD 2
	lba3: u8,		// LBA register, 31:24
	lba4: u8,		// LBA register, 39:32
	lba5: u8,		// LBA register, 47:40
	rsv2: u8,		// Reserved

	// DWORD 3
	countl: u8,		// Count register, 7:0
	counth: u8,		// Count register, 15:8
	rsv3: u8,		// Reserved
	e_status: u8,	// New value of status register

	// DWORD 4
	tc: u16,		// Transfer count
	rsv4: [u8; 2],	// Reserved
}

#[repr(packed)]
#[derive(Copy, Clone, Debug, Default)]
struct FisDmaSetup {
	// DWORD 0
	fis_type: u8,	     // FIS_TYPE_DMA_SETUP

	pm: u8,	             // Port multiplier, direction: 4 - device to host, interrupt: 2, auto-activate: 1

    rsv1: [u8; 2],       // Reserved

	//DWORD 1&2
    DMAbufferID: u64,    // DMA Buffer Identifier. Used to Identify DMA buffer in host memory. SATA Spec says host specific and not in Spec. Trying AHCI spec might work.

    //DWORD 3
    rsv3: u32,           //More reserved

    //DWORD 4
    DMAbufOffset: u32,   //Byte offset into buffer. First 2 bits must be 0

    //DWORD 5
    TransferCount: u32,  //Number of bytes to transfer. Bit 0 must be 0

    //DWORD 6
    rsv6: u32,          //Reserved
}

#[repr(packed)]
#[derive(Copy, Clone, Debug, Default)]
struct HbaPrdtEntry {
   dba: u32,		// Data base address
   dbau: u32,		// Data base address upper 32 bits
   rsv0: u32,		// Reserved
   dbc: u32,		// Byte count, 4M max, interrupt = 1
}

#[repr(packed)]
struct HbaCmdTable <T> {
	// 0x00
	cfis: [u8; 64],	// Command FIS

	// 0x40
	acmd: [u8; 16],	// ATAPI command, 12 or 16 bytes

	// 0x50
	rsv: [u8; 48],	// Reserved

	// 0x80
	prdt_entry: T,	// Physical region descriptor table entries, 0 ~ 65535
}

pub struct Ahci {
    pci: PciConfig,
    mem: *mut HbaMem,
    irq: u8,
}

impl Ahci {
    pub fn new(mut pci: PciConfig) -> Box<Self> {
        let base = unsafe { (pci.read(0x24) & 0xFFFFFFF0) as usize };
        let irq = unsafe { (pci.read(0x3C) & 0xF) as u8 };

        let mut module = box Ahci {
            pci: pci,
            mem: base as *mut HbaMem,
            irq: irq,
        };

        module.init();

        module
    }

    fn init(&mut self) {
        debugln!("AHCI on: {:X} IRQ: {:X}", self.mem as usize, self.irq);

        let mem = unsafe { &mut * self.mem };

        for i in 0..32 {
            if mem.pi & 1 << i == 1 << i {
                debugln!("Port {}: {:X} {:?}", i, mem.ports[i].ssts, mem.ports[i].probe());
            }
        }
    }
}

impl KScheme for Ahci {
    fn on_irq(&mut self, irq: u8) {
        if irq == self.irq {
            debugln!("AHCI IRQ");
        }
    }

    fn on_poll(&mut self) {
    }
}
<|endoftext|>


<commit_before>use std::ptr;
use std::vec;
use ll::*;

pub trait Window {
    fn hwnd(&self) -> HWND;
}

pub struct EmptyWindow {
    raw: HWND,
}

impl Window for EmptyWindow {
    fn hwnd(&self) -> HWND {
        self.raw
    }
}

pub fn null() -> EmptyWindow {
    EmptyWindow {
        raw: ptr::null(),
    }
}

pub trait WindowUtil {
    pub fn message_box(&self, msg: &str, title: &str);
}

impl<T: Window> WindowUtil for T {
    pub fn message_box(&self, msg: &str, title: &str) {
        let wmsg = msg.to_utf16();
        wmsg.push(0u16);
        let wtitle = title.to_utf16();
        wtitle.push(0u16);
        unsafe {
            user32::MessageBoxW(self.hwnd(),
            vec::raw::to_ptr(wmsg), vec::raw::to_ptr(wtitle),
            0u32);
        }
    }
}
<commit_msg>Use std::os::win32::as_utf16_p()<commit_after>use std::ptr;
use std::os::win32::as_utf16_p;
use ll::*;

pub trait Window {
    fn hwnd(&self) -> HWND;
}

pub struct EmptyWindow {
    raw: HWND,
}

impl Window for EmptyWindow {
    fn hwnd(&self) -> HWND {
        self.raw
    }
}

pub fn null() -> EmptyWindow {
    EmptyWindow {
        raw: ptr::null(),
    }
}

pub trait WindowUtil {
    pub fn message_box(&self, msg: &str, title: &str);
}

impl<T: Window> WindowUtil for T {
    pub fn message_box(&self, msg: &str, title: &str) {
        do as_utf16_p(msg) |msg_p| {
            do as_utf16_p(title) |title_p| {
                unsafe {
                    user32::MessageBoxW(self.hwnd(), msg_p, title_p, 0u32);
                }
            }
        }
    }
}
<|endoftext|>