Skip to content

Commit 26f0a65

Browse files
tropicaaallewisfm
authored andcommitted
vexos: block on stdout writes with size>2048
1 parent d01ce78 commit 26f0a65

File tree

3 files changed

+42
-16
lines changed

3 files changed

+42
-16
lines changed

library/std/src/sys/fs/vexos.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,6 @@ impl OpenOptions {
194194
}
195195

196196
impl File {
197-
// TODO
198197
pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
199198
// Mount sdcard volume as FAT filesystem
200199
map_fresult(unsafe { vex_sdk::vexFileMountSD() })?;

library/std/src/sys/pal/vexos/mod.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ pub mod time;
77

88
use crate::arch::global_asm;
99
use crate::ptr::{self, addr_of_mut};
10+
use crate::sys::stdio;
1011
use crate::time::{Duration, Instant};
1112

1213
global_asm!(
@@ -53,15 +54,13 @@ pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {}
5354
pub unsafe fn cleanup() {
5455
let exit_time = Instant::now();
5556
const FLUSH_TIMEOUT: Duration = Duration::from_millis(15);
56-
const STDIO_CHANNEL: u32 = 1;
5757

5858
// Force the serial buffer to flush
5959
while exit_time.elapsed() < FLUSH_TIMEOUT {
6060
vex_sdk::vexTasksRun();
6161

6262
// If the buffer has been fully flushed, exit the loop
63-
if vex_sdk::vexSerialWriteFree(STDIO_CHANNEL) == (crate::sys::stdio::STDOUT_BUF_SIZE as i32)
64-
{
63+
if vex_sdk::vexSerialWriteFree(stdio::STDIO_CHANNEL) == (stdio::STDOUT_BUF_SIZE as i32) {
6564
break;
6665
}
6766
}

library/std/src/sys/stdio/vexos.rs

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ pub struct Stdin;
44
pub struct Stdout;
55
pub type Stderr = Stdout;
66

7-
const STDIO_CHANNEL: u32 = 1;
7+
pub const STDIO_CHANNEL: u32 = 1;
88

99
impl Stdin {
1010
pub const fn new() -> Stdin {
@@ -14,7 +14,7 @@ impl Stdin {
1414

1515
impl io::Read for Stdin {
1616
fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
17-
let mut written = 0;
17+
let mut count = 0;
1818

1919
while let Some((out_byte, new_buf)) = buf.split_first_mut() {
2020
buf = new_buf;
@@ -25,10 +25,10 @@ impl io::Read for Stdin {
2525
}
2626

2727
*out_byte = byte as u8;
28-
written += 1;
28+
count += 1;
2929
}
3030

31-
Ok(written)
31+
Ok(count)
3232
}
3333
}
3434

@@ -40,20 +40,48 @@ impl Stdout {
4040

4141
impl io::Write for Stdout {
4242
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
43-
let written =
44-
unsafe { vex_sdk::vexSerialWriteBuffer(STDIO_CHANNEL, buf.as_ptr(), buf.len() as u32) };
45-
46-
if written < 0 {
47-
return Err(io::Error::new(
48-
io::ErrorKind::Uncategorized,
49-
"Internal write error occurred.",
50-
));
43+
let mut written = 0;
44+
45+
// HACK: VEXos holds an internal ringbuffer for serial writes that is flushed to USB1
46+
// roughly every millisecond by `vexTasksRun`. For writes larger than 2048 bytes, we
47+
// must block until that buffer is flushed to USB1 before writing the rest of `buf`.
48+
//
49+
// This is fairly nonstandard for a `write` implementation, but it avoids a guaranteed
50+
// recursive panic when using macros such as `print!` to write large amounts of data
51+
// (buf.len() > 2048) to stdout at once.
52+
for chunk in buf.chunks(STDOUT_BUF_SIZE) {
53+
if unsafe { vex_sdk::vexSerialWriteFree(STDIO_CHANNEL) as usize } < chunk.len() {
54+
self.flush().unwrap();
55+
}
56+
57+
let count = unsafe {
58+
vex_sdk::vexSerialWriteBuffer(STDIO_CHANNEL, chunk.as_ptr(), chunk.len() as u32)
59+
};
60+
if count < 0 {
61+
return Err(io::Error::new(
62+
io::ErrorKind::Uncategorized,
63+
"Internal write error occurred.",
64+
));
65+
}
66+
67+
written += count;
68+
69+
// This is a sanity check to ensure that we don't end up with non-contiguous
70+
// buffer writes. e.g. a chunk gets only partially written, but we continue
71+
// attempting to write the remaining chunks.
72+
//
73+
// In practice, this should never really occur since the previous flush ensures
74+
// enough space in FIFO to write the entire chunk to vexSerialWriteBuffer.
75+
if count != chunk.len() {
76+
break;
77+
}
5178
}
5279

5380
Ok(written as usize)
5481
}
5582

5683
fn flush(&mut self) -> io::Result<()> {
84+
// This may block for up to a millisecond.
5785
unsafe {
5886
while (vex_sdk::vexSerialWriteFree(STDIO_CHANNEL) as usize) != STDOUT_BUF_SIZE {
5987
vex_sdk::vexTasksRun();

0 commit comments

Comments
 (0)