Skip to content

Commit 96eb851

Browse files
committed
Added support for systemd socket activation.
1 parent a754ef2 commit 96eb851

File tree

6 files changed

+114
-23
lines changed

6 files changed

+114
-23
lines changed

CMakeLists.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,9 @@ option(LLAMA_BUILD_EXAMPLES "llama: build examples" ${LLAMA_STANDALONE})
8484
option(LLAMA_BUILD_SERVER "llama: build server example" ${LLAMA_STANDALONE})
8585

8686
# 3rd party libs
87-
option(LLAMA_CURL "llama: use libcurl to download model from an URL" ON)
88-
option(LLAMA_LLGUIDANCE "llama-common: include LLGuidance library for structured output in common utils" OFF)
87+
option(LLAMA_CURL "llama: use libcurl to download model from an URL" ON)
88+
option(LLAMA_LLGUIDANCE "llama-common: include LLGuidance library for structured output in common utils" OFF)
89+
option(LLAMA_SERVER_SYSTEMD "llama-server: support systemd socket activation and readiness notification (linux only)" OFF)
8990

9091
# Required for relocatable CMake package
9192
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/build-info.cmake)

common/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ if (LLAMA_LLGUIDANCE)
133133
set(LLAMA_COMMON_EXTRA_LIBS ${LLAMA_COMMON_EXTRA_LIBS} llguidance ${LLGUIDANCE_PLATFORM_LIBS})
134134
endif ()
135135

136+
if (UNIX AND NOT APPLE AND LLAMA_SERVER_SYSTEMD)
137+
target_compile_definitions(${TARGET} PRIVATE LLAMA_CPP_SYSTEMD_SUPPORT)
138+
endif()
139+
136140
target_include_directories(${TARGET} PUBLIC . ../vendor)
137141
target_compile_features (${TARGET} PUBLIC cxx_std_17)
138142
target_link_libraries (${TARGET} PRIVATE ${LLAMA_COMMON_EXTRA_LIBS} PUBLIC llama Threads::Threads)

