mirror of
https://github.com/janet-lang/janet
synced 2024-11-19 07:04:48 +00:00
Fix linux issues with epoll on normal files.
We use the selfpipe trick if epoll fails with EPERM when trying to register a file descriptor.
This commit is contained in:
parent
030dd747e9
commit
eb84200f28
@ -1082,6 +1082,23 @@ static int make_epoll_events(int mask) {
|
||||
return events;
|
||||
}
|
||||
|
||||
static void janet_epoll_sync_callback(JanetEVGenericMessage msg) {
|
||||
JanetListenerState *state = msg.argp;
|
||||
JanetAsyncStatus status1 = JANET_ASYNC_STATUS_NOT_DONE;
|
||||
JanetAsyncStatus status2 = JANET_ASYNC_STATUS_NOT_DONE;
|
||||
if (state->stream->_mask & JANET_ASYNC_LISTEN_WRITE)
|
||||
status1 = state->machine(state, JANET_ASYNC_EVENT_WRITE);
|
||||
if (state->stream->_mask & JANET_ASYNC_LISTEN_WRITE)
|
||||
status2 = state->machine(state, JANET_ASYNC_EVENT_READ);
|
||||
if (status1 == JANET_ASYNC_STATUS_DONE ||
|
||||
status2 == JANET_ASYNC_STATUS_DONE) {
|
||||
janet_unlisten(state, 0);
|
||||
} else {
|
||||
/* Repost event */
|
||||
janet_ev_post_event(NULL, janet_epoll_sync_callback, msg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait for the next event */
|
||||
JanetListenerState *janet_listen(JanetStream *stream, JanetListener behavior, int mask, size_t size, void *user) {
|
||||
int is_first = !(stream->state);
|
||||
@ -1095,9 +1112,23 @@ JanetListenerState *janet_listen(JanetStream *stream, JanetListener behavior, in
|
||||
status = epoll_ctl(janet_vm.epoll, op, stream->handle, &ev);
|
||||
} while (status == -1 && errno == EINTR);
|
||||
if (status == -1) {
|
||||
if (errno == EPERM) {
|
||||
/* Couldn't add to event loop, so assume that it completes
|
||||
* synchronously. In that case, fire the completion
|
||||
* event manually, since this should be a read or write
|
||||
* event to a file. So we just post a custom event to do the read/write
|
||||
* asap. */
|
||||
/* Use flag to indicate state is not registered in epoll */
|
||||
state->_mask |= (1 << JANET_ASYNC_EVENT_COMPLETE);
|
||||
JanetEVGenericMessage msg = {0};
|
||||
msg.argp = state;
|
||||
janet_ev_post_event(NULL, janet_epoll_sync_callback, msg);
|
||||
} else {
|
||||
/* Unexpected error */
|
||||
janet_unlisten_impl(state, 0);
|
||||
janet_panicv(janet_ev_lasterr());
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
@ -1105,6 +1136,8 @@ JanetListenerState *janet_listen(JanetStream *stream, JanetListener behavior, in
|
||||
static void janet_unlisten(JanetListenerState *state, int is_gc) {
|
||||
JanetStream *stream = state->stream;
|
||||
if (!(stream->flags & JANET_STREAM_CLOSED)) {
|
||||
/* Use flag to indicate state is not registered in epoll */
|
||||
if (!(state->_mask & (1 << JANET_ASYNC_EVENT_COMPLETE))) {
|
||||
int is_last = (state->_next == NULL && stream->state == state);
|
||||
int op = is_last ? EPOLL_CTL_DEL : EPOLL_CTL_MOD;
|
||||
struct epoll_event ev;
|
||||
@ -1118,6 +1151,7 @@ static void janet_unlisten(JanetListenerState *state, int is_gc) {
|
||||
janet_panicv(janet_ev_lasterr());
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Destroy state machine and free memory */
|
||||
janet_unlisten_impl(state, is_gc);
|
||||
}
|
||||
@ -1358,7 +1392,7 @@ void janet_ev_post_event(JanetVM *vm, JanetCallback cb, JanetEVGenericMessage ms
|
||||
JanetSelfPipeEvent event;
|
||||
event.msg = msg;
|
||||
event.cb = cb;
|
||||
int fd = vm->selfpipe;
|
||||
int fd = vm->selfpipe[1];
|
||||
/* handle a bit of back pressure before giving up. */
|
||||
int tries = 4;
|
||||
while (tries > 0) {
|
||||
|
@ -553,7 +553,8 @@ void janet_core_cfuns(JanetTable *env, const char *regprefix, const JanetReg *cf
|
||||
}
|
||||
|
||||
void janet_core_def_sm(JanetTable *env, const char *name, Janet x, const void *p, const void *sf, int32_t sl) {
|
||||
(void) sf, sl;
|
||||
(void) sf;
|
||||
(void) sl;
|
||||
janet_core_def(env, name, x, p);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user