fail.rs 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. //! General error handling.
  2. use prelude::*;
  3. use core::sync::atomic::{self, AtomicPtr};
  4. use core::{mem, intrinsics};
  5. use tls;
  6. /// The global OOM handler.
  7. static OOM_HANDLER: AtomicPtr<()> = AtomicPtr::new(default_oom_handler as *mut ());
  8. tls! {
  9. /// The thread-local OOM handler.
  10. static THREAD_OOM_HANDLER: MoveCell<Option<fn() -> !>> = MoveCell::new(None);
  11. }
  12. /// The default OOM handler.
  13. ///
  14. /// This will simply abort the process.
  15. #[cold]
  16. fn default_oom_handler() -> ! {
  17. unsafe {
  18. intrinsics::abort();
  19. }
  20. }
  21. /// Call the OOM handler.
  22. ///
  23. /// This is used one out-of-memory errors, and will never return. Usually, it simply consists
  24. /// of aborting the process.
  25. ///
  26. /// # An important note
  27. ///
  28. /// This is for OOM-conditions, not malformed or too big allocations, but when the system is unable
  29. /// to gather memory for the allocation (SBRK fails).
  30. ///
  31. /// The rule of thumb is that this should be called, if and only if unwinding (which allocates)
  32. /// will hit the same error.
  33. pub fn oom() -> ! {
  34. if let Some(handler) = THREAD_OOM_HANDLER.with(|x| x.replace(None)) {
  35. // There is a local allocator available.
  36. handler();
  37. } else {
  38. unsafe {
  39. // Transmute the atomic pointer to a function pointer and call it.
  40. (mem::transmute::<_, fn() -> !>(OOM_HANDLER.load(atomic::Ordering::SeqCst)))()
  41. }
  42. }
  43. }
  44. /// Set the OOM handler.
  45. ///
  46. /// This is called when the process is out-of-memory.
  47. #[inline]
  48. pub fn set_oom_handler(handler: fn() -> !) {
  49. OOM_HANDLER.store(handler as *mut (), atomic::Ordering::SeqCst);
  50. }
  51. /// Override the OOM handler for the current thread.
  52. ///
  53. /// # Panics
  54. ///
  55. /// This might panic if a thread OOM handler already exists.
  56. #[inline]
  57. pub fn set_thread_oom_handler(handler: fn() -> !) {
  58. THREAD_OOM_HANDLER.with(|thread_oom| {
  59. // Replace it with the new handler.
  60. let res = thread_oom.replace(Some(handler));
  61. // Make sure that it doesn't override another handler.
  62. // TODO: Make this a warning.
  63. debug_assert!(res.is_none(), "Overriding the old handler. Is this intentional?");
  64. });
  65. }
  66. #[cfg(test)]
  67. mod test {
  68. use super::*;
  69. #[test]
  70. #[should_panic]
  71. fn test_panic_oom() {
  72. fn panic() -> ! {
  73. panic!("cats are not cute.");
  74. }
  75. set_oom_handler(panic);
  76. oom();
  77. }
  78. #[test]
  79. #[should_panic]
  80. fn test_panic_thread_oom() {
  81. fn infinite() -> ! {
  82. #[allow(empty_loop)]
  83. loop {}
  84. }
  85. fn panic() -> ! {
  86. panic!("cats are not cute.");
  87. }
  88. set_oom_handler(infinite);
  89. set_thread_oom_handler(panic);
  90. oom();
  91. }
  92. }