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 { intrinsics::abort() } 96 } 97 }} 98 } 99 100 /// Make a runtime assertion in debug mode. 101 /// 102 /// The only way it differs from the one provided by `libcore` is the panicking strategy, which 103 /// allows for aborting, non-allocating panics when running the tests. 104 #[cfg(feature = "write")] 105 #[macro_export] 106 macro_rules! debug_assert { 107 // We force the programmer to provide explanation of their assertion. 108 ($first:expr, $( $arg:tt )*) => {{ 109 if cfg!(debug_assertions) { 110 assert!($first, $( $arg )*); 111 } 112 }} 113 } 114 115 /// Make a runtime equality assertion in debug mode. 116 /// 117 /// The only way it differs from the one provided by `libcore` is the panicking strategy, which 118 /// allows for aborting, non-allocating panics when running the tests. 119 #[cfg(feature = "write")] 120 #[macro_export] 121 macro_rules! assert_eq { 122 ($left:expr, $right:expr) => ({ 123 // We evaluate _once_. 124 let left = &$left; 125 let right = &$right; 126 127 assert!(left == right, "(left: '{:?}', right: '{:?}')", left, right) 128 }) 129 } 130 131 /// Top-secret module. 132 #[cfg(feature = "log")] 133 pub mod internal { 134 use prelude::*; 135 136 use core::fmt; 137 use core::cell::Cell; 138 use core::ops::Range; 139 140 use shim::config; 141 142 use sync; 143 144 /// The log lock. 145 /// 146 /// This lock is used to avoid bungling and intertwining the log. 147 #[cfg(not(feature = "no_log_lock"))] 148 pub static LOG_LOCK: Mutex<()> = Mutex::new(()); 149 150 /// A log writer. 151 /// 152 /// This writes to the shim logger. 153 pub struct LogWriter { 154 /// The inner lock. 155 #[cfg(not(feature = "no_log_lock"))] 156 _lock: sync::MutexGuard<'static, ()>, 157 } 158 159 impl LogWriter { 160 /// Standard error output. 161 pub fn new() -> LogWriter { 162 #[cfg(feature = "no_log_lock")] 163 { 164 LogWriter {} 165 } 166 167 #[cfg(not(feature = "no_log_lock"))] 168 LogWriter { 169 _lock: LOG_LOCK.lock(), 170 } 171 } 172 } 173 174 impl fmt::Write for LogWriter { 175 fn write_str(&mut self, s: &str) -> fmt::Result { 176 if config::log(s) == !0 { Err(fmt::Error) } else { Ok(()) } 177 } 178 } 179 180 /// A "cursor". 181 /// 182 /// Cursors represents a block or an interval in the log output. This trait is implemented for 183 /// various types that can represent a cursor. 184 pub trait Cursor { 185 /// Iteration at n. 186 /// 187 /// This is called in the logging loop. The cursor should then write, what it needs, to the 188 /// formatter if the underlying condition is true. 189 /// 190 /// For example, a plain position cursor will write `"|"` when `n == self.pos`. 191 // TODO: Use an iterator instead. 192 fn at(&self, f: &mut fmt::Formatter, n: usize) -> fmt::Result; 193 194 /// The after hook. 195 /// 196 /// This is runned when the loop is over. The aim is to e.g. catch up if the cursor wasn't 197 /// printed (i.e. is out of range). 198 fn after(&self, f: &mut fmt::Formatter) -> fmt::Result; 199 } 200 201 /// Types that can be converted into a cursor. 202 pub trait IntoCursor { 203 /// The end result. 204 type Cursor: Cursor; 205 206 /// Convert this value into its equivalent cursor. 207 fn into_cursor(self) -> Self::Cursor; 208 } 209 210 /// A single-point cursor. 211 pub struct UniCursor { 212 /// The position where this cursor will be placed. 213 pos: usize, 214 /// Is this cursor printed? 215 /// 216 /// This is used for the after hook. 217 is_printed: Cell<bool>, 218 } 219 220 impl Cursor for UniCursor { 221 fn at(&self, f: &mut fmt::Formatter, n: usize) -> fmt::Result { 222 if self.pos == n { 223 self.is_printed.set(true); 224 write!(f, "|")?; 225 } 226 227 Ok(()) 228 } 229 230 fn after(&self, f: &mut fmt::Formatter) -> fmt::Result { 231 if !self.is_printed.get() { 232 write!(f, "…|")?; 233 } 234 235 Ok(()) 236 } 237 } 238 239 impl IntoCursor for usize { 240 type Cursor = UniCursor; 241 242 fn into_cursor(self) -> UniCursor { 243 UniCursor { 244 pos: self, 245 is_printed: Cell::new(false), 246 } 247 } 248 } 249 250 impl Cursor for () { 251 fn at(&self, _: &mut fmt::Formatter, _: usize) -> fmt::Result { Ok(()) } 252 253 fn after(&self, _: &mut fmt::Formatter) -> fmt::Result { Ok(()) } 254 } 255 256 impl IntoCursor for () { 257 type Cursor = (); 258 259 fn into_cursor(self) -> () { 260 () 261 } 262 } 263 264 /// A interval/range cursor. 265 /// 266 /// The start of the range is marked by `[` and the end by `]`. 267 pub struct RangeCursor { 268 /// The range of this cursor. 269 range: Range<usize>, 270 } 271 272 impl Cursor for RangeCursor { 273 fn at(&self, f: &mut fmt::Formatter, n: usize) -> fmt::Result { 274 if self.range.start == n { 275 write!(f, "[")?; 276 } else if self.range.end == n { 277 write!(f, "]")?; 278 } 279 280 Ok(()) 281 } 282 283 fn after(&self, _: &mut fmt::Formatter) -> fmt::Result { Ok(()) } 284 } 285 286 impl IntoCursor for Range<usize> { 287 type Cursor = RangeCursor; 288 289 fn into_cursor(self) -> RangeCursor { 290 RangeCursor { 291 range: self, 292 } 293 } 294 } 295 296 /// A "block logger". 297 /// 298 /// This intend to show the structure of a block pool. The syntax used is like: 299 /// 300 /// ``` 301 /// xxx__|xx_ 302 /// ``` 303 /// 304 /// where `x` denotes an non-empty block. `_` denotes an empty block, with `|` representing the 305 /// cursor. 306 pub struct BlockLogger<'a, T> { 307 /// The cursor. 308 /// 309 /// This is where the `|` will be printed. 310 pub cur: T, 311 /// The blocks. 312 pub blocks: &'a [Block], 313 } 314 315 impl<'a, T: Cursor> fmt::Debug for BlockLogger<'a, T> { 316 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 317 // TODO: Handle alignment etc. 318 319 for (n, i) in self.blocks.iter().enumerate() { 320 self.cur.at(f, n)?; 321 322 if i.is_empty() { 323 // Empty block. 324 write!(f, "_")?; 325 } else { 326 // Non-empty block. 327 write!(f, "x")?; 328 } 329 } 330 331 self.cur.after(f)?; 332 333 Ok(()) 334 } 335 } 336 337 /// Check if this log level is enabled. 338 #[allow(absurd_extreme_comparisons)] 339 #[inline] 340 pub fn level(lv: u8) -> bool { 341 lv >= config::MIN_LOG_LEVEL 342 } 343 } 344