fail.rs 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. //! General error handling.
  2. use prelude::*;
  3. use core::sync::atomic::{self, AtomicPtr};
  4. use core::mem;
  5. use shim::config;
  6. #[cfg(feature = "tls")]
  7. use tls;
  8. /// The global OOM handler.
  9. static OOM_HANDLER: AtomicPtr<()> = AtomicPtr::new(config::default_oom_handler as *mut ());
  10. #[cfg(feature = "tls")]
  11. tls! {
  12. /// The thread-local OOM handler.
  13. static THREAD_OOM_HANDLER: MoveCell<Option<fn() -> !>> = MoveCell::new(None);
  14. }
  15. /// Call the OOM handler.
  16. ///
  17. /// This is used one out-of-memory errors, and will never return. Usually, it simply consists
  18. /// of aborting the process.
  19. ///
  20. /// # An important note
  21. ///
  22. /// This is for OOM-conditions, not malformed or too big allocations, but when the system is unable
  23. /// to gather memory for the allocation (SBRK fails).
  24. ///
  25. /// The rule of thumb is that this should be called, if and only if unwinding (which allocates)
  26. /// will hit the same error.
  27. pub fn oom() -> ! {
  28. // If TLS is enabled, we will use the thread-local OOM.
  29. #[cfg(feature = "tls")]
  30. {
  31. if let Some(handler) = THREAD_OOM_HANDLER.with(|x| x.replace(None)) {
  32. log!(DEBUG, "Calling the local OOM handler.");
  33. handler();
  34. }
  35. }
  36. log!(DEBUG, "Calling the global OOM handler.");
  37. unsafe {
  38. // LAST AUDIT: 2016-08-21 (Ticki).
  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. /// Set the OOM handler.
  44. ///
  45. /// This is called when the process is out-of-memory.
  46. #[inline]
  47. pub fn set_oom_handler(handler: fn() -> !) {
  48. log!(NOTE, "Setting the global OOM handler.");
  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. #[cfg(feature = "tls")]
  58. pub fn set_thread_oom_handler(handler: fn() -> !) {
  59. log!(NOTE, "Setting the thread OOM handler.");
  60. THREAD_OOM_HANDLER.with(|thread_oom| {
  61. // Replace it with the new handler.
  62. let old = thread_oom.replace(Some(handler));
  63. // Throw a warning if it overrides another handler.
  64. if old.is_some() {
  65. log!(WARNING, "An old thread OOM handler was overriden.");
  66. }
  67. });
  68. }
  69. #[cfg(test)]
  70. mod test {
  71. use super::*;
  72. #[test]
  73. #[should_panic]
  74. fn panic_oom() {
  75. fn panic() -> ! {
  76. panic!("cats are not cute.");
  77. }
  78. set_oom_handler(panic);
  79. oom();
  80. }
  81. #[test]
  82. #[should_panic]
  83. #[cfg(feature = "tls")]
  84. fn panic_thread_oom() {
  85. fn infinite() -> ! {
  86. #[allow(empty_loop)]
  87. loop {}
  88. }
  89. fn panic() -> ! {
  90. panic!("cats are not cute.");
  91. }
  92. set_oom_handler(infinite);
  93. set_thread_oom_handler(panic);
  94. oom();
  95. }
  96. }