Windows: clean up tcp endgame code, pass test-callback-stack
This commit is contained in:
parent
51ced6c176
commit
6a4ead0eac
172
oio-win.c
172
oio-win.c
@ -127,7 +127,9 @@ static LPFN_TRANSMITFILE pTransmitFile;
|
|||||||
#define OIO_HANDLE_CONNECTED 0x0020
|
#define OIO_HANDLE_CONNECTED 0x0020
|
||||||
#define OIO_HANDLE_READING 0x0040
|
#define OIO_HANDLE_READING 0x0040
|
||||||
#define OIO_HANDLE_EOF 0x0080
|
#define OIO_HANDLE_EOF 0x0080
|
||||||
#define OIO_HANDLE_SHUT 0x0100
|
#define OIO_HANDLE_SHUTTING 0x0100
|
||||||
|
#define OIO_HANDLE_SHUT 0x0200
|
||||||
|
#define OIO_HANDLE_ENDGAME_QUEUED 0x0400
|
||||||
#define OIO_HANDLE_BIND_ERROR 0x1000
|
#define OIO_HANDLE_BIND_ERROR 0x1000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -147,7 +149,7 @@ static struct oio_timer_s oio_timers_ = RB_INITIALIZER(oio_timers_);
|
|||||||
|
|
||||||
|
|
||||||
/* Head of a single-linked list of closed handles */
|
/* Head of a single-linked list of closed handles */
|
||||||
static oio_handle* oio_closed_handles_ = NULL;
|
static oio_handle* oio_endgame_handles_ = NULL;
|
||||||
|
|
||||||
|
|
||||||
/* The current time according to the event loop. in msecs. */
|
/* The current time according to the event loop. in msecs. */
|
||||||
@ -445,13 +447,84 @@ int oio_tcp_init(oio_handle* handle, oio_close_cb close_cb,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void oio_close_ready(oio_handle* handle) {
|
static void oio_tcp_endgame(oio_handle* handle) {
|
||||||
assert(handle->flags & OIO_HANDLE_CLOSING);
|
oio_err err;
|
||||||
assert(!(handle->flags & OIO_HANDLE_CLOSED));
|
int status;
|
||||||
assert(handle->reqs_pending == 0);
|
|
||||||
|
|
||||||
handle->closed_next = oio_closed_handles_;
|
if (handle->flags & OIO_HANDLE_SHUTTING &&
|
||||||
oio_closed_handles_ = handle;
|
!(handle->flags & OIO_HANDLE_SHUT) &&
|
||||||
|
handle->write_reqs_pending == 0) {
|
||||||
|
|
||||||
|
if (shutdown(handle->socket, SD_SEND) != SOCKET_ERROR) {
|
||||||
|
status = 0;
|
||||||
|
handle->flags |= OIO_HANDLE_SHUT;
|
||||||
|
} else {
|
||||||
|
status = -1;
|
||||||
|
err = oio_new_sys_error(WSAGetLastError());
|
||||||
|
}
|
||||||
|
if (handle->shutdown_req->cb) {
|
||||||
|
handle->shutdown_req->flags &= ~OIO_REQ_PENDING;
|
||||||
|
if (status == -1) {
|
||||||
|
oio_last_error_ = err;
|
||||||
|
}
|
||||||
|
((oio_shutdown_cb)handle->shutdown_req->cb)(handle->shutdown_req, status);
|
||||||
|
}
|
||||||
|
handle->reqs_pending--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handle->flags & OIO_HANDLE_EOF &&
|
||||||
|
handle->flags & OIO_HANDLE_SHUT &&
|
||||||
|
!(handle->flags & OIO_HANDLE_CLOSING)) {
|
||||||
|
/* Because oio_close will add the handle to the endgame_handles list, */
|
||||||
|
/* return here and call the close cb the next time. */
|
||||||
|
oio_close(handle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handle->flags & OIO_HANDLE_CLOSING &&
|
||||||
|
!(handle->flags & OIO_HANDLE_CLOSED) &&
|
||||||
|
handle->reqs_pending == 0) {
|
||||||
|
handle->flags |= OIO_HANDLE_CLOSED;
|
||||||
|
|
||||||
|
if (handle->close_cb) {
|
||||||
|
oio_last_error_ = handle->error;
|
||||||
|
handle->close_cb(handle, handle->error.code == OIO_OK ? 0 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
oio_refs_--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void oio_call_endgames() {
|
||||||
|
oio_handle* handle;
|
||||||
|
|
||||||
|
while (oio_endgame_handles_) {
|
||||||
|
handle = oio_endgame_handles_;
|
||||||
|
oio_endgame_handles_ = handle->endgame_next;
|
||||||
|
|
||||||
|
handle->flags &= ~OIO_HANDLE_ENDGAME_QUEUED;
|
||||||
|
|
||||||
|
switch (handle->type) {
|
||||||
|
case OIO_TCP:
|
||||||
|
oio_tcp_endgame(handle);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void oio_want_endgame(oio_handle* handle) {
|
||||||
|
if (!(handle->flags & OIO_HANDLE_ENDGAME_QUEUED)) {
|
||||||
|
handle->flags |= OIO_HANDLE_ENDGAME_QUEUED;
|
||||||
|
|
||||||
|
handle->endgame_next = oio_endgame_handles_;
|
||||||
|
oio_endgame_handles_ = handle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -466,13 +539,7 @@ static int oio_close_error(oio_handle* handle, oio_err e) {
|
|||||||
case OIO_TCP:
|
case OIO_TCP:
|
||||||
closesocket(handle->socket);
|
closesocket(handle->socket);
|
||||||
handle->flags |= OIO_HANDLE_CLOSING;
|
handle->flags |= OIO_HANDLE_CLOSING;
|
||||||
|
oio_want_endgame(handle);
|
||||||
/* If there are no pending requests for this handle, enqueue the close */
|
|
||||||
/* callback immediately. Otherwise oio_poll will do it after the last */
|
|
||||||
/* request returns. */
|
|
||||||
if (handle->reqs_pending == 0) {
|
|
||||||
oio_close_ready(handle);
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -488,28 +555,6 @@ int oio_close(oio_handle* handle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void oio_call_close_cbs() {
|
|
||||||
oio_handle* handle;
|
|
||||||
|
|
||||||
while (oio_closed_handles_) {
|
|
||||||
handle = oio_closed_handles_;
|
|
||||||
oio_closed_handles_ = handle->closed_next;
|
|
||||||
|
|
||||||
assert(handle->flags & OIO_HANDLE_CLOSING);
|
|
||||||
assert(!(handle->flags & OIO_HANDLE_CLOSED));
|
|
||||||
assert(handle->reqs_pending == 0);
|
|
||||||
|
|
||||||
handle->flags |= OIO_HANDLE_CLOSED;
|
|
||||||
oio_refs_--;
|
|
||||||
|
|
||||||
if (handle->close_cb) {
|
|
||||||
oio_last_error_ = handle->error;
|
|
||||||
handle->close_cb(handle, handle->error.code == OIO_OK ? 0 : 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct sockaddr_in oio_ip4_addr(char* ip, int port) {
|
struct sockaddr_in oio_ip4_addr(char* ip, int port) {
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
|
|
||||||
@ -711,7 +756,7 @@ int oio_read_start(oio_handle* handle, oio_read_cb cb) {
|
|||||||
|
|
||||||
/* If reading was stopped and then started again, there could stell be a */
|
/* If reading was stopped and then started again, there could stell be a */
|
||||||
/* read request pending. */
|
/* read request pending. */
|
||||||
if (!handle->read_accept_req.flags & OIO_REQ_PENDING)
|
if (!(handle->read_accept_req.flags & OIO_REQ_PENDING))
|
||||||
oio_queue_read(handle);
|
oio_queue_read(handle);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -787,7 +832,7 @@ int oio_write(oio_req* req, oio_buf* bufs, int bufcnt) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req->handle->flags & OIO_HANDLE_SHUT) {
|
if (req->handle->flags & OIO_HANDLE_SHUTTING) {
|
||||||
oio_set_sys_error(WSAESHUTDOWN);
|
oio_set_sys_error(WSAESHUTDOWN);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -824,27 +869,19 @@ int oio_shutdown(oio_req* req) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handle->flags & OIO_HANDLE_SHUT) {
|
if (handle->flags & OIO_HANDLE_SHUTTING) {
|
||||||
oio_set_sys_error(WSAESHUTDOWN);
|
oio_set_sys_error(WSAESHUTDOWN);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle->flags |= OIO_HANDLE_SHUT;
|
req->type = OIO_SHUTDOWN;
|
||||||
|
req->flags |= OIO_REQ_PENDING;
|
||||||
|
|
||||||
if (handle->write_reqs_pending == 0) {
|
handle->flags |= OIO_HANDLE_SHUTTING;
|
||||||
if (shutdown(handle->socket, SD_SEND) == SOCKET_ERROR) {
|
|
||||||
oio_set_sys_error(WSAGetLastError());
|
|
||||||
status = -1;
|
|
||||||
}
|
|
||||||
if (handle->flags & OIO_HANDLE_EOF) {
|
|
||||||
oio_close_error(handle, status == 0 ? oio_ok_ : oio_last_error_);
|
|
||||||
}
|
|
||||||
if (req->cb) {
|
|
||||||
((oio_shutdown_cb)req->cb)(req, status);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
handle->shutdown_req = req;
|
handle->shutdown_req = req;
|
||||||
}
|
handle->reqs_pending++;
|
||||||
|
|
||||||
|
oio_want_endgame(handle);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -914,7 +951,7 @@ static void oio_poll() {
|
|||||||
|
|
||||||
/* Call all pending close callbacks. */
|
/* Call all pending close callbacks. */
|
||||||
/* TODO: ugly, fixme. */
|
/* TODO: ugly, fixme. */
|
||||||
oio_call_close_cbs();
|
oio_call_endgames();
|
||||||
if (oio_refs_ == 0)
|
if (oio_refs_ == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -974,23 +1011,11 @@ static void oio_poll() {
|
|||||||
if (req->cb) {
|
if (req->cb) {
|
||||||
((oio_write_cb)req->cb)(req, success ? 0 : -1);
|
((oio_write_cb)req->cb)(req, success ? 0 : -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
handle->write_reqs_pending--;
|
handle->write_reqs_pending--;
|
||||||
|
|
||||||
if (success &&
|
if (success &&
|
||||||
handle->write_reqs_pending == 0
|
handle->write_reqs_pending == 0 &&
|
||||||
&& handle->flags & OIO_HANDLE_SHUT) {
|
handle->flags & OIO_HANDLE_SHUTTING) {
|
||||||
status = 0;
|
oio_want_endgame(handle);
|
||||||
if (shutdown(handle->socket, SD_SEND) == SOCKET_ERROR) {
|
|
||||||
oio_set_sys_error(WSAGetLastError());
|
|
||||||
status = -1;
|
|
||||||
}
|
|
||||||
if (handle->flags & OIO_HANDLE_EOF) {
|
|
||||||
oio_close_error(handle, status == 0 ? oio_ok_ : oio_last_error_);
|
|
||||||
}
|
|
||||||
if (handle->shutdown_req->cb) {
|
|
||||||
((oio_shutdown_cb)handle->shutdown_req->cb)(handle->shutdown_req, status);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1025,10 +1050,7 @@ static void oio_poll() {
|
|||||||
oio_last_error_.code = OIO_EOF;
|
oio_last_error_.code = OIO_EOF;
|
||||||
oio_last_error_.sys_errno_ = ERROR_SUCCESS;
|
oio_last_error_.sys_errno_ = ERROR_SUCCESS;
|
||||||
((oio_read_cb)handle->read_cb)(handle, -1, buf);
|
((oio_read_cb)handle->read_cb)(handle, -1, buf);
|
||||||
if ((handle->flags & OIO_HANDLE_SHUT) &&
|
oio_want_endgame(handle);
|
||||||
handle->write_reqs_pending == 0) {
|
|
||||||
oio_close(handle);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1108,7 +1130,7 @@ static void oio_poll() {
|
|||||||
/* more pending requests. */
|
/* more pending requests. */
|
||||||
if (handle->flags & OIO_HANDLE_CLOSING &&
|
if (handle->flags & OIO_HANDLE_CLOSING &&
|
||||||
handle->reqs_pending == 0) {
|
handle->reqs_pending == 0) {
|
||||||
oio_close_ready(handle);
|
oio_want_endgame(handle);
|
||||||
}
|
}
|
||||||
} /* if (overlapped) */
|
} /* if (overlapped) */
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,7 +54,7 @@ typedef struct oio_buf {
|
|||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
#define oio_handle_private_fields \
|
#define oio_handle_private_fields \
|
||||||
oio_handle* closed_next; \
|
oio_handle* endgame_next; \
|
||||||
union { \
|
union { \
|
||||||
SOCKET socket; \
|
SOCKET socket; \
|
||||||
HANDLE handle; \
|
HANDLE handle; \
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user