From 97dd87facbc6ad47653f7d304b65e25b652970b5 Mon Sep 17 00:00:00 2001 From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org> Date: Thu, 29 Nov 2018 17:48:12 +0300 Subject: [PATCH] evio: make on_accept be nothrow Evio is going to be C, because it is needed in SWIM to 1) support UNIX sockets in future; 2) do not care about setting SocketError directly. It is not possible via bare sio, because sio_bind ignores EADDRINUSE. A first step to make evio C - eliminate exceptions from its callbacks available to other modules. The only callback it has - on_accept. Needed for #3234 --- src/box/iproto.cc | 17 +++++++---------- src/coio.cc | 13 ++++++------- src/evio.cc | 13 ++++++------- src/evio.h | 20 ++++++++++---------- 4 files changed, 29 insertions(+), 34 deletions(-) diff --git a/src/box/iproto.cc b/src/box/iproto.cc index df4c26823b..3df4de1f8c 100644 --- a/src/box/iproto.cc +++ b/src/box/iproto.cc @@ -1800,7 +1800,7 @@ static const struct cmsg_hop connect_route[] = { /** * Create a connection and start input. */ -static void +static int iproto_on_accept(struct evio_service * /* service */, int fd, struct sockaddr *addr, socklen_t addrlen) { @@ -1809,26 +1809,23 @@ iproto_on_accept(struct evio_service * /* service */, int fd, struct iproto_msg *msg; struct iproto_connection *con = iproto_connection_new(fd); if (con == NULL) - goto error_conn; + return -1; /* * Ignore msg allocation failure - the queue size is * fixed so there is a limited number of msgs in * use, all stored in just a few blocks of the memory pool. */ msg = iproto_msg_new(con); - if (msg == NULL) - goto error_msg; + if (msg == NULL) { + mempool_free(&iproto_connection_pool, con); + return -1; + } cmsg_init(&msg->base, connect_route); msg->p_ibuf = con->p_ibuf; msg->wpos = con->wpos; msg->close_connection = false; cpipe_push(&tx_pipe, &msg->base); - return; -error_msg: - mempool_free(&iproto_connection_pool, con); -error_conn: - close(fd); - return; + return 0; } static struct evio_service binary; /* iproto binary listener */ diff --git a/src/coio.cc b/src/coio.cc index f29b648009..46333e01a6 100644 --- a/src/coio.cc +++ b/src/coio.cc @@ -590,7 +590,7 @@ coio_recvfrom_timeout(struct ev_io *coio, void *buf, size_t sz, int flags, } } -void +static int coio_service_on_accept(struct evio_service *evio_service, int fd, struct sockaddr *addr, socklen_t addrlen) { @@ -606,14 +606,12 @@ coio_service_on_accept(struct evio_service *evio_service, "%s/%s", evio_service->name, sio_strfaddr(addr, addrlen)); /* Create the worker fiber. */ - struct fiber *f; - try { - f = fiber_new_xc(fiber_name, service->handler); - } catch (struct error *e) { - error_log(e); + struct fiber *f = fiber_new(fiber_name, service->handler); + if (f == NULL) { + diag_log(); say_error("can't create a handler fiber, dropping client connection"); evio_close(loop(), &coio); - throw; + return -1; } /* * The coio is passed into the created fiber, reset the @@ -625,6 +623,7 @@ coio_service_on_accept(struct evio_service *evio_service, * and will have to close it and free before termination. */ fiber_start(f, coio, addr, addrlen, service->handler_param); + return 0; } void diff --git a/src/evio.cc b/src/evio.cc index c0addaf16d..a3d47b2f70 100644 --- a/src/evio.cc +++ b/src/evio.cc @@ -195,8 +195,10 @@ evio_service_accept_cb(ev_loop * /* loop */, ev_io *watcher, * Invoke the callback and pass it the accepted * socket. */ - service->on_accept(service, fd, (struct sockaddr *)&addr, addrlen); - + if (service->on_accept(service, fd, + (struct sockaddr *)&addr, + addrlen) != 0) + diag_raise(); } catch (Exception *e) { if (fd >= 0) close(fd); @@ -308,11 +310,8 @@ evio_service_listen(struct evio_service *service) } void -evio_service_init(ev_loop *loop, - struct evio_service *service, const char *name, - void (*on_accept)(struct evio_service *, int, - struct sockaddr *, socklen_t), - void *on_accept_param) +evio_service_init(ev_loop *loop, struct evio_service *service, const char *name, + evio_accept_f on_accept, void *on_accept_param) { memset(service, 0, sizeof(struct evio_service)); snprintf(service->name, sizeof(service->name), "%s", name); diff --git a/src/evio.h b/src/evio.h index e91ba11fc3..e56e2b8a7b 100644 --- a/src/evio.h +++ b/src/evio.h @@ -62,6 +62,11 @@ * If a service is not started, but only initialized, no * dedicated cleanup/destruction is necessary. */ +struct evio_service; + +typedef int (*evio_accept_f)(struct evio_service *, int, struct sockaddr *, + socklen_t); + struct evio_service { /** Service name. E.g. 'primary', 'secondary', etc. */ @@ -79,12 +84,10 @@ struct evio_service /** * A callback invoked on every accepted client socket. - * It's OK to throw an exception in the callback: - * when it happens, the exception is logged, and the - * accepted socket is closed. + * If a callback returned != 0, the accepted socket is + * closed and the error is logged. */ - void (*on_accept)(struct evio_service *, int, - struct sockaddr *, socklen_t); + evio_accept_f on_accept; void *on_accept_param; /** libev io object for the acceptor socket. */ @@ -94,11 +97,8 @@ struct evio_service /** Initialize the service. Don't bind to the port yet. */ void -evio_service_init(ev_loop *loop, - struct evio_service *service, const char *name, - void (*on_accept)(struct evio_service *, - int, struct sockaddr *, socklen_t), - void *on_accept_param); +evio_service_init(ev_loop *loop, struct evio_service *service, const char *name, + evio_accept_f on_accept, void *on_accept_param); /** Bind service to specified uri */ void -- GitLab