Browse Source

Update shim to support Redox

Jeremy Soller 8 years ago
parent
commit
2d54dfe2d7
5 changed files with 183 additions and 110 deletions
  1. 1 1
      Cargo.toml
  2. 5 3
      shim/Cargo.toml
  3. 0 106
      shim/src/lib.rs
  4. 71 0
      shim/src/redox.rs
  5. 106 0
      shim/src/unix.rs

+ 1 - 1
Cargo.toml

@@ -48,4 +48,4 @@ unsafe_no_mutex_lock = []
 write = []
 
 [replace]
-"libc:0.2.17" = { git = "https://github.com/redox-os/liblibc.git", branch = "new_kernel" }
+"libc:0.2.17" = { git = "https://github.com/redox-os/liblibc.git", branch = "redox" }

+ 5 - 3
shim/Cargo.toml

@@ -12,6 +12,8 @@ lto = true
 debug-assertions = false
 codegen-units = 1
 
-[dependencies.libc]
-version = "0.2"
-default-features = false
+[target.'cfg(not(redox))'.dependencies]
+libc = { version = "0.2", default-features = false }
+
+[target.'cfg(redox)'.dependencies]
+redox_syscall = { git = "https://github.com/redox-os/syscall.git" }

+ 0 - 106
shim/src/lib.rs

@@ -5,109 +5,3 @@
 #![feature(linkage)]
 #![no_std]
 #![warn(missing_docs)]
-
-extern crate libc;
-
-pub use libc::sched_yield;
-
-extern {
-    /// Change the data segment. See `man sbrk`.
-    pub fn sbrk(ptr: libc::intptr_t) -> *const libc::c_void;
-    /// Write a buffer to a file descriptor.
-    fn write(fd: libc::c_int, buff: *const libc::c_void, size: libc::size_t) -> libc::ssize_t;
-}
-
-/// Write to the log.
-///
-/// This points to stderr, but could be changed arbitrarily.
-pub fn log(s: &str) -> libc::ssize_t {
-    unsafe { write(2, s.as_ptr() as *const libc::c_void, s.len()) }
-}
-
-/// Thread destructors for Linux.
-#[cfg(target_os = "linux")]
-pub mod thread_destructor {
-    use libc;
-
-    extern {
-        #[linkage = "extern_weak"]
-        static __dso_handle: *mut u8;
-        #[linkage = "extern_weak"]
-        static __cxa_thread_atexit_impl: *const libc::c_void;
-    }
-
-    /// Does this platform support thread destructors?
-    ///
-    /// This will return true, if and only if `__cxa_thread_atexit_impl` is non-null.
-    #[inline]
-    pub fn is_supported() -> bool {
-        !__cxa_thread_atexit_impl.is_null()
-    }
-
-    /// Register a thread destructor.
-    ///
-    /// # Safety
-    ///
-    /// This is unsafe due to accepting (and dereferencing) raw pointers, as well as running an
-    /// arbitrary unsafe function.
-    ///
-    /// On older system without the `__cxa_thread_atexit_impl` symbol, this is unsafe to call, and will
-    /// likely segfault.
-    // TODO: Due to rust-lang/rust#18804, make sure this is not generic!
-    pub unsafe fn register(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
-        use core::mem;
-
-        /// A thread destructor.
-        type Dtor = unsafe extern fn(dtor: unsafe extern fn(*mut u8), arg: *mut u8, dso_handle: *mut u8) -> libc::c_int;
-
-        mem::transmute::<*const libc::c_void, Dtor>(__cxa_thread_atexit_impl)(dtor, t, &__dso_handle as *const _ as *mut _);
-    }
-}
-
-/// Thread destructors for Mac OS.
-#[cfg(target_os = "macos")]
-pub mod thread_destructor {
-    use libc;
-
-    /// Does this platform support thread destructors?
-    ///
-    /// This will always return true.
-    #[inline]
-    pub fn is_supported() -> bool { true }
-
-    /// Register a thread destructor.
-    ///
-    /// # Safety
-    ///
-    /// This is unsafe due to accepting (and dereferencing) raw pointers, as well as running an
-    /// arbitrary unsafe function.
-    #[cfg(target_os = "macos")]
-    pub unsafe fn register(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
-        extern {
-            fn _tlv_atexit(dtor: unsafe extern fn(*mut u8), arg: *mut u8);
-        }
-
-        _tlv_atexit(dtor, t);
-    }
-}
-
-/// Debugging.
-pub mod debug {
-    use libc;
-
-    extern {
-        /// Valgrind symbol to declare memory undefined.
-        fn valgrind_make_mem_undefined(ptr: *const libc::c_void, size: libc::size_t);
-        /// Valgrind symbol to declare memory freed.
-        fn valgrind_freelike_block(ptr: *const libc::c_void, size: libc::size_t);
-    }
-
-    /// Mark this segment undefined to the debugger.
-    pub fn mark_undefined(ptr: *const libc::c_void, size: libc::size_t) {
-        unsafe { valgrind_make_mem_undefined(ptr, size) }
-    }
-    /// Mark this segment free to the debugger.
-    pub fn mark_free(ptr: *const libc::c_void, size: libc::size_t) {
-        unsafe { valgrind_freelike_block(ptr, size) }
-    }
-}

