| 1399 | } |
| 1400 | |
| 1401 | static void runtime_worker_finish(cbm_daemon_runtime_worker_t *worker) { |
| 1402 | cbm_daemon_runtime_service_t *service = worker->service; |
| 1403 | runtime_worker_disconnect(worker); |
| 1404 | if (!runtime_worker_reap_application(worker, true)) { |
| 1405 | /* Fail closed on an impossible/invalid join rather than closing the |
| 1406 | * session or freeing storage a callback could still reference. The |
| 1407 | * service intentionally remains non-terminal for diagnosis. */ |
| 1408 | return; |
| 1409 | } |
| 1410 | if (worker->application_session_opened) { |
| 1411 | service->application.session_close(service->application.context, |
| 1412 | worker->application_session); |
| 1413 | worker->application_session = NULL; |
| 1414 | worker->application_session_opened = false; |
| 1415 | } |
| 1416 | if (worker->connection) { |
| 1417 | /* Off the service mutex: a peer that just received its final response |
| 1418 | * (hello rejection, disconnect acknowledgement) must be able to read |
| 1419 | * it before the handle closes; see cbm_daemon_ipc_connection_drain. */ |
| 1420 | cbm_daemon_ipc_connection_drain(worker->connection, RUNTIME_WORKER_DRAIN_TIMEOUT_MS); |
| 1421 | } |
| 1422 | cbm_mutex_lock(&service->mutex); |
| 1423 | if (worker->connection) { |
| 1424 | cbm_daemon_ipc_connection_close(worker->connection); |
| 1425 | worker->connection = NULL; |
| 1426 | } |
| 1427 | if (service->active_connections > 0) { |
| 1428 | service->active_connections--; |
| 1429 | } |
| 1430 | atomic_store_explicit(&worker->done, true, memory_order_release); |
| 1431 | cbm_mutex_unlock(&service->mutex); |
| 1432 | } |
| 1433 | |
| 1434 | static bool runtime_activation_peer_matches_claim(cbm_daemon_runtime_service_t *service, |
| 1435 | uint64_t process_id, const char *claimed_build) { |
no test coverage detected