Skip to content

Commit 200399f

Browse files
committed
Handle graceful server termination
1 parent c48e2a5 commit 200399f

5 files changed

Lines changed: 90 additions & 4 deletions

File tree

app/server/http.cpp

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <array>
77
#include <cctype>
88
#include <cstdint>
9+
#include <cerrno>
910
#include <iostream>
1011
#include <limits>
1112
#include <optional>
@@ -23,6 +24,7 @@ constexpr SocketHandle kInvalidSocket = INVALID_SOCKET;
2324
#else
2425
#include <arpa/inet.h>
2526
#include <netinet/in.h>
27+
#include <sys/select.h>
2628
#include <sys/socket.h>
2729
#include <unistd.h>
2830
using SocketHandle = int;
@@ -273,6 +275,33 @@ void handle_client(SocketHandle client, IHttpHandler & handler) {
273275
}
274276
}
275277

278+
bool wait_for_client(SocketHandle socket, int timeout_ms) {
279+
fd_set read_set;
280+
FD_ZERO(&read_set);
281+
FD_SET(socket, &read_set);
282+
283+
timeval timeout{};
284+
timeout.tv_sec = timeout_ms / 1000;
285+
timeout.tv_usec = (timeout_ms % 1000) * 1000;
286+
287+
#ifdef _WIN32
288+
const int ready = select(0, &read_set, nullptr, nullptr, &timeout);
289+
#else
290+
const int ready = select(socket + 1, &read_set, nullptr, nullptr, &timeout);
291+
#endif
292+
if (ready < 0) {
293+
#ifdef _WIN32
294+
if (WSAGetLastError() == WSAEINTR) {
295+
#else
296+
if (errno == EINTR) {
297+
#endif
298+
return false;
299+
}
300+
throw std::runtime_error("server select failed");
301+
}
302+
return ready > 0 && FD_ISSET(socket, &read_set);
303+
}
304+
276305
} // namespace
277306

