| 1237 | } |
| 1238 | |
| 1239 | static void *runtime_application_worker(void *opaque) { |
| 1240 | cbm_daemon_runtime_worker_t *worker = opaque; |
| 1241 | cbm_daemon_runtime_service_t *service = worker->service; |
| 1242 | uint8_t *response = NULL; |
| 1243 | uint32_t response_length = 0; |
| 1244 | cbm_daemon_runtime_application_status_t status = service->application.request( |
| 1245 | service->application.context, worker->application_session, |
| 1246 | worker->application_request_token, worker->application_request, |
| 1247 | worker->application_request_length, &response, &response_length); |
| 1248 | |
| 1249 | bool valid_status = runtime_application_status_is_callback_result(status); |
| 1250 | bool valid_response = |
| 1251 | response_length <= CBM_DAEMON_RUNTIME_APPLICATION_PAYLOAD_MAX && |
| 1252 | (response_length == 0 || response != NULL) && |
| 1253 | (status == CBM_DAEMON_RUNTIME_APPLICATION_OK || (response == NULL && response_length == 0)); |
| 1254 | if (!valid_status || !valid_response) { |
| 1255 | free(response); |
| 1256 | response = NULL; |
| 1257 | response_length = 0; |
| 1258 | status = CBM_DAEMON_RUNTIME_APPLICATION_HANDLER_ERROR; |
| 1259 | } |
| 1260 | |
| 1261 | /* Completion must be one atomic transition from the client's point of |
| 1262 | * view: publish the done flag BEFORE the response bytes leave, so by the |
| 1263 | * time any client can react to the response, admission already observes |
| 1264 | * this slot as reusable. With the store after the send, a client that |
| 1265 | * pipelines its next request the moment it sees a response raced this |
| 1266 | * thread's final instructions and was rejected BUSY — on loaded Windows |
| 1267 | * hosts roughly half of all back-to-back requests on one connection, |
| 1268 | * surfacing as the wandering Phase 5 session drops. The admission side |
| 1269 | * joins this thread after observing the flag, which safely absorbs the |
| 1270 | * tail of the send. */ |
| 1271 | atomic_store_explicit(&worker->application_thread_done, true, memory_order_release); |
| 1272 | bool sent = runtime_worker_send_application_response(worker, worker->application_request_token, |
| 1273 | status, response, response_length, true); |
| 1274 | free(response); |
| 1275 | if (!sent && !atomic_load_explicit(&worker->disconnecting, memory_order_acquire)) { |
| 1276 | cbm_daemon_ipc_connection_interrupt(worker->connection); |
| 1277 | } |
| 1278 | return NULL; |
| 1279 | } |
| 1280 | |
| 1281 | static bool runtime_worker_reap_application(cbm_daemon_runtime_worker_t *worker, bool wait) { |
| 1282 | if (!worker->application_thread_started) { |
nothing calls this directly
no test coverage detected