From 1810367e8d452ac0d83b0e946e5a1611265f827b Mon Sep 17 00:00:00 2001 From: William Emfinger Date: Mon, 23 Sep 2024 15:08:59 -0500 Subject: [PATCH] feat(task): Add `espp::task::run_on_core_non_blocking` static method (#331) --- components/task/example/main/task_example.cpp | 23 +++++++++++ components/task/include/run_on_core.hpp | 40 +++++++++++++++++++ components/task/include/task.hpp | 2 + 3 files changed, 65 insertions(+) diff --git a/components/task/example/main/task_example.cpp b/components/task/example/main/task_example.cpp index 6203fdfc5..02f28dacc 100644 --- a/components/task/example/main/task_example.cpp +++ b/components/task/example/main/task_example.cpp @@ -530,6 +530,29 @@ extern "C" void app_main(void) { //! [run on core example] } + { + //! [run on core nonblocking example] + logger.info("espp::task::run_on_core non-blocking example: main thread core ID: {}", + xPortGetCoreID()); + // NOTE: in these examples, because we're logging with libfmt in the + // function to be run, we need a little more than the default 2k stack size, + // so we're using 3k. + + // test running a function which takes a while to complete + auto task_fn = []() -> void { + fmt::print("[{0}] Task running on core {0}\n", xPortGetCoreID()); + std::this_thread::sleep_for(1s); + fmt::print("[{0}] Task done!\n", xPortGetCoreID()); + }; + espp::task::run_on_core_non_blocking(task_fn, 0, 3 * 1024); + espp::task::run_on_core_non_blocking(task_fn, 1); + fmt::print("Started tasks on cores 0 and 1\n"); + + // sleep for a bit to let the tasks run + std::this_thread::sleep_for(2s); + //! [run on core nonblocking example] + } + logger.info("Task example complete!"); while (true) { diff --git a/components/task/include/run_on_core.hpp b/components/task/include/run_on_core.hpp index 9f67cfa23..323ec8986 100644 --- a/components/task/include/run_on_core.hpp +++ b/components/task/include/run_on_core.hpp @@ -82,6 +82,46 @@ static auto run_on_core(const auto &f, int core_id, size_t stack_size_bytes = 20 } } } + +/// Run the given function on the specific core without blocking the calling thread +/// @details This function will run the given function on the specified core, +/// without blocking the calling thread / context. A new thread is +/// spawned for the function even if the requested core is the same as +/// the core on which the calling thread is running. +/// @param f The function to run +/// @param core_id The core to run the function on +/// @param stack_size_bytes The stack size to allocate for the function +/// @param priority The priority of the task +/// @note This function is only available on ESP32 +/// @note If you provide a core_id < 0, the thread will not be pinned to any +/// specific core, instead the scheduler will decide which core to run +/// the thread on +/// @note If you provide a core_id >= configNUM_CORES, the function will run on +/// the last core +static void run_on_core_non_blocking(const auto &f, int core_id, size_t stack_size_bytes = 2048, + size_t priority = 5) { + // Otherwise run the function on the desired core + if (core_id > configNUM_CORES - 1) { + // If the core id is larger than the number of cores, run on the last core + core_id = configNUM_CORES - 1; + } + auto thread_config = esp_pthread_get_default_config(); + thread_config.thread_name = "run_on_core_thread"; + if (core_id >= 0) + thread_config.pin_to_core = core_id; + thread_config.stack_size = stack_size_bytes; + thread_config.prio = priority; + // this will set the config for the next created thread + auto err = esp_pthread_set_cfg(&thread_config); + if (err != ESP_OK) { + // failed to set the config, can't create the thread; simply run the function + // on the current core + f(); + return; + } + auto thread = std::thread(f); + thread.detach(); +} #endif } // namespace task } // namespace espp diff --git a/components/task/include/task.hpp b/components/task/include/task.hpp index 72b499e62..1ab45046c 100644 --- a/components/task/include/task.hpp +++ b/components/task/include/task.hpp @@ -44,6 +44,8 @@ namespace espp { * * \section run_on_core_ex1 Run on Core Example * \snippet task_example.cpp run on core example + * \section run_on_core_ex2 Run on Core (Non-Blocking) Example + * \snippet task_example.cpp run on core nonblocking example */ class Task : public espp::BaseComponent { public: