mirror of
				https://github.com/janet-lang/janet
				synced 2025-10-31 15:43:01 +00:00 
			
		
		
		
	Lots of work to make iocp work again.
Big issue with IOCP vs. poll variants is that the overlapped structures have a longer lifetime than intermediate state needed for epoll. One cannot free overlapped structures after closing a handle/socket, like one can do with any intermediate state when using readiness-based IO.
This commit is contained in:
		
							
								
								
									
										150
									
								
								src/core/ev.c
									
									
									
									
									
								
							
							
						
						
									
										150
									
								
								src/core/ev.c
									
									
									
									
									
								
							| @@ -258,15 +258,17 @@ void janet_async_end(JanetFiber *fiber) { | |||||||
|         janet_gcunroot(janet_wrap_abstract(fiber->ev_stream)); |         janet_gcunroot(janet_wrap_abstract(fiber->ev_stream)); | ||||||
|         fiber->ev_callback = NULL; |         fiber->ev_callback = NULL; | ||||||
|         if (fiber->ev_state) { |         if (fiber->ev_state) { | ||||||
|  |             if (!fiber->ev_in_flight) { | ||||||
|                 janet_free(fiber->ev_state); |                 janet_free(fiber->ev_state); | ||||||
|  |                 janet_ev_dec_refcount(); | ||||||
|  |             } | ||||||
|             fiber->ev_state = NULL; |             fiber->ev_state = NULL; | ||||||
|         } |         } | ||||||
|         janet_ev_dec_refcount(); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void *janet_async_start(JanetFiber *fiber, JanetStream *stream, JanetAsyncMode mode, JanetEVCallback callback, size_t data_size) { | void *janet_async_start(JanetFiber *fiber, JanetStream *stream, JanetAsyncMode mode, JanetEVCallback callback, size_t data_size) { | ||||||
|     janet_async_end(fiber); /* Clear existing callback */ |     janet_assert(!fiber->ev_callback, "double async on fiber"); | ||||||
|     if (mode & JANET_ASYNC_LISTEN_READ) stream->read_fiber = fiber; |     if (mode & JANET_ASYNC_LISTEN_READ) stream->read_fiber = fiber; | ||||||
|     if (mode & JANET_ASYNC_LISTEN_WRITE) stream->write_fiber = fiber; |     if (mode & JANET_ASYNC_LISTEN_WRITE) stream->write_fiber = fiber; | ||||||
|     fiber->ev_callback = callback; |     fiber->ev_callback = callback; | ||||||
| @@ -278,6 +280,7 @@ void *janet_async_start(JanetFiber *fiber, JanetStream *stream, JanetAsyncMode m | |||||||
|         fiber->ev_state = data; |         fiber->ev_state = data; | ||||||
|         return data; |         return data; | ||||||
|     } else { |     } else { | ||||||
|  |         fiber->ev_state = NULL; | ||||||
|         return NULL; |         return NULL; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -1437,20 +1440,10 @@ void janet_ev_deinit(void) { | |||||||
|     CloseHandle(janet_vm.iocp); |     CloseHandle(janet_vm.iocp); | ||||||
| } | } | ||||||
|  |  | ||||||
| JanetListenerState *janet_listen(JanetStream *stream, JanetListener behavior, int mask, size_t size, void *user) { | void janet_register_stream(JanetStream *stream) { | ||||||
|     /* Add the handle to the io completion port if not already added */ |  | ||||||
|     JanetListenerState *state = janet_listen_impl(stream, behavior, mask, size, user); |  | ||||||
|     if (!(stream->flags & JANET_STREAM_REGISTERED)) { |  | ||||||
|     if (NULL == CreateIoCompletionPort(stream->handle, janet_vm.iocp, (ULONG_PTR) stream, 0)) { |     if (NULL == CreateIoCompletionPort(stream->handle, janet_vm.iocp, (ULONG_PTR) stream, 0)) { | ||||||
|         janet_panicf("failed to listen for events: %V", janet_ev_lasterr()); |         janet_panicf("failed to listen for events: %V", janet_ev_lasterr()); | ||||||
|     } |     } | ||||||
|         stream->flags |= JANET_STREAM_REGISTERED; |  | ||||||
|     } |  | ||||||
|     return state; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void janet_unlisten(JanetListenerState *state) { |  | ||||||
|     janet_unlisten_impl(state); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void janet_loop1_impl(int has_timeout, JanetTimestamp to) { | void janet_loop1_impl(int has_timeout, JanetTimestamp to) { | ||||||
| @@ -1483,19 +1476,19 @@ void janet_loop1_impl(int has_timeout, JanetTimestamp to) { | |||||||
|         } else { |         } else { | ||||||
|             /* Normal event */ |             /* Normal event */ | ||||||
|             JanetStream *stream = (JanetStream *) completionKey; |             JanetStream *stream = (JanetStream *) completionKey; | ||||||
|             JanetListenerState *state = NULL; |             JanetFiber *fiber = NULL; | ||||||
|             if (stream->read_state && stream->read_state->tag == overlapped) { |             if (stream->read_fiber && stream->read_fiber->ev_state == overlapped) { | ||||||
|                 state = stream->read_state; |                 fiber = stream->read_fiber; | ||||||
|             } else if (stream->write_state && stream->write_state->tag == overlapped) { |             } else if (stream->write_fiber && stream->write_fiber->ev_state == overlapped) { | ||||||
|                 state = stream->write_state; |                 fiber = stream->write_fiber; | ||||||
|             } |  | ||||||
|             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); |  | ||||||
|             } |             } | ||||||
|  |             if (fiber != NULL) { | ||||||
|  |                 fiber->ev_in_flight = 0; | ||||||
|  |                 fiber->ev_bytes = num_bytes_transfered; | ||||||
|  |                 fiber->ev_callback(fiber, result ? JANET_ASYNC_EVENT_COMPLETE : JANET_ASYNC_EVENT_FAILED); | ||||||
|  |             } else { | ||||||
|  |                 janet_free((void *) overlapped); | ||||||
|  |                 janet_ev_dec_refcount(); | ||||||
|             } |             } | ||||||
|             janet_stream_checktoclose(stream); |             janet_stream_checktoclose(stream); | ||||||
|         } |         } | ||||||
| @@ -2134,11 +2127,6 @@ typedef enum { | |||||||
| } JanetReadMode; | } JanetReadMode; | ||||||
|  |  | ||||||
| typedef struct { | typedef struct { | ||||||
|     int32_t bytes_left; |  | ||||||
|     int32_t bytes_read; |  | ||||||
|     JanetBuffer *buf; |  | ||||||
|     int is_chunk; |  | ||||||
|     JanetReadMode mode; |  | ||||||
| #ifdef JANET_WINDOWS | #ifdef JANET_WINDOWS | ||||||
|     OVERLAPPED overlapped; |     OVERLAPPED overlapped; | ||||||
|     DWORD flags; |     DWORD flags; | ||||||
| @@ -2151,6 +2139,11 @@ typedef struct { | |||||||
| #else | #else | ||||||
|     int flags; |     int flags; | ||||||
| #endif | #endif | ||||||
|  |     int32_t bytes_left; | ||||||
|  |     int32_t bytes_read; | ||||||
|  |     JanetBuffer *buf; | ||||||
|  |     int is_chunk; | ||||||
|  |     JanetReadMode mode; | ||||||
| } StateRead; | } StateRead; | ||||||
|  |  | ||||||
| void ev_callback_read(JanetFiber *fiber, JanetAsyncEvent event) { | void ev_callback_read(JanetFiber *fiber, JanetAsyncEvent event) { | ||||||
| @@ -2167,18 +2160,20 @@ void ev_callback_read(JanetFiber *fiber, JanetAsyncEvent event) { | |||||||
|             janet_async_end(fiber); |             janet_async_end(fiber); | ||||||
|             break; |             break; | ||||||
| #ifdef JANET_WINDOWS | #ifdef JANET_WINDOWS | ||||||
|  |         case JANET_ASYNC_EVENT_FAILED: | ||||||
|         case JANET_ASYNC_EVENT_COMPLETE: { |         case JANET_ASYNC_EVENT_COMPLETE: { | ||||||
|             /* Called when read finished */ |             /* Called when read finished */ | ||||||
|             state->bytes_read += s->bytes; |             state->bytes_read += fiber->ev_bytes; | ||||||
|             if (state->bytes_read == 0 && (state->mode != JANET_ASYNC_READMODE_RECVFROM)) { |             if (state->bytes_read == 0 && (state->mode != JANET_ASYNC_READMODE_RECVFROM)) { | ||||||
|                 janet_schedule(s->fiber, janet_wrap_nil()); |                 janet_schedule(fiber, janet_wrap_nil()); | ||||||
|                 return JANET_ASYNC_STATUS_DONE; |                 janet_async_end(fiber); | ||||||
|  |                 return; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             janet_buffer_push_bytes(state->buf, state->chunk_buf, s->bytes); |             janet_buffer_push_bytes(state->buf, state->chunk_buf, fiber->ev_bytes); | ||||||
|             state->bytes_left -= s->bytes; |             state->bytes_left -= fiber->ev_bytes; | ||||||
|  |  | ||||||
|             if (state->bytes_left == 0 || !state->is_chunk || s->bytes == 0) { |             if (state->bytes_left == 0 || !state->is_chunk || fiber->ev_bytes == 0) { | ||||||
|                 Janet resume_val; |                 Janet resume_val; | ||||||
| #ifdef JANET_NET | #ifdef JANET_NET | ||||||
|                 if (state->mode == JANET_ASYNC_READMODE_RECVFROM) { |                 if (state->mode == JANET_ASYNC_READMODE_RECVFROM) { | ||||||
| @@ -2190,15 +2185,15 @@ void ev_callback_read(JanetFiber *fiber, JanetAsyncEvent event) { | |||||||
|                 { |                 { | ||||||
|                     resume_val = janet_wrap_buffer(state->buf); |                     resume_val = janet_wrap_buffer(state->buf); | ||||||
|                 } |                 } | ||||||
|                 janet_schedule(s->fiber, resume_val); |                 janet_schedule(fiber, resume_val); | ||||||
|                 return JANET_ASYNC_STATUS_DONE; |                 janet_async_end(fiber); | ||||||
|  |                 return; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /* fallthrough */ |         /* fallthrough */ | ||||||
|         case JANET_ASYNC_EVENT_USER: { |         case JANET_ASYNC_EVENT_USER: { | ||||||
|             int32_t chunk_size = state->bytes_left > JANET_EV_CHUNKSIZE ? JANET_EV_CHUNKSIZE : state->bytes_left; |             int32_t chunk_size = state->bytes_left > JANET_EV_CHUNKSIZE ? JANET_EV_CHUNKSIZE : state->bytes_left; | ||||||
|             s->tag = &state->overlapped; |  | ||||||
|             memset(&(state->overlapped), 0, sizeof(OVERLAPPED)); |             memset(&(state->overlapped), 0, sizeof(OVERLAPPED)); | ||||||
|             int status; |             int status; | ||||||
| #ifdef JANET_NET | #ifdef JANET_NET | ||||||
| @@ -2206,33 +2201,36 @@ void ev_callback_read(JanetFiber *fiber, JanetAsyncEvent event) { | |||||||
|                 state->wbuf.len = (ULONG) chunk_size; |                 state->wbuf.len = (ULONG) chunk_size; | ||||||
|                 state->wbuf.buf = (char *) state->chunk_buf; |                 state->wbuf.buf = (char *) state->chunk_buf; | ||||||
|                 state->fromlen = sizeof(state->from); |                 state->fromlen = sizeof(state->from); | ||||||
|                 status = WSARecvFrom((SOCKET) s->stream->handle, &state->wbuf, 1, |                 status = WSARecvFrom((SOCKET) stream->handle, &state->wbuf, 1, | ||||||
|                                      NULL, &state->flags, &state->from, &state->fromlen, &state->overlapped, NULL); |                                      NULL, &state->flags, &state->from, &state->fromlen, &state->overlapped, NULL); | ||||||
|                 if (status && (WSA_IO_PENDING != WSAGetLastError())) { |                 if (status && (WSA_IO_PENDING != WSAGetLastError())) { | ||||||
|                     janet_cancel(s->fiber, janet_ev_lasterr()); |                     janet_cancel(fiber, janet_ev_lasterr()); | ||||||
|                     return JANET_ASYNC_STATUS_DONE; |                     janet_async_end(fiber); | ||||||
|  |                     return; | ||||||
|                 } |                 } | ||||||
|             } else |             } else | ||||||
| #endif | #endif | ||||||
|             { |             { | ||||||
|                 /* Some handles (not all) read from the offset in lopOverlapped |                 /* Some handles (not all) read from the offset in lpOverlapped | ||||||
|                  * if its not set before calling `ReadFile` these streams will always read from offset 0 */ |                  * if its not set before calling `ReadFile` these streams will always read from offset 0 */ | ||||||
|                 state->overlapped.Offset = (DWORD) state->bytes_read; |                 state->overlapped.Offset = (DWORD) state->bytes_read; | ||||||
|  |  | ||||||
|                 status = ReadFile(s->stream->handle, state->chunk_buf, chunk_size, NULL, &state->overlapped); |                 status = ReadFile(stream->handle, state->chunk_buf, chunk_size, NULL, &state->overlapped); | ||||||
|                 if (!status && (ERROR_IO_PENDING != GetLastError())) { |                 if (!status && (ERROR_IO_PENDING != GetLastError())) { | ||||||
|                     if (GetLastError() == ERROR_BROKEN_PIPE) { |                     if (GetLastError() == ERROR_BROKEN_PIPE) { | ||||||
|                         if (state->bytes_read) { |                         if (state->bytes_read) { | ||||||
|                             janet_schedule(s->fiber, janet_wrap_buffer(state->buf)); |                             janet_schedule(fiber, janet_wrap_buffer(state->buf)); | ||||||
|                         } else { |                         } else { | ||||||
|                             janet_schedule(s->fiber, janet_wrap_nil()); |                             janet_schedule(fiber, janet_wrap_nil()); | ||||||
|                         } |                         } | ||||||
|                     } else { |                     } else { | ||||||
|                         janet_cancel(s->fiber, janet_ev_lasterr()); |                         janet_cancel(fiber, janet_ev_lasterr()); | ||||||
|                     } |                     } | ||||||
|                     return JANET_ASYNC_STATUS_DONE; |                     janet_async_end(fiber); | ||||||
|  |                     return; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |             fiber->ev_in_flight = 1; | ||||||
|         } |         } | ||||||
|         break; |         break; | ||||||
| #else | #else | ||||||
| @@ -2372,13 +2370,6 @@ typedef enum { | |||||||
| } JanetWriteMode; | } JanetWriteMode; | ||||||
|  |  | ||||||
| typedef struct { | typedef struct { | ||||||
|     union { |  | ||||||
|         JanetBuffer *buf; |  | ||||||
|         const uint8_t *str; |  | ||||||
|     } src; |  | ||||||
|     int is_buffer; |  | ||||||
|     JanetWriteMode mode; |  | ||||||
|     void *dest_abst; |  | ||||||
| #ifdef JANET_WINDOWS | #ifdef JANET_WINDOWS | ||||||
|     OVERLAPPED overlapped; |     OVERLAPPED overlapped; | ||||||
|     DWORD flags; |     DWORD flags; | ||||||
| @@ -2389,6 +2380,13 @@ typedef struct { | |||||||
|     int flags; |     int flags; | ||||||
|     int32_t start; |     int32_t start; | ||||||
| #endif | #endif | ||||||
|  |     union { | ||||||
|  |         JanetBuffer *buf; | ||||||
|  |         const uint8_t *str; | ||||||
|  |     } src; | ||||||
|  |     int is_buffer; | ||||||
|  |     JanetWriteMode mode; | ||||||
|  |     void *dest_abst; | ||||||
| } StateWrite; | } StateWrite; | ||||||
|  |  | ||||||
| void ev_callback_write(JanetFiber *fiber, JanetAsyncEvent event) { | void ev_callback_write(JanetFiber *fiber, JanetAsyncEvent event) { | ||||||
| @@ -2411,15 +2409,18 @@ void ev_callback_write(JanetFiber *fiber, JanetAsyncEvent event) { | |||||||
|             janet_async_end(fiber); |             janet_async_end(fiber); | ||||||
|             break; |             break; | ||||||
| #ifdef JANET_WINDOWS | #ifdef JANET_WINDOWS | ||||||
|  |         case JANET_ASYNC_EVENT_FAILED: | ||||||
|         case JANET_ASYNC_EVENT_COMPLETE: { |         case JANET_ASYNC_EVENT_COMPLETE: { | ||||||
|             /* Called when write finished */ |             /* Called when write finished */ | ||||||
|             if (s->bytes == 0 && (state->mode != JANET_ASYNC_WRITEMODE_SENDTO)) { |             if (fiber->ev_bytes == 0 && (state->mode != JANET_ASYNC_WRITEMODE_SENDTO)) { | ||||||
|                 janet_cancel(s->fiber, janet_cstringv("disconnect")); |                 janet_cancel(fiber, janet_cstringv("disconnect")); | ||||||
|                 return JANET_ASYNC_STATUS_DONE; |                 janet_async_end(fiber); | ||||||
|  |                 return; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             janet_schedule(s->fiber, janet_wrap_nil()); |             janet_schedule(fiber, janet_wrap_nil()); | ||||||
|             return JANET_ASYNC_STATUS_DONE; |             janet_async_end(fiber); | ||||||
|  |             return; | ||||||
|         } |         } | ||||||
|         break; |         break; | ||||||
|         case JANET_ASYNC_EVENT_USER: { |         case JANET_ASYNC_EVENT_USER: { | ||||||
| @@ -2439,21 +2440,25 @@ void ev_callback_write(JanetFiber *fiber, JanetAsyncEvent event) { | |||||||
|                 bytes = state->src.str; |                 bytes = state->src.str; | ||||||
|                 len = janet_string_length(bytes); |                 len = janet_string_length(bytes); | ||||||
|             } |             } | ||||||
|             s->tag = &state->overlapped; |  | ||||||
|             memset(&(state->overlapped), 0, sizeof(WSAOVERLAPPED)); |             memset(&(state->overlapped), 0, sizeof(WSAOVERLAPPED)); | ||||||
|  |  | ||||||
|             int status; |             int status; | ||||||
| #ifdef JANET_NET | #ifdef JANET_NET | ||||||
|             if (state->mode == JANET_ASYNC_WRITEMODE_SENDTO) { |             if (state->mode == JANET_ASYNC_WRITEMODE_SENDTO) { | ||||||
|                 SOCKET sock = (SOCKET) s->stream->handle; |                 SOCKET sock = (SOCKET) stream->handle; | ||||||
|                 state->wbuf.buf = (char *) bytes; |                 state->wbuf.buf = (char *) bytes; | ||||||
|                 state->wbuf.len = len; |                 state->wbuf.len = len; | ||||||
|                 const struct sockaddr *to = state->dest_abst; |                 const struct sockaddr *to = state->dest_abst; | ||||||
|                 int tolen = (int) janet_abstract_size((void *) to); |                 int tolen = (int) janet_abstract_size((void *) to); | ||||||
|                 status = WSASendTo(sock, &state->wbuf, 1, NULL, state->flags, to, tolen, &state->overlapped, NULL); |                 status = WSASendTo(sock, &state->wbuf, 1, NULL, state->flags, to, tolen, &state->overlapped, NULL); | ||||||
|                 if (status && (WSA_IO_PENDING != WSAGetLastError())) { |                 if (status) { | ||||||
|                     janet_cancel(s->fiber, janet_ev_lasterr()); |                     if (WSA_IO_PENDING == WSAGetLastError()) { | ||||||
|                     return JANET_ASYNC_STATUS_DONE; |                         fiber->ev_in_flight = 1; | ||||||
|  |                     } else { | ||||||
|  |                         janet_cancel(fiber, janet_ev_lasterr()); | ||||||
|  |                         janet_async_end(fiber); | ||||||
|  |                         return; | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|             } else |             } else | ||||||
| #endif | #endif | ||||||
| @@ -2470,10 +2475,15 @@ void ev_callback_write(JanetFiber *fiber, JanetAsyncEvent event) { | |||||||
|                  */ |                  */ | ||||||
|                 state->overlapped.Offset = (DWORD) 0xFFFFFFFF; |                 state->overlapped.Offset = (DWORD) 0xFFFFFFFF; | ||||||
|                 state->overlapped.OffsetHigh = (DWORD) 0xFFFFFFFF; |                 state->overlapped.OffsetHigh = (DWORD) 0xFFFFFFFF; | ||||||
|                 status = WriteFile(s->stream->handle, bytes, len, NULL, &state->overlapped); |                 status = WriteFile(stream->handle, bytes, len, NULL, &state->overlapped); | ||||||
|                 if (!status && (ERROR_IO_PENDING != GetLastError())) { |                 if (!status) { | ||||||
|                     janet_cancel(s->fiber, janet_ev_lasterr()); |                     if (ERROR_IO_PENDING == GetLastError()) { | ||||||
|                     return JANET_ASYNC_STATUS_DONE; |                         fiber->ev_in_flight = 1; | ||||||
|  |                     } else { | ||||||
|  |                         janet_cancel(fiber, janet_ev_lasterr()); | ||||||
|  |                         janet_async_end(fiber); | ||||||
|  |                         return; | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @@ -2564,8 +2574,8 @@ static void janet_ev_write_generic(JanetStream *stream, void *buf, void *dest_ab | |||||||
|     state->flags = (DWORD) flags; |     state->flags = (DWORD) flags; | ||||||
| #else | #else | ||||||
|     state->flags = flags; |     state->flags = flags; | ||||||
| #endif |  | ||||||
|     state->start = 0; |     state->start = 0; | ||||||
|  | #endif | ||||||
|     ev_callback_write(f, JANET_ASYNC_EVENT_USER); |     ev_callback_write(f, JANET_ASYNC_EVENT_USER); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -43,7 +43,9 @@ static void fiber_reset(JanetFiber *fiber) { | |||||||
|     fiber->ev_callback = NULL; |     fiber->ev_callback = NULL; | ||||||
|     fiber->ev_state = NULL; |     fiber->ev_state = NULL; | ||||||
|     fiber->ev_stream = NULL; |     fiber->ev_stream = NULL; | ||||||
|  |     fiber->ev_bytes = 0; | ||||||
|     fiber->supervisor_channel = NULL; |     fiber->supervisor_channel = NULL; | ||||||
|  |     fiber->ev_in_flight = 0; | ||||||
| #endif | #endif | ||||||
|     janet_fiber_set_status(fiber, JANET_STATUS_NEW); |     janet_fiber_set_status(fiber, JANET_STATUS_NEW); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -327,12 +327,16 @@ static void janet_deinit_block(JanetGCObject *mem) { | |||||||
|             janet_free(((JanetTable *) mem)->data); |             janet_free(((JanetTable *) mem)->data); | ||||||
|             break; |             break; | ||||||
|         case JANET_MEMORY_FIBER: |         case JANET_MEMORY_FIBER: | ||||||
|  |             { | ||||||
|  |                 JanetFiber *f = (JanetFiber *)mem; | ||||||
| #ifdef JANET_EV | #ifdef JANET_EV | ||||||
|             if (((JanetFiber *)mem)->ev_state) { |                 if (f->ev_state && !f->ev_in_flight) { | ||||||
|                 janet_free(((JanetFiber *)mem)->ev_state); |                     janet_ev_dec_refcount(); | ||||||
|  |                     janet_free(f->ev_state); | ||||||
|                 } |                 } | ||||||
| #endif | #endif | ||||||
|             janet_free(((JanetFiber *)mem)->data); |                 janet_free(f->data); | ||||||
|  |             } | ||||||
|             break; |             break; | ||||||
|         case JANET_MEMORY_BUFFER: |         case JANET_MEMORY_BUFFER: | ||||||
|             janet_buffer_deinit((JanetBuffer *) mem); |             janet_buffer_deinit((JanetBuffer *) mem); | ||||||
|   | |||||||
| @@ -1051,8 +1051,10 @@ static const uint8_t *unmarshal_one_fiber( | |||||||
|     fiber->sched_id = 0; |     fiber->sched_id = 0; | ||||||
|     fiber->supervisor_channel = NULL; |     fiber->supervisor_channel = NULL; | ||||||
|     fiber->ev_state = NULL; |     fiber->ev_state = NULL; | ||||||
|  |     fiber->ev_bytes = 0; | ||||||
|     fiber->ev_callback = NULL; |     fiber->ev_callback = NULL; | ||||||
|     fiber->ev_stream = NULL; |     fiber->ev_stream = NULL; | ||||||
|  |     fiber->ev_in_flight = 0; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|     /* Push fiber to seen stack */ |     /* Push fiber to seen stack */ | ||||||
|   | |||||||
| @@ -127,12 +127,6 @@ void net_callback_connect(JanetFiber *fiber, JanetAsyncEvent event) { | |||||||
|             janet_cancel(fiber, janet_cstringv("stream closed")); |             janet_cancel(fiber, janet_cstringv("stream closed")); | ||||||
|             janet_async_end(fiber); |             janet_async_end(fiber); | ||||||
|             return; |             return; | ||||||
|         case JANET_ASYNC_EVENT_HUP: |  | ||||||
|         case JANET_ASYNC_EVENT_ERR: |  | ||||||
|         case JANET_ASYNC_EVENT_COMPLETE: |  | ||||||
|         case JANET_ASYNC_EVENT_WRITE: |  | ||||||
|         case JANET_ASYNC_EVENT_USER: |  | ||||||
|             break; |  | ||||||
|     } |     } | ||||||
| #ifdef JANET_WINDOWS | #ifdef JANET_WINDOWS | ||||||
|     int res = 0; |     int res = 0; | ||||||
| @@ -163,7 +157,7 @@ static void net_sched_connect(JanetStream *stream) { | |||||||
|     NetStateConnect *state = (NetStateConnect *) janet_async_start(f, stream, JANET_ASYNC_LISTEN_WRITE, net_callback_connect, sizeof(NetStateConnect)); |     NetStateConnect *state = (NetStateConnect *) janet_async_start(f, stream, JANET_ASYNC_LISTEN_WRITE, net_callback_connect, sizeof(NetStateConnect)); | ||||||
|     state->did_connect = 0; |     state->did_connect = 0; | ||||||
| #ifdef JANET_WINDOWS | #ifdef JANET_WINDOWS | ||||||
|     net_callback_connect(s, JANET_ASYNC_EVENT_USER); |     net_callback_connect(f, JANET_ASYNC_EVENT_USER); | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -172,7 +166,6 @@ static void net_sched_connect(JanetStream *stream) { | |||||||
| #ifdef JANET_WINDOWS | #ifdef JANET_WINDOWS | ||||||
|  |  | ||||||
| typedef struct { | typedef struct { | ||||||
|     JanetListenerState head; |  | ||||||
|     WSAOVERLAPPED overlapped; |     WSAOVERLAPPED overlapped; | ||||||
|     JanetFunction *function; |     JanetFunction *function; | ||||||
|     JanetStream *lstream; |     JanetStream *lstream; | ||||||
| @@ -180,10 +173,10 @@ typedef struct { | |||||||
|     char buf[1024]; |     char buf[1024]; | ||||||
| } NetStateAccept; | } NetStateAccept; | ||||||
|  |  | ||||||
| static int net_sched_accept_impl(NetStateAccept *state, Janet *err); | static int net_sched_accept_impl(NetStateAccept *state, JanetFiber *fiber, Janet *err); | ||||||
|  |  | ||||||
| JanetAsyncStatus net_machine_accept(JanetListenerState *s, JanetAsyncEvent event) { | void net_callback_accept(JanetFiber *fiber, JanetAsyncEvent event) { | ||||||
|     NetStateAccept *state = (NetStateAccept *)s; |     NetStateAccept *state = (NetStateAccept *)fiber->ev_state; | ||||||
|     switch (event) { |     switch (event) { | ||||||
|         default: |         default: | ||||||
|             break; |             break; | ||||||
| @@ -194,55 +187,58 @@ JanetAsyncStatus net_machine_accept(JanetListenerState *s, JanetAsyncEvent event | |||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         case JANET_ASYNC_EVENT_CLOSE: |         case JANET_ASYNC_EVENT_CLOSE: | ||||||
|             janet_schedule(s->fiber, janet_wrap_nil()); |             janet_schedule(fiber, janet_wrap_nil()); | ||||||
|             return JANET_ASYNC_STATUS_DONE; |             janet_async_end(fiber); | ||||||
|  |             return; | ||||||
|         case JANET_ASYNC_EVENT_COMPLETE: { |         case JANET_ASYNC_EVENT_COMPLETE: { | ||||||
|             if (state->astream->flags & JANET_STREAM_CLOSED) { |             if (state->astream->flags & JANET_STREAM_CLOSED) { | ||||||
|                 janet_cancel(s->fiber, janet_cstringv("failed to accept connection")); |                 janet_cancel(fiber, janet_cstringv("failed to accept connection")); | ||||||
|                 return JANET_ASYNC_STATUS_DONE; |                 janet_async_end(fiber); | ||||||
|  |                 return; | ||||||
|             } |             } | ||||||
|             SOCKET lsock = (SOCKET) state->lstream->handle; |             SOCKET lsock = (SOCKET) state->lstream->handle; | ||||||
|             if (NO_ERROR != setsockopt((SOCKET) state->astream->handle, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, |             if (NO_ERROR != setsockopt((SOCKET) state->astream->handle, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, | ||||||
|                                        (char *) &lsock, sizeof(lsock))) { |                                        (char *) &lsock, sizeof(lsock))) { | ||||||
|                 janet_cancel(s->fiber, janet_cstringv("failed to accept connection")); |                 janet_cancel(fiber, janet_cstringv("failed to accept connection")); | ||||||
|                 return JANET_ASYNC_STATUS_DONE; |                 janet_async_end(fiber); | ||||||
|  |                 return; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             Janet streamv = janet_wrap_abstract(state->astream); |             Janet streamv = janet_wrap_abstract(state->astream); | ||||||
|             if (state->function) { |             if (state->function) { | ||||||
|                 /* Schedule worker */ |                 /* Schedule worker */ | ||||||
|                 JanetFiber *fiber = janet_fiber(state->function, 64, 1, &streamv); |                 JanetFiber *sub_fiber = janet_fiber(state->function, 64, 1, &streamv); | ||||||
|                 fiber->supervisor_channel = s->fiber->supervisor_channel; |                 sub_fiber->supervisor_channel = fiber->supervisor_channel; | ||||||
|                 janet_schedule(fiber, janet_wrap_nil()); |                 janet_schedule(sub_fiber, janet_wrap_nil()); | ||||||
|                 /* Now listen again for next connection */ |                 /* Now listen again for next connection */ | ||||||
|                 Janet err; |                 Janet err; | ||||||
|                 if (net_sched_accept_impl(state, &err)) { |                 if (net_sched_accept_impl(state, fiber, &err)) { | ||||||
|                     janet_cancel(s->fiber, err); |                     janet_cancel(fiber, err); | ||||||
|                     return JANET_ASYNC_STATUS_DONE; |                     janet_async_end(fiber); | ||||||
|  |                     return; | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 janet_schedule(s->fiber, streamv); |                 janet_schedule(fiber, streamv); | ||||||
|                 return JANET_ASYNC_STATUS_DONE; |                 janet_async_end(fiber); | ||||||
|  |                 return; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     return JANET_ASYNC_STATUS_NOT_DONE; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| JANET_NO_RETURN static void janet_sched_accept(JanetStream *stream, JanetFunction *fun) { | JANET_NO_RETURN static void janet_sched_accept(JanetStream *stream, JanetFunction *fun) { | ||||||
|     Janet err; |     Janet err; | ||||||
|     JanetListenerState *s = janet_listen(stream, net_machine_accept, JANET_ASYNC_LISTEN_READ, sizeof(NetStateAccept), NULL); |     JanetFiber *f = janet_vm.root_fiber; | ||||||
|     NetStateAccept *state = (NetStateAccept *)s; |     NetStateAccept *state = (NetStateAccept *) janet_async_start(f, stream, JANET_ASYNC_LISTEN_READ, net_callback_accept, sizeof(NetStateAccept)); | ||||||
|     memset(&state->overlapped, 0, sizeof(WSAOVERLAPPED)); |     memset(&state->overlapped, 0, sizeof(WSAOVERLAPPED)); | ||||||
|     memset(&state->buf, 0, 1024); |     memset(&state->buf, 0, 1024); | ||||||
|     state->function = fun; |     state->function = fun; | ||||||
|     state->lstream = stream; |     state->lstream = stream; | ||||||
|     s->tag = &state->overlapped; |     if (net_sched_accept_impl(state, f, &err)) janet_panicv(err); | ||||||
|     if (net_sched_accept_impl(state, &err)) janet_panicv(err); |  | ||||||
|     janet_await(); |     janet_await(); | ||||||
| } | } | ||||||
|  |  | ||||||
| static int net_sched_accept_impl(NetStateAccept *state, Janet *err) { | static int net_sched_accept_impl(NetStateAccept *state, JanetFiber *fiber, Janet *err) { | ||||||
|     SOCKET lsock = (SOCKET) state->lstream->handle; |     SOCKET lsock = (SOCKET) state->lstream->handle; | ||||||
|     SOCKET asock = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); |     SOCKET asock = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); | ||||||
|     if (asock == INVALID_SOCKET) { |     if (asock == INVALID_SOCKET) { | ||||||
| @@ -254,7 +250,11 @@ static int net_sched_accept_impl(NetStateAccept *state, Janet *err) { | |||||||
|     int socksize = sizeof(SOCKADDR_STORAGE) + 16; |     int socksize = sizeof(SOCKADDR_STORAGE) + 16; | ||||||
|     if (FALSE == AcceptEx(lsock, asock, state->buf, 0, socksize, socksize, NULL, &state->overlapped)) { |     if (FALSE == AcceptEx(lsock, asock, state->buf, 0, socksize, socksize, NULL, &state->overlapped)) { | ||||||
|         int code = WSAGetLastError(); |         int code = WSAGetLastError(); | ||||||
|         if (code == WSA_IO_PENDING) return 0; /* indicates io is happening async */ |         if (code == WSA_IO_PENDING) { | ||||||
|  |             /* indicates io is happening async */ | ||||||
|  |             fiber->ev_in_flight = 1; | ||||||
|  |             return 0; | ||||||
|  |         } | ||||||
|         *err = janet_ev_lasterr(); |         *err = janet_ev_lasterr(); | ||||||
|         return 1; |         return 1; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -596,7 +596,8 @@ typedef enum { | |||||||
|     JANET_ASYNC_EVENT_READ = 6, |     JANET_ASYNC_EVENT_READ = 6, | ||||||
|     JANET_ASYNC_EVENT_WRITE = 7, |     JANET_ASYNC_EVENT_WRITE = 7, | ||||||
|     JANET_ASYNC_EVENT_COMPLETE = 8, /* Used on windows for IOCP */ |     JANET_ASYNC_EVENT_COMPLETE = 8, /* Used on windows for IOCP */ | ||||||
|     JANET_ASYNC_EVENT_USER = 9 |     JANET_ASYNC_EVENT_FAILED = 9, /* Used on windows for IOCP */ | ||||||
|  |     JANET_ASYNC_EVENT_USER = 10 | ||||||
| } JanetAsyncEvent; | } JanetAsyncEvent; | ||||||
|  |  | ||||||
| typedef enum { | typedef enum { | ||||||
| @@ -924,8 +925,10 @@ struct JanetFiber { | |||||||
|     uint32_t sched_id; /* Increment everytime fiber is scheduled by event loop */ |     uint32_t sched_id; /* Increment everytime fiber is scheduled by event loop */ | ||||||
|     JanetEVCallback ev_callback; /* Call this before starting scheduled fibers */ |     JanetEVCallback ev_callback; /* Call this before starting scheduled fibers */ | ||||||
|     JanetStream *ev_stream; /* which stream we are waiting on */ |     JanetStream *ev_stream; /* which stream we are waiting on */ | ||||||
|     void *ev_state; /* Extra data for ev callback state */ |     void *ev_state; /* Extra data for ev callback state. On windows, first element must be OVERLAPPED. */ | ||||||
|     void *supervisor_channel; /* Channel to push self to when complete */ |     void *supervisor_channel; /* Channel to push self to when complete */ | ||||||
|  |     uint32_t ev_bytes; /* Number of bytes for completion event */ | ||||||
|  |     int ev_in_flight; /* If overlapped operation is in flight */ | ||||||
| #endif | #endif | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -42,9 +42,6 @@ | |||||||
|   (set suite-name |   (set suite-name | ||||||
|        (cond |        (cond | ||||||
|          (number? x) (string x) |          (number? x) (string x) | ||||||
|          (string? x) (string/slice x |  | ||||||
|                                    (length "test/suite-") |  | ||||||
|                                    (- (inc (length ".janet")))) |  | ||||||
|          (string x))) |          (string x))) | ||||||
|   (set start-time (os/clock)) |   (set start-time (os/clock)) | ||||||
|   (eprint "Starting suite " suite-name "...")) |   (eprint "Starting suite " suite-name "...")) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Calvin Rose
					Calvin Rose