1
0
mirror of https://github.com/janet-lang/janet synced 2025-01-10 15:40:30 +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:
Calvin Rose 2023-10-07 08:01:35 -07:00
parent e7e4341e70
commit 7bfb17c209
7 changed files with 132 additions and 114 deletions

View File

@ -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) {
janet_free(fiber->ev_state); if (!fiber->ev_in_flight) {
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 */ if (NULL == CreateIoCompletionPort(stream->handle, janet_vm.iocp, (ULONG_PTR) stream, 0)) {
JanetListenerState *state = janet_listen_impl(stream, behavior, mask, size, user); janet_panicf("failed to listen for events: %V", janet_ev_lasterr());
if (!(stream->flags & JANET_STREAM_REGISTERED)) {
if (NULL == CreateIoCompletionPort(stream->handle, janet_vm.iocp, (ULONG_PTR) stream, 0)) {
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) { if (fiber != NULL) {
state->event = overlapped; fiber->ev_in_flight = 0;
state->bytes = num_bytes_transfered; fiber->ev_bytes = num_bytes_transfered;
JanetAsyncStatus status = state->machine(state, JANET_ASYNC_EVENT_COMPLETE); fiber->ev_callback(fiber, result ? JANET_ASYNC_EVENT_COMPLETE : JANET_ASYNC_EVENT_FAILED);
if (status == JANET_ASYNC_STATUS_DONE) { } else {
janet_unlisten(state); 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);
} }

View File

@ -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);
} }

View File

@ -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);

View File

@ -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 */

View File

@ -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;
} }

View File

@ -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
}; };

View File

@ -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 "..."))