From a89a954a850bdb425edfef920ce7c05ab77188c9 Mon Sep 17 00:00:00 2001 From: Chip Weinberger Date: Tue, 5 Nov 2024 14:22:24 -0800 Subject: [PATCH] [Examples] [Async Handlers] simplify code --- .../http_server/async_handlers/main/main.c | 77 ++++++++----------- 1 file changed, 32 insertions(+), 45 deletions(-) diff --git a/examples/protocols/http_server/async_handlers/main/main.c b/examples/protocols/http_server/async_handlers/main/main.c index 7a1091c10d..5eecf51fb1 100644 --- a/examples/protocols/http_server/async_handlers/main/main.c +++ b/examples/protocols/http_server/async_handlers/main/main.c @@ -38,7 +38,7 @@ static const char *TAG = "example"; // Async requests are queued here while they wait to // be processed by the workers -static QueueHandle_t async_req_queue; +static QueueHandle_t request_queue; // Track the number of free workers at any given time static SemaphoreHandle_t worker_ready_count; @@ -53,22 +53,8 @@ typedef struct { httpd_req_handler_t handler; } httpd_async_req_t; - -static bool is_on_async_worker_thread(void) -{ - // is our handle one of the known async handles? - TaskHandle_t handle = xTaskGetCurrentTaskHandle(); - for (int i = 0; i < CONFIG_EXAMPLE_MAX_ASYNC_REQUESTS; i++) { - if (worker_handles[i] == handle) { - return true; - } - } - return false; -} - - -// Submit an HTTP req to the async worker queue -static esp_err_t submit_async_req(httpd_req_t *req, httpd_req_handler_t handler) +// queue an HTTP req to the worker queue +static esp_err_t queue_request(httpd_req_t *req, httpd_req_handler_t handler) { // must create a copy of the request that we own httpd_req_t* copy = NULL; @@ -97,7 +83,7 @@ static esp_err_t submit_async_req(httpd_req_t *req, httpd_req_handler_t handler) // Since worker_ready_count > 0 the queue should already have space. // But lets wait up to 100ms just to be safe. - if (xQueueSend(async_req_queue, &async_req, pdMS_TO_TICKS(100)) == false) { + if (xQueueSend(request_queue, &async_req, pdMS_TO_TICKS(100)) == false) { ESP_LOGE(TAG, "worker queue is full"); httpd_req_async_handler_complete(copy); // cleanup return ESP_FAIL; @@ -106,25 +92,10 @@ static esp_err_t submit_async_req(httpd_req_t *req, httpd_req_handler_t handler) return ESP_OK; } - -/* A long running HTTP GET handler */ -static esp_err_t long_async_handler(httpd_req_t *req) +/* handle long request (on async thread) */ +static esp_err_t long_async(httpd_req_t *req) { - ESP_LOGI(TAG, "uri: /long"); - // This handler is first invoked on the httpd thread. - // In order to free the httpd thread to handle other requests, - // we must resubmit our request to be handled on an async worker thread. - if (is_on_async_worker_thread() == false) { - - // submit - if (submit_async_req(req, long_async_handler) == ESP_OK) { - return ESP_OK; - } else { - httpd_resp_set_status(req, "503 Busy"); - httpd_resp_sendstr(req, "
no workers available. server busy.
"); - return ESP_OK; - } - } + ESP_LOGI(TAG, "running: /long"); // track the number of long requests static uint8_t req_count = 0; @@ -154,7 +125,8 @@ static esp_err_t long_async_handler(httpd_req_t *req) return ESP_OK; } -static void async_req_worker_task(void *p) +// each worker thread loops forever, processing requests +static void worker_task(void *p) { ESP_LOGI(TAG, "starting async req task worker"); @@ -166,7 +138,7 @@ static void async_req_worker_task(void *p) // wait for a request httpd_async_req_t async_req; - if (xQueueReceive(async_req_queue, &async_req, portMAX_DELAY)) { + if (xQueueReceive(request_queue, &async_req, portMAX_DELAY)) { ESP_LOGI(TAG, "invoking %s", async_req.req->uri); @@ -185,7 +157,8 @@ static void async_req_worker_task(void *p) vTaskDelete(NULL); } -static void start_async_req_workers(void) +// start worker threads +static void start_workers(void) { // counting semaphore keeps track of available workers @@ -198,9 +171,9 @@ static void start_async_req_workers(void) } // create queue - async_req_queue = xQueueCreate(1, sizeof(httpd_async_req_t)); - if (async_req_queue == NULL){ - ESP_LOGE(TAG, "Failed to create async_req_queue"); + request_queue = xQueueCreate(1, sizeof(httpd_async_req_t)); + if (request_queue == NULL){ + ESP_LOGE(TAG, "Failed to create request_queue"); vSemaphoreDelete(worker_ready_count); return; } @@ -208,7 +181,7 @@ static void start_async_req_workers(void) // start worker tasks for (int i = 0; i < CONFIG_EXAMPLE_MAX_ASYNC_REQUESTS; i++) { - bool success = xTaskCreate(async_req_worker_task, "async_req_worker", + bool success = xTaskCreate(worker_task, "async_req_worker", ASYNC_WORKER_TASK_STACK_SIZE, // stack size (void *)0, // argument ASYNC_WORKER_TASK_PRIORITY, // priority @@ -221,6 +194,20 @@ static void start_async_req_workers(void) } } +/* adds /long request to the request queue */ +static esp_err_t long_handler(httpd_req_t *req) +{ + ESP_LOGI(TAG, "uri: /long"); + + // add to the async request queue + if (queue_request(req, long_async) == ESP_OK) { + return ESP_OK; + } else { + httpd_resp_set_status(req, "503 Busy"); + httpd_resp_sendstr(req, "
no workers available. server busy.
"); + return ESP_OK; + } +} /* A quick HTTP GET handler, which does not use any asynchronous features */ @@ -271,7 +258,7 @@ static httpd_handle_t start_webserver(void) const httpd_uri_t long_uri = { .uri = "/long", .method = HTTP_GET, - .handler = long_async_handler, + .handler = long_handler, }; const httpd_uri_t quick_uri = { @@ -346,7 +333,7 @@ void app_main(void) #endif // CONFIG_EXAMPLE_CONNECT_ETHERNET // start workers - start_async_req_workers(); + start_workers(); /* Start the server for the first time */ server = start_webserver();