diff --git a/apps/EchoServer.cpp b/apps/EchoServer.cpp
index 683b92653ea4e16b06111ad9761bae0f6dce49b8..e814b4a522cf4c7a25f6cfca746114f534f70542 100644
--- a/apps/EchoServer.cpp
+++ b/apps/EchoServer.cpp
@@ -3,6 +3,7 @@
 #include <sys/socket.h>
 #include <sys/types.h>
 
+#include <atomic>
 #include <cerrno>
 #include <chrono>
 #include <cstdlib>
@@ -25,6 +26,8 @@ const std::string PORT = "12345";
 
 unsigned int computations_us = 0;
 
+std::atomic<bool> quit = false;
+
 auto main(int argc, char* argv[]) -> int {
 	std::string host = HOST;
 	std::string port = PORT;
@@ -48,21 +51,20 @@ auto main(int argc, char* argv[]) -> int {
 	auto* listener = emper::io::tcp_listener(host, port, [](int socket) {
 		// NOLINTNEXTLINE(modernize-avoid-c-arrays)
 		char buf[1024];
-		for (;;) {
+		while (!quit.load(std::memory_order_consume)) {
 			ssize_t bytes_recv = emper::io::recvAndWait(socket, buf, sizeof(buf), 0);
 			if (unlikely(bytes_recv <= 0)) {
 				// socket was shutdown
 				if (bytes_recv < 0) {
 					LOGE("server read failed:" << strerror(errno));
 				}
-
-			finish:
-				emper::io::closeAndForget(socket);
-				return;
 			}
+			break;
 
 			if (unlikely(bytes_recv == 5 && strncmp("quit\n", buf, bytes_recv) == 0)) {
-				exit(EXIT_SUCCESS);
+				quit = true;
+				Runtime::getRuntime()->initiateTermination();
+				break;
 			}
 
 			const auto start = std::chrono::steady_clock::now();
@@ -76,9 +78,11 @@ auto main(int argc, char* argv[]) -> int {
 			ssize_t bytes_send = emper::io::sendAndWait(socket, buf, bytes_recv, MSG_NOSIGNAL, true);
 			if (unlikely(bytes_recv != bytes_send)) {
 				LOGE("server send failed: " << strerror(errno));
-				goto finish;
+				break;
 			}
 		}
+
+		emper::io::closeAndForget(socket);
 	});
 
 	if (!listener) {