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::cell::Cell; 143 use core::fmt; 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 { 183 Err(fmt::Error) 184 } else { 185 Ok(()) 186 } 187 } 188 } 189 190 /// A "cursor". 191 /// 192 /// Cursors represents a block or an interval in the log output. This trait is implemented for 193 /// various types that can represent a cursor. 194 pub trait Cursor { 195 /// Iteration at n. 196 /// 197 /// This is called in the logging loop. The cursor should then write, what it needs, to the 198 /// formatter if the underlying condition is true. 199 /// 200 /// For example, a plain position cursor will write `"|"` when `n == self.pos`. 201 // TODO: Use an iterator instead. 202 fn at(&self, f: &mut fmt::Formatter, n: usize) -> fmt::Result; 203 204 /// The after hook. 205 /// 206 /// This is runned when the loop is over. The aim is to e.g. catch up if the cursor wasn't 207 /// printed (i.e. is out of range). 208 fn after(&self, f: &mut fmt::Formatter) -> fmt::Result; 209 } 210 211 /// Types that can be converted into a cursor. 212 pub trait IntoCursor { 213 /// The end result. 214 type Cursor: Cursor; 215 216 /// Convert this value into its equivalent cursor. 217 fn into_cursor(self) -> Self::Cursor; 218 } 219 220 /// A single-point cursor. 221 pub struct UniCursor { 222 /// The position where this cursor will be placed. 223 pos: usize, 224 /// Is this cursor printed? 225 /// 226 /// This is used for the after hook. 227 is_printed: Cell<bool>, 228 } 229 230 impl Cursor for UniCursor { 231 fn at(&self, f: &mut fmt::Formatter, n: usize) -> fmt::Result { 232 if self.pos == n { 233 self.is_printed.set(true); 234 write!(f, "|")?; 235 } 236 237 Ok(()) 238 } 239 240 fn after(&self, f: &mut fmt::Formatter) -> fmt::Result { 241 if !self.is_printed.get() { 242 write!(f, "…|")?; 243 } 244 245 Ok(()) 246 } 247 } 248 249 impl IntoCursor for usize { 250 type Cursor = UniCursor; 251 252 fn into_cursor(self) -> UniCursor { 253 UniCursor { 254 pos: self, 255 is_printed: Cell::new(false), 256 } 257 } 258 } 259 260 impl Cursor for () { 261 fn at(&self, _: &mut fmt::Formatter, _: usize) -> fmt::Result { 262 Ok(()) 263 } 264 265 fn after(&self, _: &mut fmt::Formatter) -> fmt::Result { 266 Ok(()) 267 } 268 } 269 270 impl IntoCursor for () { 271 type Cursor = (); 272 273 fn into_cursor(self) -> () { 274 () 275 } 276 } 277 278 /// A interval/range cursor. 279 /// 280 /// The start of the range is marked by `[` and the end by `]`. 281 pub struct RangeCursor { 282 /// The range of this cursor. 283 range: Range<usize>, 284 } 285 286 impl Cursor for RangeCursor { 287 fn at(&self, f: &mut fmt::Formatter, n: usize) -> fmt::Result { 288 if self.range.start == n { 289 write!(f, "[")?; 290 } else if self.range.end == n { 291 write!(f, "]")?; 292 } 293 294 Ok(()) 295 } 296 297 fn after(&self, _: &mut fmt::Formatter) -> fmt::Result { 298 Ok(()) 299 } 300 } 301 302 impl IntoCursor for Range<usize> { 303 type Cursor = RangeCursor; 304 305 fn into_cursor(self) -> RangeCursor { 306 RangeCursor { range: self } 307 } 308 } 309 310 /// A "block logger". 311 /// 312 /// This intend to show the structure of a block pool. The syntax used is like: 313 /// 314 /// ``` 315 /// xxx__|xx_ 316 /// ``` 317 /// 318 /// where `x` denotes an non-empty block. `_` denotes an empty block, with `|` representing the 319 /// cursor. 320 pub struct BlockLogger<'a, T> { 321 /// The cursor. 322 /// 323 /// This is where the `|` will be printed. 324 pub cur: T, 325 /// The blocks. 326 pub blocks: &'a [Block], 327 } 328 329 impl<'a, T: Cursor> fmt::Debug for BlockLogger<'a, T> { 330 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 331 // TODO: Handle alignment etc. 332 333 for (n, i) in self.blocks.iter().enumerate() { 334 self.cur.at(f, n)?; 335 336 if i.is_empty() { 337 // Empty block. 338 write!(f, "_")?; 339 } else { 340 // Non-empty block. 341 write!(f, "x")?; 342 } 343 } 344 345 self.cur.after(f)?; 346 347 Ok(()) 348 } 349 } 350 351 /// Check if this log level is enabled. 352 #[inline] 353 pub fn level(lv: u8) -> bool { 354 lv >= config::MIN_LOG_LEVEL 355 } 356 } 357