| 2063 | } |
| 2064 | |
| 2065 | static bool runtime_service_can_exit(cbm_daemon_runtime_service_t *service, uint64_t now_ms) { |
| 2066 | bool can_exit = false; |
| 2067 | cbm_mutex_lock(&service->mutex); |
| 2068 | if (service->state == CBM_DAEMON_RUNTIME_SERVICE_STOPPING && service->active_connections == 0) { |
| 2069 | bool drained = cbm_daemon_should_exit(service->coordinator, now_ms); |
| 2070 | if (!drained && service->activation_shutdown_requested) { |
| 2071 | /* Activation can arrive while the daemon has no committed |
| 2072 | * coordinator client, so no final disconnect exists to flip the |
| 2073 | * coordinator's terminal bit. Resource emptiness is equivalent |
| 2074 | * once the runtime has atomically stopped all new admission. */ |
| 2075 | drained = cbm_daemon_active_clients(service->coordinator) == 0 && |
| 2076 | cbm_daemon_active_jobs(service->coordinator) == 0 && |
| 2077 | cbm_daemon_active_watches(service->coordinator) == 0; |
| 2078 | } |
| 2079 | bool deadline_reached = |
| 2080 | service->stop_deadline_ms != 0 && now_ms >= service->stop_deadline_ms; |
| 2081 | can_exit = drained || deadline_reached || service->emergency_stop; |
| 2082 | if (can_exit) { |
| 2083 | service->state = CBM_DAEMON_RUNTIME_SERVICE_EXITED; |
| 2084 | } |
| 2085 | } |
| 2086 | cbm_mutex_unlock(&service->mutex); |
| 2087 | return can_exit; |
| 2088 | } |
| 2089 | |
| 2090 | static void *runtime_accept_loop(void *opaque) { |
| 2091 | cbm_daemon_runtime_service_t *service = opaque; |
no test coverage detected