+ 71 - 0
shim/src/redox.rs

@@ -0,0 +1,71 @@
+extern crate system;
+
+use system::syscall::unix::{sys_brk, sys_write, sys_yield};
+
+/// Cooperatively gives up a timeslice to the OS scheduler.
+pub extern "C" fn sched_yield() -> isize {
+    match sys_yield() {
+        Ok(_) => 0,
+        Err(_) => -1
+    }
+}
+
+/// Increment data segment of this process by some, _n_, return a pointer to the new data segment
+/// start.
+///
+/// This uses the system call BRK as backend.
+///
+/// This is unsafe for multiple reasons. Most importantly, it can create an inconsistent state,
+/// because it is not atomic. Thus, it can be used to create Undefined Behavior.
+pub extern "C" fn sbrk(n: isize) -> *mut u8 {
+    let orig_seg_end = match unsafe { sys_brk(0) } {
+        Ok(end) => end,
+        Err(_) => return !0 as *mut u8
+    };
+
+    if n == 0 {
+        return orig_seg_end as *mut u8;
+    }
+
+    let expected_end = match orig_seg_end.checked_add(n as usize) {
+        Some(end) => end,
+        None => return !0 as *mut u8
+    };
+
+    let new_seg_end = match unsafe { sys_brk(expected_end) } {
+        Ok(end) => end,
+        Err(_) => return !0 as *mut u8
+    };
+
+    if new_seg_end != expected_end {
+        // Reset the break.
+        let _ = unsafe { sys_brk(orig_seg_end) };
+
+        !0 as *mut u8
+    } else {
+        orig_seg_end as *mut u8
+    }
+}
+
+/// Write to the log.
+///
+/// This points to stderr, but could be changed arbitrarily.
+pub fn log(s: &str) -> isize {
+    sys_write(2, s.as_bytes()).map(|count| count as isize).unwrap_or(-1)
+}
+
+pub mod thread_destructor {
+    /// Does this platform support thread destructors?
+    ///
+    /// This will always return true.
+    #[inline]
+    pub fn is_supported() -> bool { true }
+
+    /// Register a thread destructor.
+    ///
+    /// # Safety
+    ///
+    /// This is unsafe due to accepting (and dereferencing) raw pointers, as well as running an
+    /// arbitrary unsafe function.
+    pub unsafe fn register(_t: *mut u8, _dtor: unsafe extern fn(*mut u8)) {}
+}

+ 106 - 0
shim/src/unix.rs

