sys.rs 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. //! System primitives.
  2. use ptr::Pointer;
  3. use fail;
  4. /// A system call error.
  5. #[derive(Copy, Clone, Debug, PartialEq, Eq)]
  6. pub enum Error {
  7. /// Sir, we're running outta memory!
  8. OutOfMemory,
  9. /// An OS error occurred.
  10. Os,
  11. }
  12. impl Error {
  13. /// Handle this error with the appropriate method.
  14. pub fn handle(self) -> ! {
  15. match self {
  16. Error::OutOfMemory => fail::oom(),
  17. Error::Os => panic!("Unknown OS error.")
  18. }
  19. }
  20. }
  21. /// Cooperatively gives up a timeslice to the OS scheduler.
  22. pub fn yield_now() {
  23. unsafe {
  24. #[cfg(not(target_os = "redox"))]
  25. syscall!(SCHED_YIELD);
  26. #[cfg(target_os = "redox")]
  27. ::system::syscall::unix::sys_yield();
  28. }
  29. }
  30. /// Retrieve the end of the current data segment.
  31. ///
  32. /// This will not change the state of the process in any way, and is thus safe.
  33. #[inline]
  34. pub fn segment_end() -> Result<*const u8, Error> {
  35. unsafe {
  36. sys_brk(0)
  37. }.map(|x| x as *const _)
  38. }
  39. /// Increment data segment of this process by some, _n_, return a pointer to the new data segment
  40. /// start.
  41. ///
  42. /// This uses the system call BRK as backend.
  43. ///
  44. /// This is unsafe for multiple reasons. Most importantly, it can create an inconsistent state,
  45. /// because it is not atomic. Thus, it can be used to create Undefined Behavior.
  46. #[inline]
  47. pub unsafe fn inc_brk(n: usize) -> Result<Pointer<u8>, Error> {
  48. let orig_seg_end = try!(segment_end()) as usize;
  49. if n == 0 { return Ok(Pointer::new(orig_seg_end as *mut u8)) }
  50. let expected_end = try!(orig_seg_end.checked_add(n).ok_or(Error::OutOfMemory));
  51. let new_seg_end = try!(sys_brk(expected_end));
  52. if new_seg_end != expected_end {
  53. // Reset the break.
  54. try!(sys_brk(orig_seg_end));
  55. Err(Error::OutOfMemory)
  56. } else {
  57. Ok(Pointer::new(orig_seg_end as *mut u8))
  58. }
  59. }
  60. /// Redox syscall, BRK.
  61. #[inline]
  62. #[cfg(target_os = "redox")]
  63. unsafe fn sys_brk(n: usize) -> Result<usize, Error> {
  64. use system::syscall;
  65. if let Ok(ret) = syscall::sys_brk(n) {
  66. Ok(ret)
  67. } else {
  68. Err(Error::Os)
  69. }
  70. }
  71. /// Unix syscall, BRK.
  72. #[inline]
  73. #[cfg(not(target_os = "redox"))]
  74. unsafe fn sys_brk(n: usize) -> Result<usize, Error> {
  75. let ret = syscall!(BRK, n);
  76. if ret == !0 {
  77. Err(Error::Os)
  78. } else {
  79. Ok(ret)
  80. }
  81. }
  82. #[cfg(test)]
  83. mod test {
  84. use super::*;
  85. #[test]
  86. fn test_oom() {
  87. unsafe {
  88. assert_eq!(inc_brk(9999999999999).err(), Some(Error::OutOfMemory));
  89. }
  90. }
  91. #[test]
  92. fn test_overflow() {
  93. unsafe {
  94. assert_eq!(inc_brk(!0).err(), Some(Error::OutOfMemory));
  95. assert_eq!(inc_brk(!0 - 2000).err(), Some(Error::OutOfMemory));
  96. }
  97. }
  98. }