| 2733 | } |
| 2734 | |
| 2735 | static void application_session_cancel(void *context, |
| 2736 | cbm_daemon_runtime_application_session_t *opaque_session) { |
| 2737 | cbm_daemon_application_t *application = context; |
| 2738 | cbm_daemon_application_session_t *session = (cbm_daemon_application_session_t *)opaque_session; |
| 2739 | if (application && session && session->application == application) { |
| 2740 | bool reap_update = false; |
| 2741 | cbm_daemon_application_job_t *join_auto_index = NULL; |
| 2742 | cbm_mutex_lock(&application->mutex); |
| 2743 | /* Runtime may need to keep the session allocation alive until its |
| 2744 | * request callback joins. Cancellation, not the later close, is the |
| 2745 | * ownership boundary for watches and session-scoped index work. */ |
| 2746 | bool newly_cancelled = !session->session_cancelled; |
| 2747 | session->session_cancelled = true; |
| 2748 | if (session->request_active) { |
| 2749 | session->request_cancel_token = session->active_request_token; |
| 2750 | } |
| 2751 | if (session->active_job && session->active_job_subscribed) { |
| 2752 | cbm_daemon_application_job_t *job = session->active_job; |
| 2753 | session->active_job = NULL; |
| 2754 | session->active_job_subscribed = false; |
| 2755 | application_job_unsubscribe_locked(job); |
| 2756 | } |
| 2757 | join_auto_index = application_auto_index_release_locked(session); |
| 2758 | reap_update = application_update_owner_release_locked(session); |
| 2759 | reap_update = |
| 2760 | reap_update || (session->background_eligible && application->update_thread_started && |
| 2761 | application->update_owners == 0); |
| 2762 | application_release_session_watch_locked(session); |
| 2763 | bool final_live_session = newly_cancelled; |
| 2764 | for (cbm_daemon_application_session_t *other = application->sessions; |
| 2765 | final_live_session && other; other = other->next) { |
| 2766 | if (other != session && !other->session_cancelled) { |
| 2767 | final_live_session = false; |
| 2768 | } |
| 2769 | } |
| 2770 | if (final_live_session && !application->permanent) { |
| 2771 | /* The daemon runtime cannot close this allocation until an |
| 2772 | * in-flight callback joins. Stop new admission now and cancel |
| 2773 | * watcher/UI jobs that are not owned by session->active_job. |
| 2774 | * A PERMANENT generation deliberately outlives its sessions and |
| 2775 | * keeps admitting new ones; only the stop/drain paths latch it. */ |
| 2776 | application->stopping = true; |
| 2777 | application_cancel_jobs_locked(application); |
| 2778 | application_update_cancel_locked(application); |
| 2779 | reap_update = reap_update || application->update_thread_started; |
| 2780 | } |
| 2781 | cbm_mutex_unlock(&application->mutex); |
| 2782 | (void)cbm_mcp_server_cancel_active(session->mcp); |
| 2783 | application_auto_index_cancel_join(application, join_auto_index); |
| 2784 | application_jobs_reap_completed(application); |
| 2785 | if (reap_update) { |
| 2786 | if (!application_update_reap(application, true, APPLICATION_BACKGROUND_REAP_MS)) { |
| 2787 | application_cleanup_force_terminate("update_cleanup"); |
| 2788 | } |
| 2789 | } |
| 2790 | } |
| 2791 | } |
| 2792 |
nothing calls this directly
no test coverage detected