| 1053 | } |
| 1054 | |
| 1055 | static application_attempt_status_t application_job_run_attempt(cbm_daemon_application_job_t *job, |
| 1056 | const char *marker_path, |
| 1057 | const char *quarantine_path, |
| 1058 | application_attempt_t *attempt) { |
| 1059 | application_attempt_init(attempt); |
| 1060 | cbm_daemon_application_t *application = job->application; |
| 1061 | if (application_job_cancel_requested(job)) { |
| 1062 | return APPLICATION_ATTEMPT_CANCELLED; |
| 1063 | } |
| 1064 | |
| 1065 | cbm_daemon_application_worker_t worker = NULL; |
| 1066 | application_tmp_lock(); |
| 1067 | int start_result = application->worker_ops.start( |
| 1068 | application->worker_ops.context, job->args_json, application->worker_memory_budget_bytes, |
| 1069 | marker_path, quarantine_path, &worker); |
| 1070 | application_tmp_unlock(); |
| 1071 | if (start_result != 0 || !worker) { |
| 1072 | return application_job_cancel_requested(job) ? APPLICATION_ATTEMPT_CANCELLED |
| 1073 | : APPLICATION_ATTEMPT_START_FAILED; |
| 1074 | } |
| 1075 | |
| 1076 | cbm_mutex_lock(&application->mutex); |
| 1077 | job->worker = worker; |
| 1078 | bool cancel_now = job->cancel_requested || application->stopping; |
| 1079 | cbm_mutex_unlock(&application->mutex); |
| 1080 | if (cancel_now) { |
| 1081 | /* The worker thread owns this handle until destroy below. Invoke the |
| 1082 | * external supervisor without the application mutex held. */ |
| 1083 | (void)application->worker_ops.cancel(application->worker_ops.context, worker); |
| 1084 | } |
| 1085 | |
| 1086 | const cbm_index_worker_result_t *borrowed = NULL; |
| 1087 | for (;;) { |
| 1088 | cbm_index_worker_poll_t state = |
| 1089 | application->worker_ops.poll(application->worker_ops.context, worker, &borrowed); |
| 1090 | if (state == CBM_INDEX_WORKER_POLL_TERMINAL) { |
| 1091 | break; |
| 1092 | } |
| 1093 | cbm_mutex_lock(&application->mutex); |
| 1094 | bool cancel_pending = |
| 1095 | (job->cancel_requested || application->stopping) && job->worker == worker; |
| 1096 | cbm_mutex_unlock(&application->mutex); |
| 1097 | if (cancel_pending || state == CBM_INDEX_WORKER_POLL_ERROR) { |
| 1098 | (void)application->worker_ops.cancel(application->worker_ops.context, worker); |
| 1099 | } |
| 1100 | cbm_usleep(APPLICATION_JOB_POLL_US); |
| 1101 | } |
| 1102 | |
| 1103 | if (borrowed) { |
| 1104 | attempt->result = *borrowed; |
| 1105 | attempt->result.response = borrowed->response ? cbm_strdup(borrowed->response) : NULL; |
| 1106 | attempt->has_result = true; |
| 1107 | } |
| 1108 | const char *worker_log = |
| 1109 | application->worker_ops.log_path(application->worker_ops.context, worker); |
| 1110 | if (worker_log) { |
| 1111 | (void)snprintf(attempt->log_path, sizeof(attempt->log_path), "%s", worker_log); |
| 1112 | } |
no test coverage detected