-
Notifications
You must be signed in to change notification settings - Fork 823
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fflush
doesn't work on WASI
#3790
Comments
/bounty $150 |
💎 $150.00 bounty created by syrusakbary |
I am working on this. I was able to reproduce the issue in Rust with // Compile with "cargo build --target wasm32-wasi --release"
use std::io::{self, Write};
fn main() {
let mut buffer = String::new();
let mut stdout = io::stdout().lock();
let stdin = io::stdin();
stdout.write(b"Input something\n").unwrap();
stdout.write(b"> ").unwrap();
stdout.flush().unwrap();
stdin.read_line(&mut buffer).unwrap();
} |
I am trying to look into this but the codebase is quite large I keep jumping from one file to another. Any directions about where the execution of the wasm file happens or where it is passed to the runtime would be much appreciated. |
This issue is basically the same as #363 but it seem that if I run the above reproduction it does not hit the code path that fixed that issue. Also, it seems that my explicit flush in the example is not triggering any flush, nor sync syscalls. The only time that we flush is when closing the files in here. For example use std::io::{self, Write};
fn main() {
let mut stdout = io::stdout().lock();
stdout.flush().unwrap();
stdout.write(b"1").unwrap();
stdout.flush().unwrap();
stdout.write(b"22").unwrap();
stdout.flush().unwrap();
stdout.write(b"333").unwrap();
stdout.flush().unwrap();
stdout.flush().unwrap();
stdout.flush().unwrap();
} We get the following trace, again, note the lack of flush or sync.
Is the compiler not generating the flush call? or is getting optimized away? or are we not picking up the call? Using compiler-explorer I can see that the call is there. See: https://godbolt.org/z/bxhG66o6T @syrusakbary what is your intuition about all this or who could may know? Thanks. |
@ibrahim-akrab Turn on the tracing logs to get some idea.
|
The Wasm file is likely properly generated. So it's likely is an issue in the system call layer (wasmer wasix) |
The problem kind of lies here. Wasmer waits for sync syscall to flush the output but the sync syscall doesn't get generated even when using native binary. And we shouldn't see any flush call either since all file operations are translated to syscalls and the flush is simply a way to tell libc to execute the When tracing the program execution with I fixed the issue by adding handle.flush().await.map_err(map_io_error)?; before the wasmer/lib/wasi/src/syscalls/wasi/fd_write.rs Lines 110 to 148 in bd75b2b
In fact, this also fixes #3814 since it is the same problem. However, I won't be opening a PR for it since @mucinoab did most of the work so it's only fair that he gets the bounty. |
@ibrahim-akrab Nice work. I will confirm your findings and open the PR later today. We can share the bounty. Thanks. |
Note that we do not want to just flush on every write, that would penalize performance for the common case. |
@theduke The thing is that every write syscall is a flushing write. You can't expect to tell the kernel to write to a file then it keeps that piece of information around until you flush it (somehow). Writing then flushing is an abstraction layer provided by programming languages in order to have control over when the actual syscall is called. That's why the wasmer implementation of |
For example, see this item in Rust: Or how the Python print has a flush argument. But I think the main problem to solve here is why the fflush / flush is not triggering anything. right? |
It is triggering the write syscall at the specific point in program execution. And that's it's sole job, to make sure anything left in the buffer gets passed to a write syscall. So it's working as intended. What's not working as intended is wasmers fd_write since at the end of a syscall, we should be sure buffer data is all written from memory to the specific file handler. Of course that's not what happens. The current implementation leaves it to the compiler to decide when to write the data to the file, instead of choosing manually when to write to make it compatible with native binary's execution |
💡 mucinoab submitted a pull request that claims the bounty. You can visit your org dashboard to reward. |
@mucinoab we are waiting for some testing code. Please add it quickly or we will resolve the ticket ourself and the bounty will not be distributed. |
@ibrahim-akrab please take over, I am too busy right now to deal with the urgency. Thanks. |
🎉🎈 @mucinoab has been awarded $150.00! 🎈🎊 |
Describe the bug
fflush
provided by wasi-sdk doesn't work on wasmer.wasmer -vV; rustc -vV wasmer 3.2.0 (8a343d0 2023-04-18) binary: wasmer-cli commit-hash: 8a343d0f9a1d3d4b4bfe622ed345253d780a3d76 commit-date: 2023-04-18 host: x86_64-unknown-linux-gnu compiler: singlepass,cranelift,llvm sh: 1: rustc: not found
Steps to reproduce
sample C program:
I built this using wasi-sdk 19.0. (
${WASI_SDK_PATH}/bin/clang --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot -o out.wasm main.c
)On host, prompt (
>
) is printed byfflush
.On wasmer, prompt (
>
) isn't printed (isn't flushed).Expected behavior
fflush works and buffered strings are printed.
Actual behavior
fflush doesn't work and buffered strings aren't printed.
Additional context
The text was updated successfully, but these errors were encountered: