Skip to content
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

InputStreamReader.read() blocks indefinitely #990

Open
cyberpython opened this issue Dec 26, 2024 · 3 comments
Open

InputStreamReader.read() blocks indefinitely #990

cyberpython opened this issue Dec 26, 2024 · 3 comments

Comments

@cyberpython
Copy link

  • TeaVM version: 0.11.0
  • JDK: 21.0.2
  • Build tool: Gradle 8.2.1
  • Backend: JS
  • Browser: Firefox 133.3.3 (64-bit)
  • OS: Ubuntu 22.04.5 x86_64

While trying to use piped I/O streams, I found that while reading the data written to the output stream using the piped input stream works, wrapping the input stream with an InputStreamReader causes the reader's read() method to block indefinitely.

Sample code:

/*
 * This Java source file was generated by the Gradle 'init' task.
 */
package example;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

import org.teavm.jso.browser.Window;
import org.teavm.jso.dom.html.HTMLButtonElement;
import org.teavm.jso.dom.html.HTMLDocument;

public class InputStreamReaderIssue {
    private static HTMLDocument document = Window.current().getDocument();
    private static HTMLButtonElement submitButton = document.getElementById("submit-button").cast();
    

    private InputStreamReaderIssue() {
    }

    
    private static PipedInputStream in;
    private static PipedOutputStream out;

    public static void main(String[] args) {
        out = new PipedOutputStream();
        try{
            in = new PipedInputStream(out);
            submitButton.onClick(evt -> submit());
            readLoop();
        }catch(IOException ioe){System.err.println("***INIT ERROR***: "+ioe.getMessage());}
    }

    private static void readLoop() {
        Thread t = new Thread( () -> {
            try{
                InputStreamReader r = new InputStreamReader(in);
                BufferedReader br = new BufferedReader(r);
                while(true){

                    int b = in.read(); // A1
                    System.out.println(b); // A2

                    // Comment the A1, A2, C1, C2 lines and uncomment the following lines to see the issue with read().
                    // int c = r.read(); // B1
                    // System.out.println(c); // B2
                    
                    // Comment the A1, A2, B1, B2 lines and uncomment the following lines to see the issue with readLine.
                    // String line = br.readLine(); // C1
                    // System.out.println(line); // C2
                }
            }catch(IOException ioe){System.err.println("***ERROR reading***: "+ioe.getMessage());}
        });
        t.start();
    }

    private static void submit(){
        String text = "This is a test.";
        try{
            out.write((text+"\n").getBytes());
        }catch(IOException ioe){System.err.println("***ERROR writing***: "+ioe.getMessage());}
    }

}

And the HTML page that loads the JS file:

<!DOCTYPE html>
<html>
  <head>
    <title>Streams I/O Test</title>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
    <script type="text/javascript" charset="utf-8" src="app/build/generated/teavm/js/mylib.js"></script>
  </head>
  <body onload="main()" style="padding: 5px; margin: 0;">
    <button id="submit-button">Write line.</button>
  </body>
</html>
@konsoletyper
Copy link
Owner

I'll try it myself, but are you sure this code does not throw any exception? Seems, that you are trying to run possibly asynchronous code (writing to a pipe) in synchronous context (i.e. native event click handler), which is an error.

@cyberpython
Copy link
Author

Well, I tried the same also with a class extending InputStream that internally uses an ArrayBlockingQueue which had a number of Strings stored in it and then used a separate thread to consume the Strings and print them using the InputStreamReader / BufferedReader, and got the same behavior.

In any case, not of any significance to my use case as I modified my Java code to not involve the use of streams when using TeaVM.

@konsoletyper
Copy link
Owner

Turns out that this issue has nothing to do with native events or PipedInputStream. It was (false) greedy behaviour of BufferedReader and InputStreamReader.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants