sys.rs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. //! System primitives.
  2. use core::ptr::Unique;
  3. /// Out of memory.
  4. ///
  5. /// In release mode, this will simply abort the process (standard behavior). In debug mode, it will
  6. /// panic, causing debugging to be easier.
  7. pub fn oom() -> ! {
  8. #[cfg(test)]
  9. panic!("Out of memory.");
  10. #[cfg(not(test))]
  11. {
  12. use fail;
  13. fail::oom();
  14. }
  15. }
  16. /// A system call error.
  17. #[derive(Copy, Clone, Debug, PartialEq, Eq)]
  18. pub enum Error {
  19. /// Sir, we're running outta memory!
  20. OutOfMemory,
  21. /// Arithmetic overflow.
  22. ArithOverflow,
  23. /// An unknown error occurred.
  24. Unknown,
  25. }
  26. impl Error {
  27. /// Handle this error with the appropriate method.
  28. pub fn handle(self) -> ! {
  29. match self {
  30. Error::OutOfMemory | Error::ArithOverflow => oom(),
  31. Error::Unknown => panic!("Unknown OS error.")
  32. }
  33. }
  34. }
  35. /// Cooperatively gives up a timeslice to the OS scheduler.
  36. pub fn yield_now() {
  37. unsafe {
  38. #[cfg(unix)]
  39. syscall!(SCHED_YIELD);
  40. #[cfg(redox)]
  41. ::system::syscall::unix::sys_yield();
  42. }
  43. }
  44. /// Retrieve the end of the current data segment.
  45. ///
  46. /// This will not change the state of the process in any way, and is thus safe.
  47. pub fn segment_end() -> Result<*mut u8, Error> {
  48. unsafe {
  49. sys_brk(0)
  50. }.map(|x| x as *mut _)
  51. }
  52. /// Increment data segment of this process by some, _n_, return a pointer to the new data segment
  53. /// start.
  54. ///
  55. /// This uses the system call BRK as backend.
  56. pub fn inc_brk(n: usize) -> Result<Unique<u8>, Error> {
  57. let orig_seg_end = try!(segment_end()) as usize;
  58. if n == 0 {
  59. unsafe {
  60. return Ok(Unique::new(orig_seg_end as *mut u8))
  61. }
  62. }
  63. let expected_end = try!(orig_seg_end.checked_add(n).ok_or(Error::ArithOverflow));
  64. let new_seg_end = try!(unsafe { sys_brk(expected_end) });
  65. if new_seg_end != expected_end {
  66. // Reset the break.
  67. try!(unsafe { sys_brk(orig_seg_end) });
  68. Err(Error::OutOfMemory)
  69. } else {
  70. Ok(unsafe { Unique::new(orig_seg_end as *mut u8) })
  71. }
  72. }
  73. /// Redox syscall, BRK.
  74. #[cfg(target_os = "redox")]
  75. unsafe fn sys_brk(n: usize) -> Result<usize, Error> {
  76. use system::syscall;
  77. if let Ok(ret) = syscall::sys_brk(n) {
  78. Ok(ret)
  79. } else {
  80. Err(Error::Unknown)
  81. }
  82. }
  83. /// Unix syscall, BRK.
  84. #[cfg(not(target_os = "redox"))]
  85. unsafe fn sys_brk(n: usize) -> Result<usize, Error> {
  86. let ret = syscall!(BRK, n);
  87. if ret == !0 {
  88. Err(Error::Unknown)
  89. } else {
  90. Ok(ret)
  91. }
  92. }
  93. #[cfg(test)]
  94. mod test {
  95. use super::*;
  96. #[test]
  97. fn test_oom() {
  98. assert_eq!(inc_brk(9999999999999).err(), Some(Error::OutOfMemory));
  99. }
  100. #[test]
  101. fn test_read() {
  102. let mem = *inc_brk(8).unwrap() as *mut u64;
  103. unsafe {
  104. assert_eq!(*mem, 0);
  105. }
  106. }
  107. #[test]
  108. fn test_overflow() {
  109. assert_eq!(inc_brk(!0).err(), Some(Error::ArithOverflow));
  110. assert_eq!(inc_brk(!0 - 2000).err(), Some(Error::ArithOverflow));
  111. }
  112. #[test]
  113. fn test_empty() {
  114. assert_eq!(*inc_brk(0).unwrap(), segment_end().unwrap())
  115. }
  116. #[test]
  117. fn test_segment_end() {
  118. assert_eq!(segment_end().unwrap(), segment_end().unwrap());
  119. assert_eq!(segment_end().unwrap(), segment_end().unwrap());
  120. assert_eq!(segment_end().unwrap(), segment_end().unwrap());
  121. }
  122. }