@@ -0,0 +1,106 @@
+
+extern crate libc;
+
+pub use libc::sched_yield;
+
+extern {
+    /// Change the data segment. See `man sbrk`.
+    pub fn sbrk(ptr: libc::intptr_t) -> *const libc::c_void;
+    /// Write a buffer to a file descriptor.
+    fn write(fd: libc::c_int, buff: *const libc::c_void, size: libc::size_t) -> libc::ssize_t;
+}
+
+/// Write to the log.
+///
+/// This points to stderr, but could be changed arbitrarily.
+pub fn log(s: &str) -> libc::ssize_t {
+    unsafe { write(2, s.as_ptr() as *const libc::c_void, s.len()) }
+}
+
+/// Thread destructors for Linux.
+#[cfg(target_os = "linux")]
+pub mod thread_destructor {
+    use libc;
+
+    extern {
+        #[linkage = "extern_weak"]
+        static __dso_handle: *mut u8;
+        #[linkage = "extern_weak"]
+        static __cxa_thread_atexit_impl: *const libc::c_void;
+    }
+
+    /// Does this platform support thread destructors?
+    ///
+    /// This will return true, if and only if `__cxa_thread_atexit_impl` is non-null.
+    #[inline]
+    pub fn is_supported() -> bool {
+        !__cxa_thread_atexit_impl.is_null()
+    }
+
+    /// Register a thread destructor.
+    ///
+    /// # Safety
+    ///
+    /// This is unsafe due to accepting (and dereferencing) raw pointers, as well as running an
+    /// arbitrary unsafe function.
+    ///
+    /// On older system without the `__cxa_thread_atexit_impl` symbol, this is unsafe to call, and will
+    /// likely segfault.
+    // TODO: Due to rust-lang/rust#18804, make sure this is not generic!
+    pub unsafe fn register(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
+        use core::mem;
+
+        /// A thread destructor.
+        type Dtor = unsafe extern fn(dtor: unsafe extern fn(*mut u8), arg: *mut u8, dso_handle: *mut u8) -> libc::c_int;
+
+        mem::transmute::<*const libc::c_void, Dtor>(__cxa_thread_atexit_impl)(dtor, t, &__dso_handle as *const _ as *mut _);
+    }
+}
+
+/// Thread destructors for Mac OS.
+#[cfg(target_os = "macos")]
+pub mod thread_destructor {
+    use libc;
+
+    /// Does this platform support thread destructors?
+    ///
+    /// This will always return true.
+    #[inline]
+    pub fn is_supported() -> bool { true }
+
+    /// Register a thread destructor.
+    ///
+    /// # Safety
+    ///
+    /// This is unsafe due to accepting (and dereferencing) raw pointers, as well as running an
+    /// arbitrary unsafe function.
+    #[cfg(target_os = "macos")]
+    pub unsafe fn register(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
+        extern {
+            fn _tlv_atexit(dtor: unsafe extern fn(*mut u8), arg: *mut u8);
+        }
+
+        _tlv_atexit(dtor, t);
+    }
+}
+
+/// Debugging.
+pub mod debug {
+    use libc;
+
+    extern {
+        /// Valgrind symbol to declare memory undefined.
+        fn valgrind_make_mem_undefined(ptr: *const libc::c_void, size: libc::size_t);
+        /// Valgrind symbol to declare memory freed.
+        fn valgrind_freelike_block(ptr: *const libc::c_void, size: libc::size_t);
+    }
+
+    /// Mark this segment undefined to the debugger.
+    pub fn mark_undefined(ptr: *const libc::c_void, size: libc::size_t) {
+        unsafe { valgrind_make_mem_undefined(ptr, size) }
+    }
+    /// Mark this segment free to the debugger.
+    pub fn mark_free(ptr: *const libc::c_void, size: libc::size_t) {
+        unsafe { valgrind_freelike_block(ptr, size) }
+    }
+}