Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 120 additions & 2 deletions vm/src/unix/prims/unixPrims.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,20 @@ extern "C" {

const char *UnixFile_seal = "UnixFile";

fd_set activeFDs; // active file descriptors
#ifdef USE_EPOLL
int epollFD; // epoll file descriptor

// epoll doesn't work on regular files. The epoll_ctl function
// returns EPERM for any attempt to add such a file descriptor.
// The workaround is to consider any regular files as always
// ready to read/write or to use AIO functions for regular
// file i/o. The latter is quite intrusive so for now we
// use the former method. This is done by making any
// failed call to epoll_ctl due to EPERM resulting in a
// fallback to assuming that read/write is ready.
#endif

fd_set activeFDs; // active file descriptors

static struct termios normalSettings;

Expand All @@ -80,7 +92,30 @@ class IOCleanup {
# else
# error what?
# endif
#ifdef USE_EPOLL
epollFD = epoll_create(256);
if (epollFD < 0) {
}
else {
// TODO:
// These file descriptors work with epoll unless they're
// redirected to/from a standard file. We should check
// if that's the case and fallback to select for those.
struct epoll_event event;
event.events = EPOLLIN | EPOLLOUT;
event.data.fd = 0;
if (epoll_ctl(epollFD, EPOLL_CTL_ADD, 0, &event) < 0)
printf("epoll_ctl for fd 0 failed: %s\n", strerror(errno));
event.data.fd = 1;
if (epoll_ctl(epollFD, EPOLL_CTL_ADD, 1, &event) < 0)
printf("epoll_ctl for fd 1 failed: %s\n", strerror(errno));
event.data.fd = 2;
if (epoll_ctl(epollFD, EPOLL_CTL_ADD, 2, &event) < 0)
printf("epoll_ctl for fd 2 failed: %s\n", strerror(errno));
}
#else
FD_SET(0, &activeFDs); FD_SET(1, &activeFDs); FD_SET(2, &activeFDs);
#endif
}
~IOCleanup() { resetTerminal(); }
};
Expand Down Expand Up @@ -390,7 +425,19 @@ void register_file_descriptor(int fd) {
// (/dev/rsr0 does under SVR4) -- dmu

if (fd < 0) return;

#ifdef USE_EPOLL
struct epoll_event event;
event.data.fd = fd;
event.events = EPOLLIN | EPOLLOUT;
int res = epoll_ctl(epollFD, EPOLL_CTL_ADD, fd, &event);
if (res < 0 && errno == EPERM) {
FD_SET(fd, &activeFDs);
}
else if (res < 0) {
// What to do for error?
printf("epoll_ctl failed on fd %d: %s\n", fd, strerror(errno));
}
#else
timeval nowait;
nowait.tv_sec = 0;
nowait.tv_usec = 0;
Expand All @@ -406,6 +453,7 @@ void register_file_descriptor(int fd) {
// end of check

FD_SET(fd, &activeFDs);
#endif

}

Expand All @@ -419,9 +467,24 @@ int open_wrap(char *path, int flags, int mode) {


int close_wrap(int fd) {
#ifdef USE_EPOLL
// Check if it's a regular file descriptor and don't perform the epoll
// call if it is.
if (FD_ISSET(fd, &activeFDs)) {
FD_CLR(fd, &activeFDs);
}
else {
struct epoll_event event;
if (epoll_ctl(epollFD, EPOLL_CTL_DEL, fd, &event) < 0) {
printf("epoll_ctl delete failed on fd %d: %s\n", fd, strerror(errno));
}
}
int result = close(fd);
#else
int result = close(fd);
if (result != -1)
FD_CLR(fd, &activeFDs);
#endif
return result;
}

Expand All @@ -431,8 +494,34 @@ int select_wrap(objVectorOop vec, int howMany, void *FH) {
prim_failure(FH, BADSIZEERROR);
return 0;
}
#ifdef USE_EPOLL
struct epoll_event* events = (struct epoll_event*)malloc(sizeof(epoll_event) * howMany);
int ret = epoll_wait(epollFD, events, howMany, 0);
if (ret < 0) {
unix_failure(FH);
return 0;
}

for(int i = 0; i < ret; ++i) {
struct epoll_event* event = &events[i];
vec->obj_at_put(i, as_smiOop(event->data.fd), false);
}

free(events);

// Add any regular files
howMany -= ret;
int index= ret;
for (int fd = 0; fd < FD_SETSIZE && index < howMany; fd++) {
if (FD_ISSET(fd, &activeFDs)) {
vec->obj_at_put(index++, as_smiOop(fd), false);
}
}
return index;
#else
if (howMany > FD_SETSIZE)
howMany = FD_SETSIZE;

fd_set r = activeFDs, w = activeFDs;
timeval nowait;
nowait.tv_sec = 0;
Expand All @@ -448,13 +537,41 @@ int select_wrap(objVectorOop vec, int howMany, void *FH) {
vec->obj_at_put(index++, as_smiOop(fd), false);
}
return index;
#endif
}

int select_read_wrap(objVectorOop vec, int howMany, void *FH) {
if (howMany > vec->length_obj_array()) {
prim_failure(FH, BADSIZEERROR);
return 0;
}
#ifdef USE_EPOLL
struct epoll_event* events = (struct epoll_event*)malloc(sizeof(epoll_event) * howMany);
int ret = epoll_wait(epollFD, events, howMany, 0);
if (ret < 0) {
unix_failure(FH);
return 0;
}

int index = 0;
for(int i = 0; i < ret; ++i) {
struct epoll_event* event = &events[i];
if ((event->events & EPOLLIN) == EPOLLIN) {
vec->obj_at_put(index++, as_smiOop(event->data.fd), false);
}
}

free(events);

// Add any regular files
howMany -= index;
for (int fd = 0; fd < FD_SETSIZE && index < howMany; fd++) {
if (FD_ISSET(fd, &activeFDs)) {
vec->obj_at_put(index++, as_smiOop(fd), false);
}
}
return index;
#else
if (howMany > FD_SETSIZE)
howMany = FD_SETSIZE;
fd_set r = activeFDs;
Expand All @@ -472,6 +589,7 @@ int select_read_wrap(objVectorOop vec, int howMany, void *FH) {
vec->obj_at_put(index++, as_smiOop(fd), false);
}
return index;
#endif
}


Expand Down
11 changes: 11 additions & 0 deletions vm/src/unix/prims/unixPrims.hh
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,20 @@
# pragma interface
# endif

#if TARGET_OS_VERSION == LINUX_VERSION
#define USE_EPOLL
#endif

#ifdef USE_EPOLL
#include <sys/epoll.h>
#endif

extern const char *UnixFile_seal;

#ifdef USE_EPOLL
extern int epollFD; // epoll file descriptor
#endif

extern fd_set activeFDs; // active file descriptors

// so glued in routines can call me
Expand Down
13 changes: 12 additions & 1 deletion vm/src/unix/prims/xlibPrims.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,25 @@
XSetIOErrorHandler(XErrorHandlers::handle_X_IO_error);

// add this file descriptor to list of all open files
#ifdef USE_EPOLL
register_file_descriptor(ConnectionNumber(result));
#else
FD_SET(ConnectionNumber(result), &activeFDs);
#endif
return result;
}

void XCloseDisplay_wrap(Display* display) {
int fd = ConnectionNumber(display);
XCloseDisplay(display);
#ifdef USE_EPOLL
struct epoll_event event;
if (epoll_ctl(epollFD, EPOLL_CTL_DEL, fd, &event) < 0) {
printf("epoll_ctl delete for X11 descriptor failed: %s\n", strerror(errno));
}
#else
FD_CLR(fd, &activeFDs);
#endif
XCloseDisplay(display);
}

# define WHAT_GLUE FUNCTIONS
Expand Down