MCPcopy Create free account
hub / github.com/DeusData/codebase-memory-mcp / cbm_mcp_server_run

Function cbm_mcp_server_run

src/mcp/mcp.c:6299–6376  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

6297/* ── Event loop ───────────────────────────────────────────────── */
6298
6299int cbm_mcp_server_run(cbm_mcp_server_t *srv, FILE *in, FILE *out) {
6300 char *line = NULL;
6301 size_t cap = 0;
6302 int fd = cbm_fileno(in);
6303
6304 for (;;) {
6305 /* Poll with idle timeout so we can evict unused stores between requests.
6306 *
6307 * IMPORTANT: poll() operates on the raw fd, but getline() reads from a
6308 * buffered FILE*. When a client sends multiple messages in rapid
6309 * succession, the first getline() call may drain ALL kernel data into
6310 * libc's internal FILE* buffer. Subsequent poll() calls then see an
6311 * empty kernel fd and block for STORE_IDLE_TIMEOUT_S seconds even
6312 * though the next messages are already in the FILE* buffer.
6313 *
6314 * Fix (Unix): use a three-phase approach —
6315 * Phase 1: non-blocking poll (timeout=0) to check the kernel fd.
6316 * Phase 2: if Phase 1 returns 0, peek the FILE* buffer via fgetc/
6317 * ungetc to detect data buffered by a prior getline() call.
6318 * The fd is temporarily set O_NONBLOCK so fgetc() returns
6319 * immediately (EAGAIN → EOF + ferror) instead of blocking
6320 * when the FILE* buffer is empty, which would otherwise
6321 * bypass the Phase 3 idle eviction timeout.
6322 * Phase 3: only if both phases confirm no data, do blocking poll. */
6323#ifdef _WIN32
6324 /* Windows: WaitForSingleObject on stdin handle */
6325 HANDLE hStdin = (HANDLE)_get_osfhandle(fd);
6326 DWORD wr = WaitForSingleObject(hStdin, STORE_IDLE_TIMEOUT_S * MCP_TIMEOUT_MS);
6327 if (wr == WAIT_FAILED) {
6328 break;
6329 }
6330 if (wr == WAIT_TIMEOUT) {
6331 cbm_mcp_server_evict_idle(srv, STORE_IDLE_TIMEOUT_S);
6332 continue;
6333 }
6334#else
6335 int pr = poll_for_input_unix(srv, fd, in);
6336 if (pr < 0) {
6337 break;
6338 }
6339 if (pr == 0) {
6340 continue; /* timeout — idle stores evicted */
6341 }
6342#endif
6343
6344 if (cbm_getline(&line, &cap, in) <= 0) {
6345 break;
6346 }
6347
6348 /* Trim trailing newline/CR */
6349 size_t len = strlen(line);
6350 while (len > 0 && (line[len - SKIP_ONE] == '\n' || line[len - SKIP_ONE] == '\r')) {
6351 line[--len] = '\0';
6352 }
6353 if (len == 0) {
6354 continue;
6355 }
6356

Callers 2

mainFunction · 0.85
test_mcp.cFile · 0.85

Calls 5

poll_for_input_unixFunction · 0.85
cbm_getlineFunction · 0.85
cbm_mcp_server_handleFunction · 0.85

Tested by

no test coverage detected