qbicc / qbicc-class-library

The run time class library for qbicc native images
Other
13 stars 6 forks source link

EPoll support for Linux #393

Open dgrove-oss opened 1 year ago

dgrove-oss commented 1 year ago

An issue to document the current work in progress.

I've got a branch that implements the epoll natives here: https://github.com/dgrove-oss/qbicc-class-library/tree/epoll I'm not submitting a PR from the branch because once we have union support, we'll want to change the struct definitions in qbicc-runtime-linux's EPoll.java, so no point in introducing a dependency on a declaration we intend to change.

As an experiment, that branch also moves some of the <clinit> of sun.nio.ch.EPoll to runtime. We probably don't want to bother doing that (it was an attempt to see if EPoll could be made to work just by bypassing the need to have the interpreter support unions). Unfortunately, the answer appears to be no...

Once we have a definition of EPoll that seems plausible, here's a unit test we can use to verify it (I originally wrote it to debug the KQueue natives on MacOS).

import java.io.IOException;
import java.nio.channels.Pipe;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Collections;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;

class SelectorTest {

    public static void main(String[] args) throws Exception {
        doTest();
    }

    public static void doTest() throws Exception {
        Selector selector = Selector.open();

        CountDownLatch latch1 = new CountDownLatch(1);
        CountDownLatch latch2 = new CountDownLatch(1);

        new Thread(() -> {
                System.out.println(Thread.currentThread() + " >> Count down");
                latch1.countDown();
                try {
                    System.out.println(Thread.currentThread() + " >> Start select");
                    selector.select();
                    System.out.println(Thread.currentThread() + " >> End select");
                    latch2.countDown();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }).start();

        System.out.println(Thread.currentThread() +  " >> Start await");
        latch1.await();
        System.out.println(Thread.currentThread() +  " >> End await");

        System.out.println(Thread.currentThread() + " >> Wakeup thread");
        selector.wakeup();

        System.out.println(Thread.currentThread() +  " >> Start await 2");
        latch2.await();
        System.out.println(Thread.currentThread() +  " >> End await 2");

        //clean up
        selector.close();
    }
}
dmlloyd commented 1 year ago

It looks like we're patching, externally implementing, or otherwise replacing every single member of the EPoll class. Would it be easier if we dropped all of those and supplied our own version of the single class?

Also, here's a completely untested possible idea that I just thought of for getting an offset without needing to initialize an instance of the union; something along the lines of: offsetof(deref(zero().cast(), struct_epoll_event.class).events); (basically use a dereferenced null pointer as the basis for the offset).

dgrove-oss commented 1 year ago

It looks like we're patching, externally implementing, or otherwise replacing every single member of the EPoll class. Would it be easier if we dropped all of those and supplied our own version of the single class?

I'm expecting that once we have union types working, we'll only need the first commit on that branch which just adds native methods. If that's true, then I think we don't need to have our own full version. If we need to do more than that, then yes I agree having our own class is better than having 3 patch classes that collectively change every single element of the class.