From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: From: Vladislav Shpilevoy Subject: [PATCH 03/11] sio: remove exceptions Date: Fri, 30 Nov 2018 18:39:35 +0300 Message-Id: <14e50e3a3872a1898d5df006fb61442c1ab2e556.1543590433.git.v.shpilevoy@tarantool.org> In-Reply-To: References: In-Reply-To: References: To: tarantool-patches@freelists.org Cc: vdavydov.dev@gmail.com List-ID: To turn sio into C it should not have exceptions. Replace them with diagnostics setting. In some cases errors are not critical so several functions return an error criticalness along with setting or not setting diag. --- src/box/iproto.cc | 31 ++++++++++-------- src/coio.cc | 54 +++++++++++++++++++------------ src/evio.cc | 13 +++++--- src/sio.cc | 72 ++++++++++++++++++++++++++++------------- src/sio.h | 81 +++++++++++++++++++++++++++++++++++++++-------- 5 files changed, 176 insertions(+), 75 deletions(-) diff --git a/src/box/iproto.cc b/src/box/iproto.cc index cd613932e..07ef23cac 100644 --- a/src/box/iproto.cc +++ b/src/box/iproto.cc @@ -857,8 +857,12 @@ iproto_connection_on_input(ev_loop *loop, struct ev_io *watcher, return; } /* Read input. */ - int nrd = sio_read(fd, in->wpos, ibuf_unused(in)); + bool is_error_fatal; + int nrd = sio_read(fd, in->wpos, ibuf_unused(in), + &is_error_fatal); if (nrd < 0) { /* Socket is not ready. */ + if (is_error_fatal) + diag_raise(); ev_io_start(loop, &con->input); return; } @@ -922,11 +926,12 @@ iproto_flush(struct iproto_connection *con) /* *Overwrite* iov_len of the last pos as it may be garbage. */ iov[iovcnt-1].iov_len = end->iov_len - begin->iov_len * (iovcnt == 1); - ssize_t nwr = sio_writev(fd, iov, iovcnt); - - /* Count statistics */ - rmean_collect(rmean_net, IPROTO_SENT, nwr); - if (nwr > 0) { + bool is_error_fatal; + ssize_t nwr = sio_writev(fd, iov, iovcnt, &is_error_fatal); + if (nwr < 0 && is_error_fatal) + diag_raise(); + else if (nwr > 0) { + rmean_collect(rmean_net, IPROTO_SENT, nwr); if (begin->used + nwr == end->used) { *begin = *end; return 0; @@ -1752,15 +1757,13 @@ net_send_greeting(struct cmsg *m) struct iproto_connection *con = msg->connection; if (msg->close_connection) { struct obuf *out = msg->wpos.obuf; - try { - int64_t nwr = sio_writev(con->output.fd, out->iov, - obuf_iovcnt(out)); - - /* Count statistics */ + bool is_error_fatal; + int64_t nwr = sio_writev(con->output.fd, out->iov, + obuf_iovcnt(out), &is_error_fatal); + if (nwr < 0 && is_error_fatal) + diag_log(); + else if (nwr > 0) rmean_collect(rmean_net, IPROTO_SENT, nwr); - } catch (Exception *e) { - e->log(); - } assert(iproto_connection_is_idle(con)); iproto_connection_close(con); iproto_msg_delete(msg); diff --git a/src/coio.cc b/src/coio.cc index e91de40b5..b69f5e31a 100644 --- a/src/coio.cc +++ b/src/coio.cc @@ -78,11 +78,9 @@ coio_connect_addr(struct ev_io *coio, struct sockaddr *addr, { ev_loop *loop = loop(); evio_socket(coio, addr->sa_family, SOCK_STREAM, 0); - auto coio_guard = make_scoped_guard([=]{ evio_close(loop, coio); }); - if (sio_connect(coio->fd, addr, len) == 0) { - coio_guard.is_active = false; + if (sio_connect(coio->fd, addr, len) == 0) return 0; - } + auto coio_guard = make_scoped_guard([=]{ evio_close(loop, coio); }); if (errno != EINPROGRESS) diag_raise(); /* @@ -252,12 +250,16 @@ coio_accept(struct ev_io *coio, struct sockaddr *addr, while (true) { /* Assume that there are waiting clients * available */ - int fd = sio_accept(coio->fd, addr, &addrlen); + bool is_error_fatal; + int fd = sio_accept(coio->fd, addr, &addrlen, + &is_error_fatal); if (fd >= 0) { evio_setsockopt_client(fd, addr->sa_family, SOCK_STREAM); return fd; } + if (is_error_fatal) + diag_raise(); /* The socket is not ready, yield */ if (! ev_is_active(coio)) { ev_io_set(coio, coio->fd, EV_READ); @@ -303,7 +305,9 @@ coio_read_ahead_timeout(struct ev_io *coio, void *buf, size_t sz, * the user called read(), some data must * be expected. */ - ssize_t nrd = sio_read(coio->fd, buf, bufsiz); + bool is_error_fatal; + ssize_t nrd = sio_read(coio->fd, buf, bufsiz, + &is_error_fatal); if (nrd > 0) { to_read -= nrd; if (to_read <= 0) @@ -313,6 +317,8 @@ coio_read_ahead_timeout(struct ev_io *coio, void *buf, size_t sz, } else if (nrd == 0) { errno = 0; return sz - to_read; + } else if (is_error_fatal) { + diag_raise(); } /* The socket is not ready, yield */ @@ -397,13 +403,17 @@ coio_write_timeout(struct ev_io *coio, const void *buf, size_t sz, * Sic: write as much data as possible, * assuming the socket is ready. */ - ssize_t nwr = sio_write(coio->fd, buf, towrite); + bool is_error_fatal; + ssize_t nwr = sio_write(coio->fd, buf, towrite, + &is_error_fatal); if (nwr > 0) { /* Go past the data just written. */ if (nwr >= towrite) return sz; towrite -= nwr; buf = (char *) buf + nwr; + } else if (is_error_fatal) { + diag_raise(); } if (! ev_is_active(coio)) { ev_io_set(coio, coio->fd, EV_WRITE); @@ -433,15 +443,12 @@ coio_write_timeout(struct ev_io *coio, const void *buf, size_t sz, static inline ssize_t coio_flush(int fd, struct iovec *iov, ssize_t offset, int iovcnt) { - ssize_t nwr; - try { - sio_add_to_iov(iov, -offset); - nwr = sio_writev(fd, iov, iovcnt); - sio_add_to_iov(iov, offset); - } catch (SocketError *e) { - sio_add_to_iov(iov, offset); - throw; - } + sio_add_to_iov(iov, -offset); + bool is_error_fatal; + ssize_t nwr = sio_writev(fd, iov, iovcnt, &is_error_fatal); + sio_add_to_iov(iov, offset); + if (nwr < 0 && is_error_fatal) + diag_raise(); return nwr; } @@ -518,10 +525,13 @@ coio_sendto_timeout(struct ev_io *coio, const void *buf, size_t sz, int flags, * Sic: write as much data as possible, * assuming the socket is ready. */ - ssize_t nwr = sio_sendto(coio->fd, buf, sz, - flags, dest_addr, addrlen); + bool is_error_fatal; + ssize_t nwr = sio_sendto(coio->fd, buf, sz, flags, dest_addr, + addrlen, &is_error_fatal); if (nwr > 0) return nwr; + if (is_error_fatal) + diag_raise(); if (! ev_is_active(coio)) { ev_io_set(coio, coio->fd, EV_WRITE); ev_io_start(loop(), coio); @@ -561,11 +571,13 @@ coio_recvfrom_timeout(struct ev_io *coio, void *buf, size_t sz, int flags, * Read as much data as possible, * assuming the socket is ready. */ - ssize_t nrd = sio_recvfrom(coio->fd, buf, sz, flags, - src_addr, &addrlen); + bool is_error_fatal; + ssize_t nrd = sio_recvfrom(coio->fd, buf, sz, flags, src_addr, + &addrlen, &is_error_fatal); if (nrd >= 0) return nrd; - + if (is_error_fatal) + diag_raise(); if (! ev_is_active(coio)) { ev_io_set(coio, coio->fd, EV_READ); ev_io_start(loop(), coio); diff --git a/src/evio.cc b/src/evio.cc index a8475e0d1..401e71155 100644 --- a/src/evio.cc +++ b/src/evio.cc @@ -181,11 +181,15 @@ evio_service_accept_cb(ev_loop * /* loop */, ev_io *watcher, try { struct sockaddr_storage addr; socklen_t addrlen = sizeof(addr); + bool is_error_fatal; fd = sio_accept(service->ev.fd, - (struct sockaddr *)&addr, &addrlen); - - if (fd < 0) /* EAGAIN, EWOULDLOCK, EINTR */ + (struct sockaddr *)&addr, &addrlen, + &is_error_fatal); + if (fd < 0) { + if (is_error_fatal) + diag_raise(); return; + } /* set common client socket options */ evio_setsockopt_client(fd, service->addr.sa_family, SOCK_STREAM); /* @@ -294,7 +298,8 @@ evio_service_listen(struct evio_service *service) sio_strfaddr(&service->addr, service->addr_len)); int fd = service->ev.fd; - sio_listen(fd); + if (sio_listen(fd) < 0) + diag_raise(); ev_io_start(service->loop, &service->ev); } diff --git a/src/sio.cc b/src/sio.cc index b2f05e5c8..09f413c2d 100644 --- a/src/sio.cc +++ b/src/sio.cc @@ -206,23 +206,27 @@ sio_listen(int fd) { int rc = listen(fd, sio_listen_backlog()); if (rc < 0) - tnt_raise(SocketError, sio_socketname(fd), "listen"); + diag_set(SocketError, sio_socketname(fd), "listen"); return rc; } int -sio_accept(int fd, struct sockaddr *addr, socklen_t *addrlen) +sio_accept(int fd, struct sockaddr *addr, socklen_t *addrlen, + bool *is_error_fatal) { /* Accept a connection. */ int newfd = accept(fd, addr, addrlen); - if (newfd < 0 && errno != EAGAIN && errno != EWOULDBLOCK && - errno != EINTR) - tnt_raise(SocketError, sio_socketname(fd), "accept"); + if (newfd < 0) { + *is_error_fatal = errno != EAGAIN && errno != EWOULDBLOCK && + errno != EINTR; + if (*is_error_fatal) + diag_set(SocketError, sio_socketname(fd), "accept"); + } return newfd; } ssize_t -sio_read(int fd, void *buf, size_t count) +sio_read(int fd, void *buf, size_t count, bool *is_error_fatal) { ssize_t n = read(fd, buf, count); if (n >= 0) @@ -232,6 +236,7 @@ sio_read(int fd, void *buf, size_t count) switch (errno) { case EAGAIN: case EINTR: + *is_error_fatal = false; break; /* * Happens typically when the client closes socket on @@ -241,55 +246,78 @@ sio_read(int fd, void *buf, size_t count) case ECONNRESET: errno = 0; n = 0; + *is_error_fatal = false; break; default: - tnt_raise(SocketError, sio_socketname(fd), "read(%zd)", count); + diag_set(SocketError, sio_socketname(fd), "read(%zd)", count); + *is_error_fatal = true; } return n; } ssize_t -sio_write(int fd, const void *buf, size_t count) +sio_write(int fd, const void *buf, size_t count, bool *is_error_fatal) { ssize_t n = write(fd, buf, count); - if (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) - tnt_raise(SocketError, sio_socketname(fd), "write(%zd)", count); + if (n < 0) { + *is_error_fatal = errno != EAGAIN && errno != EWOULDBLOCK && + errno != EINTR; + if (*is_error_fatal) { + diag_set(SocketError, sio_socketname(fd), "write(%zd)", + count); + } + } return n; } ssize_t -sio_writev(int fd, const struct iovec *iov, int iovcnt) +sio_writev(int fd, const struct iovec *iov, int iovcnt, bool *is_error_fatal) { int cnt = iovcnt < IOV_MAX ? iovcnt : IOV_MAX; ssize_t n = writev(fd, iov, cnt); - if (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK && - errno != EINTR) { - tnt_raise(SocketError, sio_socketname(fd), - "writev(%d)", iovcnt); + if (n < 0) { + *is_error_fatal = errno != EAGAIN && errno != EWOULDBLOCK && + errno != EINTR; + if (*is_error_fatal) { + diag_set(SocketError, sio_socketname(fd), "writev(%d)", + iovcnt); + } } return n; } ssize_t sio_sendto(int fd, const void *buf, size_t len, int flags, - const struct sockaddr *dest_addr, socklen_t addrlen) + const struct sockaddr *dest_addr, socklen_t addrlen, + bool *is_error_fatal) { ssize_t n = sendto(fd, buf, len, flags, (struct sockaddr*)dest_addr, addrlen); - if (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) - tnt_raise(SocketError, sio_socketname(fd), "sendto(%zd)", len); + if (n < 0) { + *is_error_fatal = errno != EAGAIN && errno != EWOULDBLOCK && + errno != EINTR; + if (*is_error_fatal) { + diag_set(SocketError, sio_socketname(fd), "sendto(%zd)", + len); + } + } return n; } ssize_t sio_recvfrom(int fd, void *buf, size_t len, int flags, - struct sockaddr *src_addr, socklen_t *addrlen) + struct sockaddr *src_addr, socklen_t *addrlen, + bool *is_error_fatal) { ssize_t n = recvfrom(fd, buf, len, flags, (struct sockaddr*)src_addr, addrlen); - if (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) { - tnt_raise(SocketError, sio_socketname(fd), "recvfrom(%zd)", - len); + if (n < 0) { + *is_error_fatal = errno != EAGAIN && errno != EWOULDBLOCK && + errno != EINTR; + if (*is_error_fatal) { + diag_set(SocketError, sio_socketname(fd), + "recvfrom(%zd)", len); + } } return n; } diff --git a/src/sio.h b/src/sio.h index d937cfd3d..ab0a243cd 100644 --- a/src/sio.h +++ b/src/sio.h @@ -151,57 +151,110 @@ sio_bind(int fd, struct sockaddr *addr, socklen_t addrlen); /** * Mark a socket as accepting connections. A wrapper for listen(), - * but throws exception on error. + * but sets diagnostics on error. */ int sio_listen(int fd); /** * Accept a client connection on a server socket. A wrapper for - * accept(), but throws exception on error except EAGAIN, EINTR, + * accept(), but sets diagnostics on error except EAGAIN, EINTR, * EWOULDBLOCK. + * @param fd Server socket. + * @param[out] addr Accepted client's address. + * @param[in, out] addrlen Size of @a addr. + * @param[out] is_error_fatal Set to true, if an error occured and + * it was not EAGAIN, EINTR and EWOULDBLOCK. + * + * @retval Client socket, or -1 on error. */ int -sio_accept(int fd, struct sockaddr *addr, socklen_t *addrlen); +sio_accept(int fd, struct sockaddr *addr, socklen_t *addrlen, + bool *is_error_fatal); /** * Read up to @a count bytes from a socket. A wrapper for read(), - * but throws exception on error except EWOULDBLOCK, EINTR, + * but sets diagnostics on error except EWOULDBLOCK, EINTR, * EAGAIN, ECONNRESET. + * @param fd Socket. + * @param buf Buffer to read into. + * @param count How many bytes to read. + * @param[out] is_error_fatal Set to true, if an error occured and + * it was not EAGAIN, EINTR, ECONNRESET and + * EWOULDBLOCK. + * + * @retval How many bytes are read, or -1 on error. */ ssize_t -sio_read(int fd, void *buf, size_t count); +sio_read(int fd, void *buf, size_t count, bool *is_error_fatal); /** * Write up to @a count bytes to a socket. A wrapper for write(), - * but throws exception on error except EAGAIN, EINTR, + * but sets diagnostics on error except EAGAIN, EINTR, * EWOULDBLOCK. + * @param fd Socket. + * @param buf Buffer to write. + * @param count How many bytes to write. + * @param[out] is_error_fatal Set to true, if an error occured and + * it was not EAGAIN, EINTR and EWOULDBLOCK. + * + * @retval How many bytes are written, or -1 on error. */ ssize_t -sio_write(int fd, const void *buf, size_t count); +sio_write(int fd, const void *buf, size_t count, bool *is_error_fatal); /** * Write @a iov vector to a socket. A wrapper for writev(), but - * throws exception on error except EAGAIN, EINTR, EWOULDBLOCK. + * sets diagnostics on error except EAGAIN, EINTR, EWOULDBLOCK. + * @param fd Socket. + * @param iov Vector to write. + * @param iovcnt Size of @a iov. + * @param[out] is_error_fatal Set to true, if an error occured and + * it was not EAGAIN, EINTR and EWOULDBLOCK. + * + * @retval How many bytes are written, or -1 on error. */ ssize_t -sio_writev(int fd, const struct iovec *iov, int iovcnt); +sio_writev(int fd, const struct iovec *iov, int iovcnt, + bool *is_error_fatal); /** - * Send a message on a socket. A wrapper for sendto(), but throws - * exception on error except EAGAIN, EINTR, EWOULDBLOCK. + * Send a message on a socket. A wrapper for sendto(), but sets + * diagnostics on error except EAGAIN, EINTR, EWOULDBLOCK. + * @param fd Socket to send to. + * @param buf Buffer to send. + * @param len Size of @a buf. + * @param flags sendto() flags. + * @param dest_addr Destination address. + * @param addrlen Size of @a dest_addr. + * @param[out] is_error_fatal Set to true, if an error occured and + * it was not EAGAIN, EINTR and EWOULDBLOCK. + * + * @param How many bytes are sent, or -1 on error. */ ssize_t sio_sendto(int fd, const void *buf, size_t len, int flags, - const struct sockaddr *dest_addr, socklen_t addrlen); + const struct sockaddr *dest_addr, socklen_t addrlen, + bool *is_error_fatal); /** * Receive a message on a socket. A wrapper for recvfrom(), but - * throws exception on error except EAGAIN, EINTR, EWOULDBLOCK. + * sets diagnostics on error except EAGAIN, EINTR, EWOULDBLOCK. + * @param fd Socket to receive from. + * @param buf Buffer to save message. + * @param len Size of @a buf. + * @param flags recvfrom() flags. + * @param[out] src_addr Source address. + * @param[in, out] addrlen Size of @a src_addr. + * @param[out] is_error_fatal Set to true, if an error occured and + * it was not EAGAIN, EINTR and EWOULDBLOCK. + * + * @param How many bytes are received, or -1 on error. */ ssize_t sio_recvfrom(int fd, void *buf, size_t len, int flags, - struct sockaddr *src_addr, socklen_t *addrlen); + struct sockaddr *src_addr, socklen_t *addrlen, + bool *is_error_fatal); #endif /* defined(__cplusplus) */ -- 2.17.2 (Apple Git-113)