81 lines · 2.2 KB · C
RawDownload
// SPDX-License-Identifier: ISC/* * Shared by main.c and tui.c: settle the loop after teardown. Every uv-backed * object in clm frees itself from a uv_close callback, so a frontend that * stops running the loop at teardown leaks all of them. */#ifndef CLM_LOOP_DRAIN_H#define CLM_LOOP_DRAIN_H #include <stdbool.h> #include <uv.h> #include "clm/clm.h" /* How long the drain waits for the last closes to land. Long enough for a * SIGKILL'd MCP server to be reaped, short enough to never feel like a hang. */#define CLM_DRAIN_MS 500 /* Loop turns spent waiting for a cancelled turn to unwind. */#define CLM_SETTLE_ITERATIONS 1000 static inline voidclm_drain_deadline(uv_timer_t *t){	*(bool *)t->data = true;} /* * Cancel a turn still in flight and let the loop deliver the cancellation: * the turn belongs to its completion callback, so an exit that never runs * that callback leaks it. Bounded, so a stuck cancel cannot hang exit. */static inline voidclm_settle_turn(struct clm_agent *agent, uv_loop_t *loop){	int i; 	if (agent == NULL || loop == NULL || clm_agent_cancel(agent) != 0)		return;	for (i = 0; i < CLM_SETTLE_ITERATIONS; i++) {		enum clm_agent_state st = clm_agent_get_state(agent); 		if (st != CLM_STATE_THINKING && st != CLM_STATE_CALLING_TOOL)			break;		uv_run(loop, UV_RUN_NOWAIT);	}} /* * Run loop until nothing is left on it, or the deadline expires, then close * it. Call it after the last *_free on an exit path, with the frontend's own * handles already closed: a handle still active here keeps firing callbacks * into objects the teardown released. Returns 0 if every handle settled, * UV_EBUSY if one is still outstanding. */static inline intclm_drain_loop(uv_loop_t *loop){	uv_timer_t deadline;	bool expired = false; 	if (loop == NULL)		return 0; 	uv_timer_init(loop, &deadline);	deadline.data = &expired;	uv_timer_start(&deadline, clm_drain_deadline, CLM_DRAIN_MS, 0);	/* Unreferenced so the deadline alone never counts as "still busy". */	uv_unref((uv_handle_t *)&deadline); 	while (!expired && uv_run(loop, UV_RUN_ONCE) != 0)		; 	uv_close((uv_handle_t *)&deadline, NULL);	(void)uv_run(loop, UV_RUN_NOWAIT);	return uv_loop_close(loop);} #endif /* CLM_LOOP_DRAIN_H */