common/arg.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2686,6 +2686,14 @@ common_params_context common_params_parser_init(common_params & params,
26862686
[](common_params & params, int value) { params.port = value; })
26872687
.set_examples({ LLAMA_EXAMPLE_SERVER })
26882688
.set_env("LLAMA_ARG_PORT"));
2689+
#ifdef LLAMA_CPP_SYSTEMD_SUPPORT
2690+
add_opt(common_arg({ "--systemd" },
2691+
string_format("use systemd socket and readiness notification (default: %s)",
2692+
params.use_systemd ? "enabled" : "disabled"),
2693+
[](common_params & params) { params.use_systemd = true; })
2694+
.set_examples({ LLAMA_EXAMPLE_SERVER })
2695+
.set_env("LLAMA_ARG_SYSTEMD"));
2696+
#endif // LLAMA_CPP_SYSTEMD_SUPPORT
26892697
add_opt(common_arg({ "--path" }, "PATH",
26902698
string_format("path to serve static files from (default: %s)", params.public_path.c_str()),
26912699
[](common_params & params, const std::string & value) { params.public_path = value; })

common/common.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,10 @@ struct common_params {
451451
int reasoning_budget = -1;
452452
bool prefill_assistant = true; // if true, any trailing assistant message will be prefilled into the response
453453

454+
#ifdef LLAMA_CPP_SYSTEMD_SUPPORT
455+
bool use_systemd = false; // use systemd socket and readiness notification
456+
#endif
457+
454458
std::vector<std::string> api_keys;
455459

456460
std::string ssl_file_key = ""; // NOLINT

tools/server/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,12 @@ if (WIN32)
4747
TARGET_LINK_LIBRARIES(${TARGET} PRIVATE ws2_32)
4848
endif()
4949

50+
if (UNIX AND NOT APPLE AND LLAMA_SERVER_SYSTEMD)
51+
message(STATUS "LLAMA_SERVER_SYSTEMD is ON, enabling systemd support")
52+
find_package(PkgConfig REQUIRED)
53+
pkg_check_modules(SYSTEMD REQUIRED libsystemd)
54+
target_link_libraries(${TARGET} PRIVATE ${SYSTEMD_LIBRARIES})
55+
target_compile_definitions(${TARGET} PRIVATE LLAMA_CPP_SYSTEMD_SUPPORT)
56+
endif()
57+
5058
target_compile_features(${TARGET} PRIVATE cxx_std_17)

tools/server/server.cpp

Lines changed: 87 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@
3131
#include <unordered_map>
3232
#include <unordered_set>
3333

34+
#ifdef LLAMA_CPP_SYSTEMD_SUPPORT
35+
# include <sys/socket.h>
36+
# include <sys/stat.h>
37+
# include <systemd/sd-daemon.h>
38+
#endif // LLAMA_CPP_SYSTEMD_SUPPORT
39+
3440
using json = nlohmann::ordered_json;
3541

3642
constexpr int HTTP_POLLING_SECONDS = 1;
@@ -4110,6 +4116,38 @@ inline void signal_handler(int signal) {
41104116
shutdown_handler(signal);
41114117
}
41124118

4119+
#ifdef LLAMA_CPP_SYSTEMD_SUPPORT
4120+
// Subclass of httplib::Server that adds systemd socket activation support on systems
4121+
// where that's available.
4122+
class SystemdServer : public httplib::Server {
4123+
public:
4124+
bool setup_sd_socket() {
4125+
int n = sd_listen_fds(0);
4126+
if (n != 1) {
4127+
LOG_ERR("%s: sd_listen_fds() returned %d\n", __func__, n);
4128+
return false;
4129+
}
4130+
4131+
int fd = SD_LISTEN_FDS_START;
4132+
struct stat statbuf;
4133+
if (fstat(fd, &statbuf) == -1 || !S_ISSOCK(statbuf.st_mode)) {
4134+
LOG_ERR("%s: fstat() failed or fd is not a socket\n", __func__);
4135+
return false;
4136+
}
4137+
4138+
LOG_INF("%s: using systemd socket fd %d\n", __func__, fd);
4139+
svr_sock_ = fd;
4140+
return true;
4141+
}
4142+
};
4143+
#endif // LLAMA_CPP_SYSTEMD_SUPPORT
4144+
4145+
#ifdef LLAMA_CPP_SYSTEMD_SUPPORT
4146+
# define NEW_SERVER (new SystemdServer())
4147+
#else
4148+
# define NEW_SERVER (new httplib::Server())
4149+
#endif // LLAMA_CPP_SYSTEMD_SUPPORT
4150+
41134151
int main(int argc, char ** argv) {
41144152
// own arguments required by this example
41154153
common_params params;
@@ -4139,14 +4177,14 @@ int main(int argc, char ** argv) {
41394177
svr.reset(new httplib::SSLServer(params.ssl_file_cert.c_str(), params.ssl_file_key.c_str()));
41404178
} else {
41414179
LOG_INF("Running without SSL\n");
4142-
svr.reset(new httplib::Server());
4180+
svr.reset(NEW_SERVER);
41434181
}
41444182
#else
41454183
if (params.ssl_file_key != "" && params.ssl_file_cert != "") {
41464184
LOG_ERR("Server is built without SSL support\n");
41474185
return 1;
41484186
}
4149-
svr.reset(new httplib::Server());
4187+
svr.reset(NEW_SERVER);
41504188
#endif
41514189

41524190
std::atomic<server_state> state{ SERVER_STATE_LOADING_MODEL };
@@ -5342,23 +5380,37 @@ int main(int argc, char ** argv) {
53425380

53435381
bool was_bound = false;
53445382
bool is_sock = false;
5345-
if (string_ends_with(std::string(params.hostname), ".sock")) {
5346-
is_sock = true;
5347-
LOG_INF("%s: setting address family to AF_UNIX\n", __func__);
5348-
svr->set_address_family(AF_UNIX);
5349-
// bind_to_port requires a second arg, any value other than 0 should
5350-
// simply get ignored
5351-
was_bound = svr->bind_to_port(params.hostname, 8080);
5352-
} else {
5353-
LOG_INF("%s: binding port with default address family\n", __func__);
5354-
// bind HTTP listen port
5355-
if (params.port == 0) {
5356-
int bound_port = svr->bind_to_any_port(params.hostname);
5357-
if ((was_bound = (bound_port >= 0))) {
5358-
params.port = bound_port;
5359-
}
5383+
5384+
#ifdef LLAMA_CPP_SYSTEMD_SUPPORT
5385+
bool using_sd_socket = false;
5386+
if (params.use_systemd) {
5387+
was_bound = static_cast<SystemdServer *>(svr.get())->setup_sd_socket();
5388+
using_sd_socket = was_bound;
5389+
if (!was_bound) {
5390+
LOG_INF("%s: couldn't set up systemd socket; falling back to opening host:port socket\n", __func__);
5391+
}
5392+
}
5393+
#endif // LLAMA_CPP_SYSTEMD_SUPPORT
5394+
5395+
if (!was_bound) {
5396+
if (string_ends_with(std::string(params.hostname), ".sock")) {
5397+
is_sock = true;
5398+
LOG_INF("%s: setting address family to AF_UNIX\n", __func__);
5399+
svr->set_address_family(AF_UNIX);
5400+
// bind_to_port requires a second arg, any value other than 0 should
5401+
// simply get ignored
5402+
was_bound = svr->bind_to_port(params.hostname, 8080);
53605403
} else {
5361-
was_bound = svr->bind_to_port(params.hostname, params.port);
5404+
LOG_INF("%s: binding port with default address family\n", __func__);
5405+
// bind HTTP listen port
5406+
if (params.port == 0) {
5407+
int bound_port = svr->bind_to_any_port(params.hostname);
5408+
if ((was_bound = (bound_port >= 0))) {
5409+
params.port = bound_port;
5410+
}
5411+
} else {
5412+
was_bound = svr->bind_to_port(params.hostname, params.port);
5413+
}
53625414
}
53635415
}
53645416

@@ -5389,6 +5441,12 @@ int main(int argc, char ** argv) {
53895441
ctx_server.init();
53905442
state.store(SERVER_STATE_READY);
53915443

5444+
#ifdef LLAMA_CPP_SYSTEMD_SUPPORT
5445+
if (params.use_systemd) {
5446+
sd_notify(0, "READY=1");
5447+
}
5448+
#endif
5449+
53925450
LOG_INF("%s: model loaded\n", __func__);
53935451

53945452
// print sample chat example to make it clear which template is used
@@ -5422,9 +5480,17 @@ int main(int argc, char ** argv) {
54225480
SetConsoleCtrlHandler(reinterpret_cast<PHANDLER_ROUTINE>(console_ctrl_handler), true);
54235481
#endif
54245482

5425-
LOG_INF("%s: server is listening on %s - starting the main loop\n", __func__,
5426-
is_sock ? string_format("unix://%s", params.hostname.c_str()).c_str() :
5427-
string_format("http://%s:%d", params.hostname.c_str(), params.port).c_str());
5483+
#ifdef LLAMA_CPP_SYSTEMD_SUPPORT
5484+
if (using_sd_socket) {
5485+
LOG_INF("%s: server is listening on systemd socket - starting the main loop\n", __func__);
5486+
} else {
5487+
#endif // LLAMA_CPP_SYSTEMD_SUPPORT
5488+
LOG_INF("%s: server is listening on %s - starting the main loop\n", __func__,
5489+
is_sock ? string_format("unix://%s", params.hostname.c_str()).c_str() :
5490+
string_format("http://%s:%d", params.hostname.c_str(), params.port).c_str());
5491+
#ifdef LLAMA_CPP_SYSTEMD_SUPPORT
5492+
}
5493+
#endif // LLAMA_CPP_SYSTEMD_SUPPORT
54285494

54295495
// this call blocks the main thread until queue_tasks.terminate() is called
54305496
ctx_server.queue_tasks.start_loop();

0 commit comments

Comments
 (0)