jart / blink

tiniest x86-64-linux emulator
ISC License
6.99k stars 222 forks source link

epoll support #73

Open borkdude opened 1 year ago

borkdude commented 1 year ago

See discussion here.

johnothwolo commented 1 year ago

@jart I think this can be implmented on BSD and macOS using kqueue, right? As for Windows I don't really know.

jart commented 1 year ago

It can probably be implemented on other platforms using just poll() if necessary. I've implemented epoll() support for just Linux for now. I was hoping it'd be enough to run NodeJS hello world but alas it also wants eventfd.

borkdude commented 1 year ago

I wanted to try it out but I'm getting:

blink/checked.h: In function ‘CheckedAdd’:
blink/checked.h:18:45: error: missing binary operator before token "("
   18 |     (defined(__has_builtin) && __has_builtin(__builtin_add_overflow))
      |                                             ^
blink/checked.h: In function ‘CheckedSub’:
blink/checked.h:39:45: error: missing binary operator before token "("
   39 |     (defined(__has_builtin) && __has_builtin(__builtin_sub_overflow))
      |                                             ^
blink/checked.h: In function ‘CheckedMul’:
blink/checked.h:60:45: error: missing binary operator before token "("
   60 |     (defined(__has_builtin) && __has_builtin(__builtin_mul_overflow))
      |                                             ^
make: *** [build/rules.mk:18: o//blink/checked.h.ok] Error 1
make: *** Waiting for unfinished jobs....
jart commented 1 year ago

Could you try syncing to head and let me know if that fixes things?

borkdude commented 1 year ago

That fixed that error. I'm trying to build on a linux aarch64 fresh ubuntu install. I installed make and gcc.

Now I'm getting:

/usr/bin/ld: /blink/blink/ssefloat.c:281: undefined reference to `sqrt'

Should I tweak some compile flags and what's the best way to do that?

Sorry for the noob questions, I don't normally work a lot with C tooling.

jart commented 1 year ago

Blink builds fine for me on Raspberry Pi if I run:

./configure
make

If sqrt can't be found, then maybe check less config.log and see if -lm is being detected.

borkdude commented 1 year ago

@jart I was able to run it like this on an aarch64 mac + docker:

FROM ubuntu

RUN apt-get update
RUN apt-get -y install gcc git make sudo curl
RUN git clone https://github.com/jart/blink
WORKDIR blink
RUN ./configure
RUN make -j4
RUN sudo make install
RUN curl -sLO https://github.com/babashka/babashka/releases/download/v1.2.174/babashka-1.2.174-linux-amd64.tar.gz
RUN tar xzvf babashka-1.2.174-linux-amd64.tar.gz
RUN blink bb
docker build -t blink .

What I'm getting currently is:

#13 0.228 /lib64/ld-linux-x86-64.so.2: failed to load interpreter (errno 2)
aidanhs commented 1 year ago

The current epoll support seems to not be aware of vfs file descriptors and so chooses overlapping ranges for epoll_ctl fds:

$ cat test.c 
#include <stdio.h>
#include <sys/epoll.h>
#include <unistd.h>
int main() {
    int i;
    for (i = 0; i < 3; i++) {
        printf("ep - %u\n", epoll_create(1));
    }
    for (i = 0; i < 3; i++) {
        int pfds[2];
        pipe(pfds);
        printf("pipe - %u %u\n", pfds[0], pfds[1]);
    }
    return 0;
}
aidanhs@a-winthinkpad:~$ gcc test.c && ./blink/o/blink/blink -m -j -C ubuntu-22.04 ./a.out
ep - 3
ep - 4
ep - 5
pipe - 3 4
pipe - 5 6
pipe - 7 8

I believe (though haven't double checked with a test program) that because it also doesn't do translation from vfs fds to real fds, that epoll_ctl also doesn't work to add file descriptors.

jart commented 1 year ago

@borkdude The bb executable is dynamic. It depends on things like Glibc being provided by the system. Possibly try downloading something like https://dl-cdn.alpinelinux.org/alpine/v3.17/releases/x86_64/alpine-minirootfs-3.17.2-x86_64.tar.gz and using that directory as your chroot using the blink -C alpine-minirootfs-3.17.2-x86_64 flag. You would need to compile Blink using ./configure --enable-vfs. The thing I actually recommend doing though, is try to get a statically compiled build of babashka. Then you don't need to worry about the Linux userspace when running your binaries on MacOS.

trungnt2910 commented 1 year ago

The VFS subsystem was created on a fork before blink adds syscall passthrough support for epoll on Linux.

This can be fixed by simply hooking all epoll family syscalls and translate all input/output fds.

With --enable-vfs, we can also look at supporting this on platforms other than Linux, as we fully manage all file descriptors. However, to truly implement epoll we have to solve #92, as epoll objects are kernel objects that may be shared between processes through fork.

trungnt2910 commented 1 year ago

It might be possible to implement epoll without a dedicated kernel daemon using a dedicated temporary folder instead.

When an epoll fd is created, a temporary file can be opened in a directory hidden to all other blink VFS functions. When the state attached to this epoll fd is read or modified, the file can be mapped into memory using mmap, and then a spinlock can be acquired.

The same probably applies to eventfd.