278307
HttpResponse json_response(std::string body, int status) {
@@ -285,11 +314,14 @@ HttpResponse error_response(int status, const std::string & message, const std::
285314
return json_response(body, status);
286315
}
287316

288-
void serve_http(const std::string & host, int port, IHttpHandler & handler) {
317+
void serve_http(const std::string & host, int port, IHttpHandler & handler, ShutdownRequested shutdown_requested) {
289318
SocketRuntime sockets;
290319
auto listen_socket = bind_listen_socket(host, port);
291320
std::cout << "audiocpp_server listening on http://" << host << ":" << port << "\n";
292-
while (true) {
321+
while (!shutdown_requested()) {
322+
if (!wait_for_client(listen_socket.get(), 250)) {
323+
continue;
324+
}
293325
sockaddr_in client_addr{};
294326
#ifdef _WIN32
295327
int client_len = sizeof(client_addr);
@@ -301,10 +333,20 @@ void serve_http(const std::string & host, int port, IHttpHandler & handler) {
301333
reinterpret_cast<sockaddr *>(&client_addr),
302334
&client_len);
303335
if (client == kInvalidSocket) {
336+
#ifdef _WIN32
337+
const int error = WSAGetLastError();
338+
const bool transient = error == WSAEINTR || error == WSAEWOULDBLOCK;
339+
#else
340+
const bool transient = errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK;
341+
#endif
342+
if (shutdown_requested() || transient) {
343+
continue;
344+
}
304345
throw std::runtime_error("accept failed");
305346
}
306347
std::thread(handle_client, client, std::ref(handler)).detach();
307348
}
349+
std::cout << "audiocpp_server stopped\n";
308350
}
309351

310352
} // namespace minitts::server

app/server/http.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@ class IHttpHandler {
2626
virtual HttpResponse handle(const HttpRequest & request) = 0;
2727
};
2828

29+
using ShutdownRequested = bool (*)();
30+
2931
HttpResponse json_response(std::string body, int status = 200);
3032
HttpResponse error_response(int status, const std::string & message, const std::string & type);
31-
void serve_http(const std::string & host, int port, IHttpHandler & handler);
33+
void serve_http(const std::string & host, int port, IHttpHandler & handler, ShutdownRequested shutdown_requested);
3234

3335
} // namespace minitts::server

app/server/main.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include "engine/framework/debug/trace.h"
66

7+
#include <csignal>
78
#include <filesystem>
89
#include <iostream>
910
#include <optional>
@@ -12,6 +13,16 @@
1213

1314
namespace {
1415

16+
volatile std::sig_atomic_t g_shutdown_requested = 0;
17+
18+
void request_shutdown(int) {
19+
g_shutdown_requested = 1;
20+
}
21+
22+
bool shutdown_requested() {
23+
return g_shutdown_requested != 0;
24+
}
25+
1526
std::optional<std::string> arg_value(int argc, char ** argv, const std::string & name) {
1627
for (int i = 1; i + 1 < argc; ++i) {
1728
if (argv[i] == name) {
@@ -63,6 +74,8 @@ int main(int argc, char ** argv) {
6374
has_arg(argc, argv, "--log") || log_file.has_value(),
6475
log_file,
6576
});
77+
std::signal(SIGINT, request_shutdown);
78+
std::signal(SIGTERM, request_shutdown);
6679

6780
auto config = minitts::server::load_server_config(*config_path);
6881
if (const auto host = arg_value(argc, argv, "--host")) {
@@ -85,7 +98,7 @@ int main(int argc, char ** argv) {
8598
}
8699

87100
minitts::server::ServerState state(config, std::filesystem::current_path());
88-
minitts::server::serve_http(config.host, config.port, state);
101+
minitts::server::serve_http(config.host, config.port, state, shutdown_requested);
89102
return 0;
90103
} catch (const std::exception & ex) {
91104
std::cerr << "audiocpp_server failed: " << ex.what() << "\n";

scripts/build_linux.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ WITH_TESTS="OFF"
1111
WITH_EXAMPLES="OFF"
1212
WITH_WARMBENCH="OFF"
1313
NATIVE_CPU="ON"
14+
LLAMAFILE="ON"
1415
TARGETS=()
1516
JOBS=""
1617

@@ -79,6 +80,21 @@ while [[ $# -gt 0 ]]; do
7980
esac
8081
shift 2
8182
;;
83+
--llamafile)
84+
case "$2" in
85+
ON|on|On|1|true|TRUE|yes|YES)
86+
LLAMAFILE="ON"
87+
;;
88+
OFF|off|Off|0|false|FALSE|no|NO)
89+
LLAMAFILE="OFF"
90+
;;
91+
*)
92+
echo "--llamafile must be ON or OFF" >&2
93+
exit 1
94+
;;
95+
esac
96+
shift 2
97+
;;
8298
--target)
8399
TARGETS+=("$2")
84100
shift 2
@@ -178,6 +194,7 @@ echo "Using build dir: $BUILD_DIR"
178194
echo "Including CUDA backend: $ENGINE_ENABLE_CUDA"
179195
echo "Including Vulkan backend: $ENGINE_ENABLE_VULKAN"
180196
echo "Native CPU optimization: $NATIVE_CPU"
197+
echo "llamafile SGEMM: $LLAMAFILE"
181198
echo "Building examples: $WITH_EXAMPLES"
182199
echo "Building tests: $WITH_TESTS"
183200
echo "Building warmbench: $WITH_WARMBENCH"
@@ -190,6 +207,7 @@ echo "Building warmbench: $WITH_WARMBENCH"
190207
-DENGINE_ENABLE_CUDA="$ENGINE_ENABLE_CUDA" \
191208
-DENGINE_ENABLE_VULKAN="$ENGINE_ENABLE_VULKAN" \
192209
-DENGINE_ENABLE_NATIVE_CPU="$NATIVE_CPU" \
210+
-DENGINE_ENABLE_LLAMAFILE="$LLAMAFILE" \
193211
-DENGINE_BUILD_EXAMPLES="$WITH_EXAMPLES" \
194212
-DENGINE_BUILD_TESTS="$WITH_TESTS" \
195213
-DENGINE_BUILD_WARMBENCH="$WITH_WARMBENCH"

scripts/build_windows.ps1

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ param(
88
[string]$CudaArchitectures = "auto",
99
[ValidateSet("ON", "OFF")]
1010
[string]$NativeCpu = $null,
11+
[ValidateSet("ON", "OFF")]
12+
[string]$Llamafile = $null,
1113
[string]$VsInstall = ""
1214
)
1315

@@ -261,6 +263,7 @@ function Get-PresetSettings {
261263
BuildType = "Release"
262264
BuildTests = "OFF"
263265
Native = "ON"
266+
Llamafile = "ON"
264267
EnableCuda = "OFF"
265268
EnableCudaGraphs = "OFF"
266269
CFlagsDebug = ""
@@ -272,6 +275,7 @@ function Get-PresetSettings {
272275
BuildType = "Debug"
273276
BuildTests = "ON"
274277
Native = "ON"
278+
Llamafile = "ON"
275279
EnableCuda = "ON"
276280
EnableCudaGraphs = "ON"
277281
CFlagsDebug = "/O2 /Zi"
@@ -283,6 +287,7 @@ function Get-PresetSettings {
283287
BuildType = "Release"
284288
BuildTests = "OFF"
285289
Native = "ON"
290+
Llamafile = "ON"
286291
EnableCuda = "ON"
287292
EnableCudaGraphs = "ON"
288293
CFlagsDebug = ""
@@ -294,6 +299,7 @@ function Get-PresetSettings {
294299
BuildType = "Debug"
295300
BuildTests = "ON"
296301
Native = "ON"
302+
Llamafile = "ON"
297303
EnableCuda = "ON"
298304
EnableCudaGraphs = "ON"
299305
CFlagsDebug = "/O2 /Zi"
@@ -310,6 +316,9 @@ $settings = Get-PresetSettings $Preset
310316
if ($null -ne $NativeCpu) {
311317
$settings.Native = $NativeCpu
312318
}
319+
if ($null -ne $Llamafile) {
320+
$settings.Llamafile = $Llamafile
321+
}
313322
$isCudaPreset = $settings.EnableCuda -eq "ON"
314323

315324
if ($isCudaPreset) {
@@ -356,6 +365,7 @@ if ($arch -ne "") {
356365
Write-Host "CUDA architectures: $arch"
357366
}
358367
Write-Host "Native CPU optimization: $($settings.Native)"
368+
Write-Host "llamafile SGEMM: $($settings.Llamafile)"
359369

360370
if ($Clean) {
361371
$buildDirForClean = Join-Path (Join-Path (Split-Path $PSScriptRoot -Parent) "build") $Preset
@@ -387,6 +397,7 @@ $configureArgs = @(
387397
"-DENGINE_ENABLE_METAL=OFF",
388398
"-DGGML_OPENMP=ON",
389399
"-DENGINE_ENABLE_NATIVE_CPU=$($settings.Native)",
400+
"-DENGINE_ENABLE_LLAMAFILE=$($settings.Llamafile)",
390401
"-DENGINE_BUILD_TESTS=$($settings.BuildTests)"
391402
)
392403
if ($settings.CFlagsDebug -ne "") {

0 commit comments

Comments
 (0)