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

Function poll_for_input_unix

src/mcp/mcp.c:6237–6294  ·  view source on GitHub ↗

Unix 3-phase poll: non-blocking fd check, FILE* buffer peek, blocking poll. * Returns: 1 = data ready, 0 = timeout (evicted idle stores), -1 = error/EOF. */

Source from the content-addressed store, hash-verified

6235/* Unix 3-phase poll: non-blocking fd check, FILE* buffer peek, blocking poll.
6236 * Returns: 1 = data ready, 0 = timeout (evicted idle stores), -1 = error/EOF. */
6237static int poll_for_input_unix(cbm_mcp_server_t *srv, int fd, FILE *in) {
6238 struct pollfd pfd = {.fd = fd, .events = POLLIN};
6239 int pr = poll(&pfd, SKIP_ONE, 0); /* Phase 1: non-blocking */
6240
6241 if (pr < 0) {
6242 return CBM_NOT_FOUND;
6243 }
6244 if (pr > 0) {
6245 return SKIP_ONE;
6246 }
6247
6248 /* Phase 2: peek FILE* buffer */
6249 int saved_flags = fcntl(fd, F_GETFL);
6250 if (saved_flags < 0) {
6251 /* fcntl failed — fall through to a short blocking poll (see the Phase-3
6252 * note below on why the interval is bounded, not the full idle timeout) */
6253 pr = poll(&pfd, SKIP_ONE, MCP_TIMEOUT_MS);
6254 if (pr < 0) {
6255 return CBM_NOT_FOUND;
6256 }
6257 if (pr == 0) {
6258 cbm_mcp_server_evict_idle(srv, STORE_IDLE_TIMEOUT_S);
6259 return 0;
6260 }
6261 return SKIP_ONE;
6262 }
6263
6264 (void)fcntl(fd, F_SETFL, saved_flags | O_NONBLOCK);
6265 int c = fgetc(in);
6266 (void)fcntl(fd, F_SETFL, saved_flags);
6267
6268 if (c == EOF) {
6269 if (feof(in)) {
6270 return CBM_NOT_FOUND; /* true EOF */
6271 }
6272 clearerr(in);
6273 /* Phase 3: blocking poll, bounded to a SHORT interval (not the full idle
6274 * timeout). macOS poll()/select() do NOT report POLLIN/POLLHUP when a
6275 * FIFO's last writer closes — only read() returns 0 there (verified). A
6276 * 60s poll would therefore leave the server blocked up to a full idle
6277 * timeout after stdin EOF (a client that closes the pipe would appear to
6278 * hang). Waking every MCP_TIMEOUT_MS lets the Phase-2 read() above detect
6279 * the EOF within ~1s. Idle-store eviction (threshold STORE_IDLE_TIMEOUT_S)
6280 * is idempotent, so checking it on each short tick is harmless. */
6281 pr = poll(&pfd, SKIP_ONE, MCP_TIMEOUT_MS);
6282 if (pr < 0) {
6283 return CBM_NOT_FOUND;
6284 }
6285 if (pr == 0) {
6286 cbm_mcp_server_evict_idle(srv, STORE_IDLE_TIMEOUT_S);
6287 return 0;
6288 }
6289 return SKIP_ONE;
6290 }
6291
6292 (void)ungetc(c, in);
6293 return SKIP_ONE;
6294}

Callers 1

cbm_mcp_server_runFunction · 0.85

Calls 1

Tested by

no test coverage detected