|  |  |  | @@ -254,84 +254,89 @@ static void add_timeout(JanetTimeout to) { | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static void janet_cleanup_canceled_states(JanetStream *stream) { | 
		
	
		
			
				|  |  |  |  |     JanetListenerState *other_state = stream->state; | 
		
	
		
			
				|  |  |  |  |     while (other_state) { | 
		
	
		
			
				|  |  |  |  |         JanetListenerState *next_state = other_state->_next; | 
		
	
		
			
				|  |  |  |  |         if (other_state->fiber->sched_id != other_state->_sched_id) { | 
		
	
		
			
				|  |  |  |  |             janet_unlisten(other_state); | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |         other_state = next_state; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | static int janet_listener_gc(void *p, size_t s); | 
		
	
		
			
				|  |  |  |  | static int janet_listener_mark(void *p, size_t s); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static const JanetAbstractType janet_listener_AT = { | 
		
	
		
			
				|  |  |  |  |     "core/ev-listener", | 
		
	
		
			
				|  |  |  |  |     janet_listener_gc, | 
		
	
		
			
				|  |  |  |  |     janet_listener_mark | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /* Create a new event listener */ | 
		
	
		
			
				|  |  |  |  | static JanetListenerState *janet_listen_impl(JanetStream *stream, JanetListener behavior, int mask, size_t size, void *user) { | 
		
	
		
			
				|  |  |  |  |     if (stream->flags & JANET_STREAM_CLOSED) { | 
		
	
		
			
				|  |  |  |  |         janet_panic("cannot listen on closed stream"); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     if (stream->_mask & mask) { | 
		
	
		
			
				|  |  |  |  |         janet_cleanup_canceled_states(stream); | 
		
	
		
			
				|  |  |  |  |         if (stream->_mask & mask) { | 
		
	
		
			
				|  |  |  |  |             janet_panic("cannot listen for duplicate event on stream"); | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     if (size < sizeof(JanetListenerState)) | 
		
	
		
			
				|  |  |  |  |         size = sizeof(JanetListenerState); | 
		
	
		
			
				|  |  |  |  |     JanetListenerState *state = janet_malloc(size); | 
		
	
		
			
				|  |  |  |  |     if (NULL == state) { | 
		
	
		
			
				|  |  |  |  |         JANET_OUT_OF_MEMORY; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     if ((mask & JANET_ASYNC_LISTEN_READ) && stream->read_state) goto bad_listen_read; | 
		
	
		
			
				|  |  |  |  |     if ((mask & JANET_ASYNC_LISTEN_WRITE) && stream->write_state) goto bad_listen_write; | 
		
	
		
			
				|  |  |  |  |     janet_assert(size >= sizeof(JanetListenerState), "bad size"); | 
		
	
		
			
				|  |  |  |  |     JanetListenerState *state = janet_abstract(&janet_listener_AT, size); | 
		
	
		
			
				|  |  |  |  |     state->machine = behavior; | 
		
	
		
			
				|  |  |  |  |     state->fiber = janet_vm.root_fiber; | 
		
	
		
			
				|  |  |  |  |     state->_sched_id = janet_vm.root_fiber->sched_id; | 
		
	
		
			
				|  |  |  |  |     janet_vm.root_fiber->waiting = state; | 
		
	
		
			
				|  |  |  |  |     if (mask & JANET_ASYNC_LISTEN_READ) stream->read_state = state; | 
		
	
		
			
				|  |  |  |  |     if (mask & JANET_ASYNC_LISTEN_WRITE) stream->write_state = state; | 
		
	
		
			
				|  |  |  |  |     state->stream = stream; | 
		
	
		
			
				|  |  |  |  |     state->_mask = mask; | 
		
	
		
			
				|  |  |  |  |     stream->_mask |= mask; | 
		
	
		
			
				|  |  |  |  |     state->_next = stream->state; | 
		
	
		
			
				|  |  |  |  |     stream->state = state; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /* Keep track of a listener for GC purposes */ | 
		
	
		
			
				|  |  |  |  |     int resize = janet_vm.listener_cap == janet_vm.listener_count; | 
		
	
		
			
				|  |  |  |  |     if (resize) { | 
		
	
		
			
				|  |  |  |  |         size_t newcap = janet_vm.listener_count ? janet_vm.listener_cap * 2 : 16; | 
		
	
		
			
				|  |  |  |  |         janet_vm.listeners = janet_realloc(janet_vm.listeners, newcap * sizeof(JanetListenerState *)); | 
		
	
		
			
				|  |  |  |  |         if (NULL == janet_vm.listeners) { | 
		
	
		
			
				|  |  |  |  |             JANET_OUT_OF_MEMORY; | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |         janet_vm.listener_cap = newcap; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     size_t index = janet_vm.listener_count++; | 
		
	
		
			
				|  |  |  |  |     janet_vm.listeners[index] = state; | 
		
	
		
			
				|  |  |  |  |     state->_index = index; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /* Emit INIT event for convenience */ | 
		
	
		
			
				|  |  |  |  |     state->event = user; | 
		
	
		
			
				|  |  |  |  |     state->machine(state, JANET_ASYNC_EVENT_INIT); | 
		
	
		
			
				|  |  |  |  |     janet_ev_inc_refcount(); | 
		
	
		
			
				|  |  |  |  |     janet_gcroot(janet_wrap_abstract(state)); | 
		
	
		
			
				|  |  |  |  |     return state; | 
		
	
		
			
				|  |  |  |  | bad_listen_write: | 
		
	
		
			
				|  |  |  |  |     janet_panic("cannot listen for duplicate write event on stream"); | 
		
	
		
			
				|  |  |  |  | bad_listen_read: | 
		
	
		
			
				|  |  |  |  |     janet_panic("cannot listen for duplicate read event on stream"); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | void janet_fiber_did_resume(JanetFiber *fiber) { | 
		
	
		
			
				|  |  |  |  |     if (fiber->waiting) { | 
		
	
		
			
				|  |  |  |  |         janet_unlisten(fiber->waiting); | 
		
	
		
			
				|  |  |  |  |         fiber->waiting = NULL; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /* Indicate we are no longer listening for an event. This | 
		
	
		
			
				|  |  |  |  |  * frees the memory of the state machine as well. */ | 
		
	
		
			
				|  |  |  |  | static void janet_unlisten_impl(JanetListenerState *state) { | 
		
	
		
			
				|  |  |  |  |     state->machine(state, JANET_ASYNC_EVENT_DEINIT); | 
		
	
		
			
				|  |  |  |  |     /* Remove state machine from poll list */ | 
		
	
		
			
				|  |  |  |  |     JanetListenerState **iter = &(state->stream->state); | 
		
	
		
			
				|  |  |  |  |     while (*iter && *iter != state) | 
		
	
		
			
				|  |  |  |  |         iter = &((*iter)->_next); | 
		
	
		
			
				|  |  |  |  |     janet_assert(*iter, "failed to remove listener"); | 
		
	
		
			
				|  |  |  |  |     *iter = state->_next; | 
		
	
		
			
				|  |  |  |  |     /* Remove mask */ | 
		
	
		
			
				|  |  |  |  |     state->stream->_mask &= ~(state->_mask); | 
		
	
		
			
				|  |  |  |  |     /* Untrack a listener for gc purposes */ | 
		
	
		
			
				|  |  |  |  |     size_t index = state->_index; | 
		
	
		
			
				|  |  |  |  |     janet_vm.listeners[index] = janet_vm.listeners[--janet_vm.listener_count]; | 
		
	
		
			
				|  |  |  |  |     janet_vm.listeners[index]->_index = index; | 
		
	
		
			
				|  |  |  |  |     //janet_free(state); | 
		
	
		
			
				|  |  |  |  |     janet_gcunroot(janet_wrap_abstract(state)); | 
		
	
		
			
				|  |  |  |  |     if (state->stream) { | 
		
	
		
			
				|  |  |  |  |         janet_ev_dec_refcount(); | 
		
	
		
			
				|  |  |  |  |         if (state->stream->read_state == state) { | 
		
	
		
			
				|  |  |  |  |             state->stream->read_state = NULL; | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |         if (state->stream->write_state == state) { | 
		
	
		
			
				|  |  |  |  |             state->stream->write_state = NULL; | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |         state->stream = NULL; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static int janet_listener_gc(void *p, size_t size) { | 
		
	
		
			
				|  |  |  |  |     (void) size; | 
		
	
		
			
				|  |  |  |  |     JanetListenerState *state = (JanetListenerState *)p; | 
		
	
		
			
				|  |  |  |  |     if (state->stream) { | 
		
	
		
			
				|  |  |  |  |         janet_ev_dec_refcount(); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     if (state->machine) { | 
		
	
		
			
				|  |  |  |  |         state->machine(state, JANET_ASYNC_EVENT_DEINIT); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     return 0; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static int janet_listener_mark(void *p, size_t size) { | 
		
	
		
			
				|  |  |  |  |     (void) size; | 
		
	
		
			
				|  |  |  |  |     JanetListenerState *state = (JanetListenerState *)p; | 
		
	
		
			
				|  |  |  |  |     if (state->stream) { | 
		
	
		
			
				|  |  |  |  |         janet_mark(janet_wrap_abstract(state->stream)); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     if (state->fiber) { | 
		
	
		
			
				|  |  |  |  |         janet_mark(janet_wrap_fiber(state->fiber)); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     state->machine(state, JANET_ASYNC_EVENT_MARK); | 
		
	
		
			
				|  |  |  |  |     return 0; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static void janet_stream_checktoclose(JanetStream *stream) { | 
		
	
		
			
				|  |  |  |  |     if ((stream->flags & JANET_STREAM_TOCLOSE) && !stream->state) { | 
		
	
		
			
				|  |  |  |  |     if ((stream->flags & JANET_STREAM_TOCLOSE) && !stream->read_state && !stream->write_state) { | 
		
	
		
			
				|  |  |  |  |         janet_stream_close(stream); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
	
		
			
				
					
					|  |  |  | @@ -349,22 +354,15 @@ JanetStream *janet_stream(JanetHandle handle, uint32_t flags, const JanetMethod | 
		
	
		
			
				|  |  |  |  |     JanetStream *stream = janet_abstract(&janet_stream_type, sizeof(JanetStream)); | 
		
	
		
			
				|  |  |  |  |     stream->handle = handle; | 
		
	
		
			
				|  |  |  |  |     stream->flags = flags; | 
		
	
		
			
				|  |  |  |  |     stream->state = NULL; | 
		
	
		
			
				|  |  |  |  |     stream->_mask = 0; | 
		
	
		
			
				|  |  |  |  |     stream->read_state = NULL; | 
		
	
		
			
				|  |  |  |  |     stream->write_state = NULL; | 
		
	
		
			
				|  |  |  |  |     if (methods == NULL) methods = ev_default_stream_methods; | 
		
	
		
			
				|  |  |  |  |     stream->methods = methods; | 
		
	
		
			
				|  |  |  |  |     return stream; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | void janet_stream_close(JanetStream *stream) { | 
		
	
		
			
				|  |  |  |  | static void janet_stream_close_impl(JanetStream *stream) { | 
		
	
		
			
				|  |  |  |  |     stream->flags |= JANET_STREAM_CLOSED; | 
		
	
		
			
				|  |  |  |  |     JanetListenerState *state = stream->state; | 
		
	
		
			
				|  |  |  |  |     while (state) { | 
		
	
		
			
				|  |  |  |  |         state->machine(state, JANET_ASYNC_EVENT_CLOSE); | 
		
	
		
			
				|  |  |  |  |         JanetListenerState *next_state = state->_next; | 
		
	
		
			
				|  |  |  |  |         janet_unlisten(state); | 
		
	
		
			
				|  |  |  |  |         state = next_state; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | #ifdef JANET_WINDOWS | 
		
	
		
			
				|  |  |  |  |     if (stream->handle != INVALID_HANDLE_VALUE) { | 
		
	
		
			
				|  |  |  |  | #ifdef JANET_NET | 
		
	
	
		
			
				
					
					|  |  |  | @@ -385,11 +383,23 @@ void janet_stream_close(JanetStream *stream) { | 
		
	
		
			
				|  |  |  |  | #endif | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | void janet_stream_close(JanetStream *stream) { | 
		
	
		
			
				|  |  |  |  |     if (stream->read_state) { | 
		
	
		
			
				|  |  |  |  |         stream->read_state->machine(stream->read_state, JANET_ASYNC_EVENT_CLOSE); | 
		
	
		
			
				|  |  |  |  |         janet_unlisten(stream->read_state); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     if (stream->write_state) { | 
		
	
		
			
				|  |  |  |  |         stream->write_state->machine(stream->write_state, JANET_ASYNC_EVENT_CLOSE); | 
		
	
		
			
				|  |  |  |  |         janet_unlisten(stream->write_state); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     janet_stream_close_impl(stream); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /* Called to clean up a stream */ | 
		
	
		
			
				|  |  |  |  | static int janet_stream_gc(void *p, size_t s) { | 
		
	
		
			
				|  |  |  |  |     (void) s; | 
		
	
		
			
				|  |  |  |  |     JanetStream *stream = (JanetStream *)p; | 
		
	
		
			
				|  |  |  |  |     janet_stream_close(stream); | 
		
	
		
			
				|  |  |  |  |     janet_stream_close_impl(stream); | 
		
	
		
			
				|  |  |  |  |     return 0; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @@ -397,13 +407,11 @@ static int janet_stream_gc(void *p, size_t s) { | 
		
	
		
			
				|  |  |  |  | static int janet_stream_mark(void *p, size_t s) { | 
		
	
		
			
				|  |  |  |  |     (void) s; | 
		
	
		
			
				|  |  |  |  |     JanetStream *stream = (JanetStream *) p; | 
		
	
		
			
				|  |  |  |  |     JanetListenerState *state = stream->state; | 
		
	
		
			
				|  |  |  |  |     while (NULL != state) { | 
		
	
		
			
				|  |  |  |  |         if (NULL != state->fiber) { | 
		
	
		
			
				|  |  |  |  |             janet_mark(janet_wrap_fiber(state->fiber)); | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |         (state->machine)(state, JANET_ASYNC_EVENT_MARK); | 
		
	
		
			
				|  |  |  |  |         state = state->_next; | 
		
	
		
			
				|  |  |  |  |     if (NULL != stream->read_state) { | 
		
	
		
			
				|  |  |  |  |         janet_mark(janet_wrap_abstract(stream->read_state)); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     if (NULL != stream->write_state) { | 
		
	
		
			
				|  |  |  |  |         janet_mark(janet_wrap_abstract(stream->write_state)); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     return 0; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
	
		
			
				
					
					|  |  |  | @@ -456,8 +464,8 @@ static void *janet_stream_unmarshal(JanetMarshalContext *ctx) { | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     JanetStream *p = janet_unmarshal_abstract(ctx, sizeof(JanetStream)); | 
		
	
		
			
				|  |  |  |  |     /* Can't share listening state and such across threads */ | 
		
	
		
			
				|  |  |  |  |     p->_mask = 0; | 
		
	
		
			
				|  |  |  |  |     p->state = NULL; | 
		
	
		
			
				|  |  |  |  |     p->read_state = NULL; | 
		
	
		
			
				|  |  |  |  |     p->write_state = NULL; | 
		
	
		
			
				|  |  |  |  |     p->flags = (uint32_t) janet_unmarshal_int(ctx); | 
		
	
		
			
				|  |  |  |  |     p->methods =  janet_unmarshal_ptr(ctx); | 
		
	
		
			
				|  |  |  |  | #ifdef JANET_WINDOWS | 
		
	
	
		
			
				
					
					|  |  |  | @@ -549,16 +557,6 @@ void janet_ev_mark(void) { | 
		
	
		
			
				|  |  |  |  |             janet_mark(janet_wrap_fiber(janet_vm.tq[i].curr_fiber)); | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /* Pending listeners */ | 
		
	
		
			
				|  |  |  |  |     for (size_t i = 0; i < janet_vm.listener_count; i++) { | 
		
	
		
			
				|  |  |  |  |         JanetListenerState *state = janet_vm.listeners[i]; | 
		
	
		
			
				|  |  |  |  |         if (NULL != state->fiber) { | 
		
	
		
			
				|  |  |  |  |             janet_mark(janet_wrap_fiber(state->fiber)); | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |         janet_stream_mark(state->stream, sizeof(JanetStream)); | 
		
	
		
			
				|  |  |  |  |         (state->machine)(state, JANET_ASYNC_EVENT_MARK); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static int janet_channel_push(JanetChannel *channel, Janet x, int mode); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -579,9 +577,6 @@ static Janet make_supervisor_event(const char *name, JanetFiber *fiber, int thre | 
		
	
		
			
				|  |  |  |  | /* Common init code */ | 
		
	
		
			
				|  |  |  |  | void janet_ev_init_common(void) { | 
		
	
		
			
				|  |  |  |  |     janet_q_init(&janet_vm.spawn); | 
		
	
		
			
				|  |  |  |  |     janet_vm.listener_count = 0; | 
		
	
		
			
				|  |  |  |  |     janet_vm.listener_cap = 0; | 
		
	
		
			
				|  |  |  |  |     janet_vm.listeners = NULL; | 
		
	
		
			
				|  |  |  |  |     janet_vm.tq = NULL; | 
		
	
		
			
				|  |  |  |  |     janet_vm.tq_count = 0; | 
		
	
		
			
				|  |  |  |  |     janet_vm.tq_capacity = 0; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -599,8 +594,6 @@ void janet_ev_init_common(void) { | 
		
	
		
			
				|  |  |  |  | void janet_ev_deinit_common(void) { | 
		
	
		
			
				|  |  |  |  |     janet_q_deinit(&janet_vm.spawn); | 
		
	
		
			
				|  |  |  |  |     janet_free(janet_vm.tq); | 
		
	
		
			
				|  |  |  |  |     janet_free(janet_vm.listeners); | 
		
	
		
			
				|  |  |  |  |     janet_vm.listeners = NULL; | 
		
	
		
			
				|  |  |  |  |     janet_table_deinit(&janet_vm.threaded_abstracts); | 
		
	
		
			
				|  |  |  |  |     janet_table_deinit(&janet_vm.active_tasks); | 
		
	
		
			
				|  |  |  |  |     janet_table_deinit(&janet_vm.signal_handlers); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -1327,8 +1320,7 @@ const JanetAbstractType janet_channel_type = { | 
		
	
		
			
				|  |  |  |  | void janet_loop1_impl(int has_timeout, JanetTimestamp timeout); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | int janet_loop_done(void) { | 
		
	
		
			
				|  |  |  |  |     return !(janet_vm.listener_count || | 
		
	
		
			
				|  |  |  |  |              (janet_vm.spawn.head != janet_vm.spawn.tail) || | 
		
	
		
			
				|  |  |  |  |     return !((janet_vm.spawn.head != janet_vm.spawn.tail) || | 
		
	
		
			
				|  |  |  |  |              janet_vm.tq_count || | 
		
	
		
			
				|  |  |  |  |              janet_vm.extra_listeners); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
	
		
			
				
					
					|  |  |  | @@ -1392,7 +1384,7 @@ JanetFiber *janet_loop1(void) { | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /* Poll for events */ | 
		
	
		
			
				|  |  |  |  |     if (janet_vm.listener_count || janet_vm.tq_count || janet_vm.extra_listeners) { | 
		
	
		
			
				|  |  |  |  |     if (janet_vm.tq_count || janet_vm.extra_listeners) { | 
		
	
		
			
				|  |  |  |  |         JanetTimeout to; | 
		
	
		
			
				|  |  |  |  |         memset(&to, 0, sizeof(to)); | 
		
	
		
			
				|  |  |  |  |         int has_timeout; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -1411,7 +1403,7 @@ JanetFiber *janet_loop1(void) { | 
		
	
		
			
				|  |  |  |  |             break; | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |         /* Run polling implementation only if pending timeouts or pending events */ | 
		
	
		
			
				|  |  |  |  |         if (janet_vm.tq_count || janet_vm.listener_count || janet_vm.extra_listeners) { | 
		
	
		
			
				|  |  |  |  |         if (janet_vm.tq_count || janet_vm.extra_listeners) { | 
		
	
		
			
				|  |  |  |  |             janet_loop1_impl(has_timeout, to.when); | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
	
		
			
				
					
					|  |  |  | @@ -1541,19 +1533,19 @@ void janet_loop1_impl(int has_timeout, JanetTimestamp to) { | 
		
	
		
			
				|  |  |  |  |         } else { | 
		
	
		
			
				|  |  |  |  |             /* Normal event */ | 
		
	
		
			
				|  |  |  |  |             JanetStream *stream = (JanetStream *) completionKey; | 
		
	
		
			
				|  |  |  |  |             janet_assert(!(stream->flags & JANET_STREAM_CLOSED), "got closed stream event"); | 
		
	
		
			
				|  |  |  |  |             JanetListenerState *state = stream->state; | 
		
	
		
			
				|  |  |  |  |             while (state != NULL) { | 
		
	
		
			
				|  |  |  |  |                 if (state->tag == overlapped) { | 
		
	
		
			
				|  |  |  |  |                     state->event = overlapped; | 
		
	
		
			
				|  |  |  |  |                     state->bytes = num_bytes_transfered; | 
		
	
		
			
				|  |  |  |  |                     JanetAsyncStatus status = state->machine(state, JANET_ASYNC_EVENT_COMPLETE); | 
		
	
		
			
				|  |  |  |  |                     if (status == JANET_ASYNC_STATUS_DONE) { | 
		
	
		
			
				|  |  |  |  |                         janet_unlisten(state); | 
		
	
		
			
				|  |  |  |  |                     } | 
		
	
		
			
				|  |  |  |  |                     break; | 
		
	
		
			
				|  |  |  |  |                 } else { | 
		
	
		
			
				|  |  |  |  |                     state = state->_next; | 
		
	
		
			
				|  |  |  |  |             janet_assert(stream->handle != INVALID_HANDLE_VALUE, "got closed stream event"); | 
		
	
		
			
				|  |  |  |  |             JanetListenerState *state = NULL; | 
		
	
		
			
				|  |  |  |  |             if (stream->read_state && stream->read_state->tag == overlapped) { | 
		
	
		
			
				|  |  |  |  |                 state = stream->read_state; | 
		
	
		
			
				|  |  |  |  |             } else if (stream->write_state && stream->write_state->tag == overlapped) { | 
		
	
		
			
				|  |  |  |  |                 state = stream->write_state; | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |             if (state != NULL) { | 
		
	
		
			
				|  |  |  |  |                 state->event = overlapped; | 
		
	
		
			
				|  |  |  |  |                 state->bytes = num_bytes_transfered; | 
		
	
		
			
				|  |  |  |  |                 JanetAsyncStatus status = state->machine(state, JANET_ASYNC_EVENT_COMPLETE); | 
		
	
		
			
				|  |  |  |  |                 if (status == JANET_ASYNC_STATUS_DONE) { | 
		
	
		
			
				|  |  |  |  |                     janet_unlisten(state); | 
		
	
		
			
				|  |  |  |  |                 } | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |             janet_stream_checktoclose(stream); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -1633,7 +1625,7 @@ JanetListenerState *janet_listen(JanetStream *stream, JanetListener behavior, in | 
		
	
		
			
				|  |  |  |  | /* Tell system we are done listening for a certain event */ | 
		
	
		
			
				|  |  |  |  | static void janet_unlisten(JanetListenerState *state) { | 
		
	
		
			
				|  |  |  |  |     JanetStream *stream = state->stream; | 
		
	
		
			
				|  |  |  |  |     if (!(stream->flags & JANET_STREAM_CLOSED)) { | 
		
	
		
			
				|  |  |  |  |     if (!(stream->handle != -1)) { | 
		
	
		
			
				|  |  |  |  |         /* 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); | 
		
	
	
		
			
				
					
					|  |  |  |   |