diff options
Diffstat (limited to '')
| -rw-r--r-- | rsnix/src/serial.rs | 35 |
1 files changed, 27 insertions, 8 deletions
diff --git a/rsnix/src/serial.rs b/rsnix/src/serial.rs index 484a114..2267225 100644 --- a/rsnix/src/serial.rs +++ b/rsnix/src/serial.rs | |||
| @@ -60,8 +60,17 @@ pub fn try_get_byte() -> Option<u8> { | |||
| 60 | } | 60 | } |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | /// Write a string to serial. | 63 | /// Write a string to serial, holding the scheduler lock for the whole |
| 64 | /// write so a line can't be interleaved with another task's output. | ||
| 64 | pub fn write_str(s: &str) { | 65 | pub fn write_str(s: &str) { |
| 66 | crate::sched::lock(); | ||
| 67 | write_raw(s); | ||
| 68 | crate::sched::unlock(); | ||
| 69 | } | ||
| 70 | |||
| 71 | /// Raw serial write — no scheduler lock. Callers must hold the lock | ||
| 72 | /// (klog::emit does) or be in a context where preemption is impossible. | ||
| 73 | pub fn write_raw(s: &str) { | ||
| 65 | for &b in s.as_bytes() { | 74 | for &b in s.as_bytes() { |
| 66 | if b == b'\n' { | 75 | if b == b'\n' { |
| 67 | put_byte(b'\r'); | 76 | put_byte(b'\r'); |
| @@ -70,6 +79,16 @@ pub fn write_str(s: &str) { | |||
| 70 | } | 79 | } |
| 71 | } | 80 | } |
| 72 | 81 | ||
| 82 | /// One scheduler-locked call: the line plus its CRLF, atomic with | ||
| 83 | /// respect to context switches (used by the shell's term_println, where | ||
| 84 | /// the line and its newline must not be split by a tick). | ||
| 85 | pub fn write_line(s: &str) { | ||
| 86 | crate::sched::lock(); | ||
| 87 | write_raw(s); | ||
| 88 | write_raw("\r\n"); | ||
| 89 | crate::sched::unlock(); | ||
| 90 | } | ||
| 91 | |||
| 73 | // --------------------------------------------------------------------------- | 92 | // --------------------------------------------------------------------------- |
| 74 | // fmt::Write implementation | 93 | // fmt::Write implementation |
| 75 | // --------------------------------------------------------------------------- | 94 | // --------------------------------------------------------------------------- |
| @@ -96,17 +115,17 @@ macro_rules! serial_print { | |||
| 96 | /// here, so the ring captures the whole boot sequence for free. | 115 | /// here, so the ring captures the whole boot sequence for free. |
| 97 | /// User-facing shell output must NOT use this macro (shell output would | 116 | /// User-facing shell output must NOT use this macro (shell output would |
| 98 | /// pollute the boot log); it writes to the serial port directly. | 117 | /// pollute the boot log); it writes to the serial port directly. |
| 118 | /// | ||
| 119 | /// The whole line is formatted, written, and logged under one scheduler | ||
| 120 | /// lock (klog::emit), so lines from different tasks never interleave. | ||
| 99 | #[macro_export] | 121 | #[macro_export] |
| 100 | macro_rules! serial_println { | 122 | macro_rules! serial_println { |
| 101 | () => { | 123 | () => { |
| 102 | $crate::serial::write_str("\r\n"); | 124 | $crate::klog::emit(core::format_args!("")) |
| 103 | $crate::klog::append_fmt(core::format_args!("")); | 125 | }; |
| 126 | ($($arg:tt)*) => { | ||
| 127 | $crate::klog::emit(core::format_args!($($arg)*)) | ||
| 104 | }; | 128 | }; |
| 105 | ($($arg:tt)*) => {{ | ||
| 106 | $crate::serial_print!($($arg)*); | ||
| 107 | $crate::serial::write_str("\r\n"); | ||
| 108 | $crate::klog::append_fmt(core::format_args!($($arg)*)); | ||
| 109 | }}; | ||
| 110 | } | 129 | } |
| 111 | 130 | ||
| 112 | // --------------------------------------------------------------------------- | 131 | // --------------------------------------------------------------------------- |
