1 //! Allocator logging. 2 //! 3 //! This allows for detailed logging for `ralloc`. 4 5 /// Log to the appropriate source. 6 /// 7 /// The first argument defines the log level, the rest of the arguments are just `write!`-like 8 /// formatters. 9 #[macro_export] 10 macro_rules! log { 11 (INTERNAL, $( $x:tt )*) => { 12 log!(@["INTERNAL: ", 1], $( $x )*); 13 }; 14 (DEBUG, $( $x:tt )*) => { 15 log!(@["DEBUG: ", 2], $( $x )*); 16 }; 17 (CALL, $( $x:tt )*) => { 18 log!(@["CALL: ", 3], $( $x )*); 19 }; 20 (NOTE, $( $x:tt )*) => { 21 log!(@["NOTE: ", 5], $( $x )*); 22 }; 23 (WARNING, $( $x:tt )*) => { 24 log!(@["WARNING: ", 5], $( $x )*); 25 }; 26 (ERROR, $( $x:tt )*) => { 27 log!(@["ERROR: ", 6], $( $x )*); 28 }; 29 (@[$kind:expr, $lv:expr], $( $arg:expr ),*) => { 30 #[cfg(feature = "log")] 31 { 32 use core::fmt::Write; 33 34 use log::internal::{LogWriter, level}; 35 36 // Set the level. 37 if level($lv) { 38 // Print the pool state. 39 let mut log = LogWriter::new(); 40 // Print the log message. 41 let _ = write!(log, $kind); 42 let _ = write!(log, $( $arg ),*); 43 let _ = writeln!(log, " (at {}:{})", file!(), line!()); 44 } 45 } 46 }; 47 } 48 49 /// Log with bookkeeper data to the appropriate source. 50 /// 51 /// The first argument this takes is of the form `pool;cursor`, which is used to print the 52 /// block pools state. `cursor` is what the operation "revolves around" to give a sense of 53 /// position. 54 /// 55 /// If the `;cursor` part is left out, no cursor will be printed. 56 /// 57 /// The rest of the arguments are just normal formatters. 58 /// 59 /// This logs to level 2. 60 #[macro_export] 61 macro_rules! bk_log { 62 ($pool:expr, $( $arg:expr ),*) => { 63 bk_log!($pool;(), $( $arg ),*); 64 }; 65 ($bk:expr;$cur:expr, $( $arg:expr ),*) => { 66 #[cfg(feature = "log")] 67 { 68 use log::internal::{IntoCursor, BlockLogger}; 69 70 log!(INTERNAL, "({:2}) {:10?} : {}", $bk.id, BlockLogger { 71 cur: $cur.clone().into_cursor(), 72 blocks: &$bk.pool, 73 }, format_args!($( $arg ),*)); 74 } 75 }; 76 } 77 78 /// Make a runtime assertion. 79 /// 80 /// The only way it differs from the one provided by `libcore` is the panicking strategy, which 81 /// allows for aborting, non-allocating panics when running the tests. 82 #[macro_export] 83 #[cfg(feature = "write")] 84 macro_rules! assert { 85 ($e:expr) => { 86 assert!($e, "No description."); 87 }; 88 ($e:expr, $( $arg:expr ),*) => {{ 89 use core::intrinsics; 90 91 if !$e { 92 log!(ERROR, $( $arg ),*); 93 94 #[allow(unused_unsafe)] 95 unsafe { 96 // LAST AUDIT: 2016-08-21 (Ticki). 97 98 // Right now there is no safe interface exposed for this, but it is safe no matter 99 // what. 100 intrinsics::abort(); 101 } 102 } 103 }} 104 } 105 106 /// Make a runtime assertion in debug mode. 107 /// 108 /// The only way it differs from the one provided by `libcore` is the panicking strategy, which 109 /// allows for aborting, non-allocating panics when running the tests. 110 #[cfg(feature = "write")] 111 #[macro_export] 112 macro_rules! debug_assert { 113 // We force the programmer to provide explanation of their assertion. 114 ($first:expr, $( $arg:tt )*) => {{ 115 if cfg!(debug_assertions) { 116 assert!($first, $( $arg )*); 117 } 118 }} 119 } 120 121 /// Make a runtime equality assertion in debug mode. 122 /// 123 /// The only way it differs from the one provided by `libcore` is the panicking strategy, which 124 /// allows for aborting, non-allocating panics when running the tests. 125 #[cfg(feature = "write")] 126 #[macro_export] 127 macro_rules! assert_eq { 128 ($left:expr, $right:expr) => ({ 129 // We evaluate _once_. 130 let left = &$left; 131 let right = &$right; 132 133 assert!(left == right, "(left: '{:?}', right: '{:?}')", left, right) 134 }) 135 } 136 137 /// Top-secret module. 138 #[cfg(feature = "log")] 139 pub mod internal { 140 use prelude::*; 141 142 use core::fmt; 143 use core::cell::Cell; 144 use core::ops::Range; 145 146 use shim::config; 147 148 use sync; 149 150 /// The log lock. 151 /// 152 /// This lock is used to avoid bungling and intertwining the log. 153 #[cfg(not(feature = "no_log_lock"))] 154 pub static LOG_LOCK: Mutex<()> = Mutex::new(()); 155 156 /// A log writer. 157 /// 158 /// This writes to the shim logger. 159 pub struct LogWriter { 160 /// The inner lock. 161 #[cfg(not(feature = "no_log_lock"))] 162 _lock: sync::MutexGuard<'static, ()>, 163 } 164 165 impl LogWriter { 166 /// Standard error output. 167 pub fn new() -> LogWriter { 168 #[cfg(feature = "no_log_lock")] 169 { 170 LogWriter {} 171 } 172 173 #[cfg(not(feature = "no_log_lock"))] 174 LogWriter { 175 _lock: LOG_LOCK.lock(), 176 } 177 } 178 } 179 180 impl fmt::Write for LogWriter { 181 fn write_str(&mut self, s: &str) -> fmt::Result { 182 if config::log(s) == !0 { Err(fmt::Error) } else { Ok(()) } 183 } 184 } 185 186 /// A "cursor". 187 /// 188 /// Cursors represents a block or an interval in the log output. This trait is implemented for 189 /// various types that can represent a cursor. 190 pub trait Cursor { 191 /// Iteration at n. 192 /// 193 /// This is called in the logging loop. The cursor should then write, what it needs, to the 194 /// formatter if the underlying condition is true. 195 /// 196 /// For example, a plain position cursor will write `"|"` when `n == self.pos`. 197 // TODO: Use an iterator instead. 198 fn at(&self, f: &mut fmt::Formatter, n: usize) -> fmt::Result; 199 200 /// The after hook. 201 /// 202 /// This is runned when the loop is over. The aim is to e.g. catch up if the cursor wasn't 203 /// printed (i.e. is out of range). 204 fn after(&self, f: &mut fmt::Formatter) -> fmt::Result; 205 } 206 207 /// Types that can be converted into a cursor. 208 pub trait IntoCursor { 209 /// The end result. 210 type Cursor: Cursor; 211 212 /// Convert this value into its equivalent cursor. 213 fn into_cursor(self) -> Self::Cursor; 214 } 215 216 /// A single-point cursor. 217 pub struct UniCursor { 218 /// The position where this cursor will be placed. 219 pos: usize, 220 /// Is this cursor printed? 221 /// 222 /// This is used for the after hook. 223 is_printed: Cell<bool>, 224 } 225 226 impl Cursor for UniCursor { 227 fn at(&self, f: &mut fmt::Formatter, n: usize) -> fmt::Result { 228 if self.pos == n { 229 self.is_printed.set(true); 230 write!(f, "|")?; 231 } 232 233 Ok(()) 234 } 235 236 fn after(&self, f: &mut fmt::Formatter) -> fmt::Result { 237 if !self.is_printed.get() { 238 write!(f, "…|")?; 239 } 240 241 Ok(()) 242 } 243 } 244 245 impl IntoCursor for usize { 246 type Cursor = UniCursor; 247 248 fn into_cursor(self) -> UniCursor { 249 UniCursor { 250 pos: self, 251 is_printed: Cell::new(false), 252 } 253 } 254 } 255 256 impl Cursor for () { 257 fn at(&self, _: &mut fmt::Formatter, _: usize) -> fmt::Result { Ok(()) } 258 259 fn after(&self, _: &mut fmt::Formatter) -> fmt::Result { Ok(()) } 260 } 261 262 impl IntoCursor for () { 263 type Cursor = (); 264 265 fn into_cursor(self) -> () { 266 () 267 } 268 } 269 270 /// A interval/range cursor. 271 /// 272 /// The start of the range is marked by `[` and the end by `]`. 273 pub struct RangeCursor { 274 /// The range of this cursor. 275 range: Range<usize>, 276 } 277 278 impl Cursor for RangeCursor { 279 fn at(&self, f: &mut fmt::Formatter, n: usize) -> fmt::Result { 280 if self.range.start == n { 281 write!(f, "[")?; 282 } else if self.range.end == n { 283 write!(f, "]")?; 284 } 285 286 Ok(()) 287 } 288 289 fn after(&self, _: &mut fmt::Formatter) -> fmt::Result { Ok(()) } 290 } 291 292 impl IntoCursor for Range<usize> { 293 type Cursor = RangeCursor; 294 295 fn into_cursor(self) -> RangeCursor { 296 RangeCursor { 297 range: self, 298 } 299 } 300 } 301 302 /// A "block logger". 303 /// 304 /// This intend to show the structure of a block pool. The syntax used is like: 305 /// 306 /// ``` 307 /// xxx__|xx_ 308 /// ``` 309 /// 310 /// where `x` denotes an non-empty block. `_` denotes an empty block, with `|` representing the 311 /// cursor. 312 pub struct BlockLogger<'a, T> { 313 /// The cursor. 314 /// 315 /// This is where the `|` will be printed. 316 pub cur: T, 317 /// The blocks. 318 pub blocks: &'a [Block], 319 } 320 321 impl<'a, T: Cursor> fmt::Debug for BlockLogger<'a, T> { 322 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 323 // TODO: Handle alignment etc. 324 325 for (n, i) in self.blocks.iter().enumerate() { 326 self.cur.at(f, n)?; 327 328 if i.is_empty() { 329 // Empty block. 330 write!(f, "_")?; 331 } else { 332 // Non-empty block. 333 write!(f, "x")?; 334 } 335 } 336 337 self.cur.after(f)?; 338 339 Ok(()) 340 } 341 } 342 343 /// Check if this log level is enabled. 344 #[allow(absurd_extreme_comparisons)] 345 #[inline] 346 pub fn level(lv: u8) -> bool { 347 lv >= config::MIN_LOG_LEVEL 348 } 349 } 350