mirror of
https://github.com/janet-lang/janet
synced 2025-05-06 17:34:16 +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;
|
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 */
|
/* Wait for the next event */
|
||||||
JanetListenerState *janet_listen(JanetStream *stream, JanetListener behavior, int mask, size_t size, void *user) {
|
JanetListenerState *janet_listen(JanetStream *stream, JanetListener behavior, int mask, size_t size, void *user) {
|
||||||
int is_first = !(stream->state);
|
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);
|
status = epoll_ctl(janet_vm.epoll, op, stream->handle, &ev);
|
||||||
} while (status == -1 && errno == EINTR);
|
} while (status == -1 && errno == EINTR);
|
||||||
if (status == -1) {
|
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_unlisten_impl(state, 0);
|
||||||
janet_panicv(janet_ev_lasterr());
|
janet_panicv(janet_ev_lasterr());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1105,6 +1136,8 @@ JanetListenerState *janet_listen(JanetStream *stream, JanetListener behavior, in
|
|||||||
static void janet_unlisten(JanetListenerState *state, int is_gc) {
|
static void janet_unlisten(JanetListenerState *state, int is_gc) {
|
||||||
JanetStream *stream = state->stream;
|
JanetStream *stream = state->stream;
|
||||||
if (!(stream->flags & JANET_STREAM_CLOSED)) {
|
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 is_last = (state->_next == NULL && stream->state == state);
|
||||||
int op = is_last ? EPOLL_CTL_DEL : EPOLL_CTL_MOD;
|
int op = is_last ? EPOLL_CTL_DEL : EPOLL_CTL_MOD;
|
||||||
struct epoll_event ev;
|
struct epoll_event ev;
|
||||||
@ -1118,6 +1151,7 @@ static void janet_unlisten(JanetListenerState *state, int is_gc) {
|
|||||||
janet_panicv(janet_ev_lasterr());
|
janet_panicv(janet_ev_lasterr());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/* Destroy state machine and free memory */
|
/* Destroy state machine and free memory */
|
||||||
janet_unlisten_impl(state, is_gc);
|
janet_unlisten_impl(state, is_gc);
|
||||||
}
|
}
|
||||||
@ -1358,7 +1392,7 @@ void janet_ev_post_event(JanetVM *vm, JanetCallback cb, JanetEVGenericMessage ms
|
|||||||
JanetSelfPipeEvent event;
|
JanetSelfPipeEvent event;
|
||||||
event.msg = msg;
|
event.msg = msg;
|
||||||
event.cb = cb;
|
event.cb = cb;
|
||||||
int fd = vm->selfpipe;
|
int fd = vm->selfpipe[1];
|
||||||
/* handle a bit of back pressure before giving up. */
|
/* handle a bit of back pressure before giving up. */
|
||||||
int tries = 4;
|
int tries = 4;
|
||||||
while (tries > 0) {
|
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 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);
|
janet_core_def(env, name, x, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user