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:
parent
e7e4341e70
commit
7bfb17c209
156
src/core/ev.c
156
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) {
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 "..."))
|
||||||
|
Loading…
Reference in New Issue
Block a user