Merge branch 'iocp-fixes'

* iocp-fixes:
  regress: test for HTTP/HTTPS with IOCP enabled
  bev_async: trigger/run only deferred callbacks
  bev_async: do not initialize timeouts multiple times
  bev_async: set "ok" on setfd if fd>=0 (like we do during creation)
  bev_async: ignore ERROR_INVALID_PARAMETER on .setfd for iocp

Closes: #709
Refs: nmathewson/Libevent#160
(cherry picked from commit 3d815cf22074792f31274fd6d810a94984661dbf)
This commit is contained in:
Azat Khuzhin 2018-11-13 22:47:43 +03:00 committed by Azat Khuzhin
parent 6ac2ec2500
commit 6bfac964e7
No known key found for this signature in database
GPG Key ID: B86086848EF8686D
4 changed files with 44 additions and 18 deletions

View File

@ -100,6 +100,27 @@ const struct bufferevent_ops bufferevent_ops_async = {
be_async_ctrl,
};
static inline void
be_async_run_eventcb(struct bufferevent *bev, short what, int options)
{ bufferevent_run_eventcb_(bev, what, options|BEV_TRIG_DEFER_CALLBACKS); }
static inline void
be_async_trigger_nolock(struct bufferevent *bev, short what, int options)
{ bufferevent_trigger_nolock_(bev, what, options|BEV_TRIG_DEFER_CALLBACKS); }
static inline int
fatal_error(int err)
{
switch (err) {
/* We may have already associated this fd with a port.
* Let's hope it's this port, and that the error code
* for doing this neer changes. */
case ERROR_INVALID_PARAMETER:
return 0;
}
return 1;
}
static inline struct bufferevent_async *
upcast(struct bufferevent *bev)
{
@ -217,7 +238,7 @@ bev_async_consider_writing(struct bufferevent_async *beva)
&beva->write_overlapped)) {
bufferevent_decref_(bev);
beva->ok = 0;
bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0);
be_async_run_eventcb(bev, BEV_EVENT_ERROR, 0);
} else {
beva->write_in_progress = at_most;
bufferevent_decrement_write_buckets_(&beva->bev, at_most);
@ -270,7 +291,7 @@ bev_async_consider_reading(struct bufferevent_async *beva)
bufferevent_incref_(bev);
if (evbuffer_launch_read_(bev->input, at_most, &beva->read_overlapped)) {
beva->ok = 0;
bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0);
be_async_run_eventcb(bev, BEV_EVENT_ERROR, 0);
bufferevent_decref_(bev);
} else {
beva->read_in_progress = at_most;
@ -428,8 +449,7 @@ connect_complete(struct event_overlapped *eo, ev_uintptr_t key,
else
bev_async_set_wsa_error(bev, eo);
bufferevent_run_eventcb_(bev,
ok? BEV_EVENT_CONNECTED : BEV_EVENT_ERROR, 0);
be_async_run_eventcb(bev, ok ? BEV_EVENT_CONNECTED : BEV_EVENT_ERROR, 0);
event_base_del_virtual_(bev->ev_base);
@ -459,16 +479,16 @@ read_complete(struct event_overlapped *eo, ev_uintptr_t key,
if (bev_a->ok) {
if (ok && nbytes) {
BEV_RESET_GENERIC_READ_TIMEOUT(bev);
bufferevent_trigger_nolock_(bev, EV_READ, 0);
be_async_trigger_nolock(bev, EV_READ, 0);
bev_async_consider_reading(bev_a);
} else if (!ok) {
what |= BEV_EVENT_ERROR;
bev_a->ok = 0;
bufferevent_run_eventcb_(bev, what, 0);
be_async_run_eventcb(bev, what, 0);
} else if (!nbytes) {
what |= BEV_EVENT_EOF;
bev_a->ok = 0;
bufferevent_run_eventcb_(bev, what, 0);
be_async_run_eventcb(bev, what, 0);
}
}
@ -502,16 +522,16 @@ write_complete(struct event_overlapped *eo, ev_uintptr_t key,
if (bev_a->ok) {
if (ok && nbytes) {
BEV_RESET_GENERIC_WRITE_TIMEOUT(bev);
bufferevent_trigger_nolock_(bev, EV_WRITE, 0);
be_async_trigger_nolock(bev, EV_WRITE, 0);
bev_async_consider_writing(bev_a);
} else if (!ok) {
what |= BEV_EVENT_ERROR;
bev_a->ok = 0;
bufferevent_run_eventcb_(bev, what, 0);
be_async_run_eventcb(bev, what, 0);
} else if (!nbytes) {
what |= BEV_EVENT_EOF;
bev_a->ok = 0;
bufferevent_run_eventcb_(bev, what, 0);
be_async_run_eventcb(bev, what, 0);
}
}
@ -532,11 +552,7 @@ bufferevent_async_new_(struct event_base *base,
return NULL;
if (fd >= 0 && event_iocp_port_associate_(iocp, fd, 1)<0) {
int err = GetLastError();
/* We may have alrady associated this fd with a port.
* Let's hope it's this port, and that the error code
* for doing this neer changes. */
if (err != ERROR_INVALID_PARAMETER)
if (fatal_error(GetLastError()))
return NULL;
}
@ -580,7 +596,6 @@ bufferevent_async_set_connected_(struct bufferevent *bev)
{
struct bufferevent_async *bev_async = upcast(bev);
bev_async->ok = 1;
bufferevent_init_generic_timeout_cbs_(bev);
/* Now's a good time to consider reading/writing */
be_async_enable(bev, bev->enabled);
}
@ -654,16 +669,20 @@ be_async_ctrl(struct bufferevent *bev, enum bufferevent_ctrl_op op,
data->fd = evbuffer_overlapped_get_fd_(bev->input);
return 0;
case BEV_CTRL_SET_FD: {
struct bufferevent_async *bev_a = upcast(bev);
struct event_iocp_port *iocp;
if (data->fd == evbuffer_overlapped_get_fd_(bev->input))
return 0;
if (!(iocp = event_base_get_iocp_(bev->ev_base)))
return -1;
if (event_iocp_port_associate_(iocp, data->fd, 1) < 0)
return -1;
if (event_iocp_port_associate_(iocp, data->fd, 1) < 0) {
if (fatal_error(GetLastError()))
return -1;
}
evbuffer_overlapped_set_fd_(bev->input, data->fd);
evbuffer_overlapped_set_fd_(bev->output, data->fd);
bev_a->ok = data->fd >= 0;
return 0;
}
case BEV_CTRL_CANCEL_ALL: {

View File

@ -43,6 +43,7 @@ extern struct testcase_t bufferevent_iocp_testcases[];
extern struct testcase_t util_testcases[];
extern struct testcase_t signal_testcases[];
extern struct testcase_t http_testcases[];
extern struct testcase_t http_iocp_testcases[];
extern struct testcase_t dns_testcases[];
extern struct testcase_t rpc_testcases[];
extern struct testcase_t edgetriggered_testcases[];

View File

@ -4786,3 +4786,8 @@ struct testcase_t http_testcases[] = {
END_OF_TESTCASES
};
struct testcase_t http_iocp_testcases[] = {
{ "simple", http_simple_test, TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, NULL },
{ "https_simple", https_simple_test, TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, NULL },
END_OF_TESTCASES
};

View File

@ -384,6 +384,7 @@ struct testgroup_t testgroups[] = {
{ "iocp/", iocp_testcases },
{ "iocp/bufferevent/", bufferevent_iocp_testcases },
{ "iocp/listener/", listener_iocp_testcases },
{ "iocp/http/", http_iocp_testcases },
#endif
#ifdef EVENT__HAVE_OPENSSL
{ "ssl/", ssl_testcases },