|
17 | 17 | #[doc(inline)] pub use alloc_system::System;
|
18 | 18 | #[doc(inline)] pub use core::alloc::*;
|
19 | 19 |
|
| 20 | +use core::sync::atomic::{AtomicPtr, Ordering}; |
| 21 | +use core::{mem, ptr}; |
| 22 | + |
| 23 | +static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut()); |
| 24 | + |
| 25 | +/// Registers a custom OOM hook, replacing any that was previously registered. |
| 26 | +/// |
| 27 | +/// The OOM hook is invoked when an infallible memory allocation fails. |
| 28 | +/// The default hook prints a message to standard error and aborts the |
| 29 | +/// execution, but this behavior can be customized with the [`set_oom_hook`] |
| 30 | +/// and [`take_oom_hook`] functions. |
| 31 | +/// |
| 32 | +/// The hook is provided with a `Layout` struct which contains information |
| 33 | +/// about the allocation that failed. |
| 34 | +/// |
| 35 | +/// The OOM hook is a global resource. |
| 36 | +pub fn set_oom_hook(hook: fn(Layout) -> !) { |
| 37 | + HOOK.store(hook as *mut (), Ordering::SeqCst); |
| 38 | +} |
| 39 | + |
| 40 | +/// Unregisters the current OOM hook, returning it. |
| 41 | +/// |
| 42 | +/// *See also the function [`set_oom_hook`].* |
| 43 | +/// |
| 44 | +/// If no custom hook is registered, the default hook will be returned. |
| 45 | +pub fn take_oom_hook() -> fn(Layout) -> ! { |
| 46 | + let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst); |
| 47 | + if hook.is_null() { |
| 48 | + default_oom_hook |
| 49 | + } else { |
| 50 | + unsafe { mem::transmute(hook) } |
| 51 | + } |
| 52 | +} |
| 53 | + |
| 54 | +fn default_oom_hook(layout: Layout) -> ! { |
| 55 | + rtabort!("memory allocation of {} bytes failed", layout.size()) |
| 56 | +} |
| 57 | + |
20 | 58 | #[cfg(not(test))]
|
21 | 59 | #[doc(hidden)]
|
22 | 60 | #[lang = "oom"]
|
23 |
| -pub extern fn rust_oom(_: Layout) -> ! { |
24 |
| - rtabort!("memory allocation failed"); |
| 61 | +pub extern fn rust_oom(layout: Layout) -> ! { |
| 62 | + let hook = HOOK.load(Ordering::SeqCst); |
| 63 | + let hook: fn(Layout) -> ! = if hook.is_null() { |
| 64 | + default_oom_hook |
| 65 | + } else { |
| 66 | + unsafe { mem::transmute(hook) } |
| 67 | + }; |
| 68 | + hook(layout) |
25 | 69 | }
|
26 | 70 |
|
27 | 71 | #[cfg(not(test))]
|
|
0 commit comments