123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- //! System primitives.
- use core::ptr::Unique;
- /// Out of memory.
- ///
- /// In release mode, this will simply abort the process (standard behavior). In debug mode, it will
- /// panic, causing debugging to be easier.
- pub fn oom() -> ! {
- #[cfg(test)]
- panic!("Out of memory.");
- #[cfg(not(test))]
- {
- use fail;
- fail::oom();
- }
- }
- /// A system call error.
- #[derive(Copy, Clone, Debug, PartialEq, Eq)]
- pub enum Error {
- /// Sir, we're running outta memory!
- OutOfMemory,
- /// Arithmetic overflow.
- ArithOverflow,
- /// An unknown error occurred.
- Unknown,
- }
- impl Error {
- /// Handle this error with the appropriate method.
- pub fn handle(self) -> ! {
- match self {
- Error::OutOfMemory | Error::ArithOverflow => oom(),
- Error::Unknown => panic!("Unknown OS error.")
- }
- }
- }
- /// Cooperatively gives up a timeslice to the OS scheduler.
- pub fn yield_now() {
- unsafe {
- #[cfg(unix)]
- syscall!(SCHED_YIELD);
- #[cfg(redox)]
- ::system::syscall::unix::sys_yield();
- }
- }
- /// Retrieve the end of the current data segment.
- ///
- /// This will not change the state of the process in any way, and is thus safe.
- pub fn segment_end() -> Result<*mut u8, Error> {
- unsafe {
- sys_brk(0)
- }.map(|x| x as *mut _)
- }
- /// 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.
- pub fn inc_brk(n: usize) -> Result<Unique<u8>, Error> {
- let orig_seg_end = try!(segment_end()) as usize;
- if n == 0 {
- unsafe {
- return Ok(Unique::new(orig_seg_end as *mut u8))
- }
- }
- let expected_end = try!(orig_seg_end.checked_add(n).ok_or(Error::ArithOverflow));
- let new_seg_end = try!(unsafe { sys_brk(expected_end) });
- if new_seg_end != expected_end {
- // Reset the break.
- try!(unsafe { sys_brk(orig_seg_end) });
- Err(Error::OutOfMemory)
- } else {
- Ok(unsafe { Unique::new(orig_seg_end as *mut u8) })
- }
- }
- /// Redox syscall, BRK.
- #[cfg(target_os = "redox")]
- unsafe fn sys_brk(n: usize) -> Result<usize, Error> {
- use system::syscall;
- if let Ok(ret) = syscall::sys_brk(n) {
- Ok(ret)
- } else {
- Err(Error::Unknown)
- }
- }
- /// Unix syscall, BRK.
- #[cfg(not(target_os = "redox"))]
- unsafe fn sys_brk(n: usize) -> Result<usize, Error> {
- let ret = syscall!(BRK, n);
- if ret == !0 {
- Err(Error::Unknown)
- } else {
- Ok(ret)
- }
- }
- #[cfg(test)]
- mod test {
- use super::*;
- #[test]
- fn test_oom() {
- assert_eq!(inc_brk(9999999999999).err(), Some(Error::OutOfMemory));
- }
- #[test]
- fn test_read() {
- let mem = *inc_brk(8).unwrap() as *mut u64;
- unsafe {
- assert_eq!(*mem, 0);
- }
- }
- #[test]
- fn test_overflow() {
- assert_eq!(inc_brk(!0).err(), Some(Error::ArithOverflow));
- assert_eq!(inc_brk(!0 - 2000).err(), Some(Error::ArithOverflow));
- }
- #[test]
- fn test_empty() {
- assert_eq!(*inc_brk(0).unwrap(), segment_end().unwrap())
- }
- #[test]
- fn test_segment_end() {
- assert_eq!(segment_end().unwrap(), segment_end().unwrap());
- assert_eq!(segment_end().unwrap(), segment_end().unwrap());
- assert_eq!(segment_end().unwrap(), segment_end().unwrap());
- }
- }
|