[PATCH 03/11] sio: remove exceptions

Vladislav Shpilevoy v.shpilevoy at tarantool.org
Fri Nov 30 18:39:35 MSK 2018


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)




More information about the Tarantool-patches mailing list