mirror of
				https://github.com/janet-lang/janet
				synced 2025-10-31 15:43:01 +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:
		| @@ -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); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Calvin Rose
					Calvin Rose