Skip to content

Commit 6972195

Browse files
authored
feat(task): Add additional APIs for querying specific characteristics of the task or the current task context (#581)
* feat(task): Add additional APIs for querying specific characteristics of the task or the current task context * fix copy-pasta in docs * fix incorrect return type in docs * update xplat libs
1 parent e94ee66 commit 6972195

File tree

5 files changed

+195
-50
lines changed

5 files changed

+195
-50
lines changed

components/task/example/main/task_example.cpp

Lines changed: 55 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ using namespace std::chrono_literals;
3535
*/
3636
extern "C" void app_main(void) {
3737
espp::Logger logger({.tag = "TaskExample", .level = espp::Logger::Verbosity::DEBUG});
38+
logger.info("Starting Task example application");
39+
3840
/**
3941
* Set up some variables we'll re-use to control and measure our tests.
4042
*/
@@ -52,9 +54,10 @@ extern "C" void app_main(void) {
5254
logger.info("Basic task example: spawning 1 task for {} seconds!", num_seconds_to_run);
5355
//! [Task example]
5456
espp::Task::configure_task_watchdog(1000ms);
57+
fmt::println("Main thread task handle = {}", fmt::ptr(espp::Task::get_freertos_handle()));
5558
auto task_fn = [](std::mutex &m, std::condition_variable &cv) {
5659
static size_t task_iterations{0};
57-
fmt::print("Task: #iterations = {}\n", task_iterations);
60+
fmt::println("Task: #iterations = {}", task_iterations);
5861
task_iterations++;
5962
// NOTE: sleeping in this way allows the sleep to exit early when the
6063
// task is being stopped / destroyed
@@ -71,18 +74,24 @@ extern "C" void app_main(void) {
7174
task.start();
7275
task.start_watchdog(); // start the watchdog timer for this task
7376
std::this_thread::sleep_for(num_seconds_to_run * 1s);
77+
fmt::println("Task HWM: {} bytes", espp::Task::get_high_water_mark(task));
78+
fmt::println("Task priority: {}", espp::Task::get_priority(task));
79+
fmt::println("Task Core ID: {}", espp::Task::get_core_id(task));
80+
fmt::println("Task ID: {}", espp::Task::get_id(task));
81+
fmt::println("Task Handle: {}", fmt::ptr(espp::Task::get_freertos_handle(task)));
82+
7483
task.stop_watchdog(); // stop the watchdog timer for this task
7584
// show explicitly stopping the task (though the destructor called at the
7685
// end of this scope would do it for us)
7786
task.stop();
7887
std::error_code ec;
7988
std::string watchdog_info = espp::Task::get_watchdog_info(ec);
8089
if (ec) {
81-
fmt::print("Error getting watchdog info: {}\n", ec.message());
90+
fmt::println("Error getting watchdog info: {}", ec.message());
8291
} else if (!watchdog_info.empty()) {
83-
fmt::print("Watchdog info: {}\n", watchdog_info);
92+
fmt::println("Watchdog info: {}", watchdog_info);
8493
} else {
85-
fmt::print("No watchdog info available\n");
94+
fmt::println("No watchdog info available");
8695
}
8796
//! [Task example]
8897
}
@@ -102,7 +111,7 @@ extern "C" void app_main(void) {
102111
espp::Task::configure_task_watchdog(300ms, panic_on_watchdog_timeout);
103112
auto task_fn = [](std::mutex &m, std::condition_variable &cv) {
104113
static size_t task_iterations{0};
105-
fmt::print("Task: #iterations = {}\n", task_iterations);
114+
fmt::println("Task: #iterations = {}", task_iterations);
106115
task_iterations++;
107116
std::unique_lock<std::mutex> lk(m);
108117
// note our sleep here is longer than the watchdog timeout, so we should
@@ -120,11 +129,11 @@ extern "C" void app_main(void) {
120129
std::error_code ec;
121130
std::string watchdog_info = espp::Task::get_watchdog_info(ec);
122131
if (ec) {
123-
fmt::print("Error getting watchdog info: {}\n", ec.message());
132+
fmt::println("Error getting watchdog info: {}", ec.message());
124133
} else if (!watchdog_info.empty()) {
125-
fmt::print("Watchdog info: {}\n", watchdog_info);
134+
fmt::println("Watchdog info: {}", watchdog_info);
126135
} else {
127-
fmt::print("No watchdog info available\n");
136+
fmt::println("No watchdog info available");
128137
}
129138
// NOTE: the task and the watchdog will both automatically get stopped when
130139
// the task goes out of scope and is destroyed.
@@ -152,7 +161,7 @@ extern "C" void app_main(void) {
152161
size_t iterations{0};
153162
// copy the loop variables and indicate that we intend to mutate them!
154163
auto task_fn = [i, iterations](std::mutex &m, std::condition_variable &cv) mutable {
155-
fmt::print("Task {}: #iterations = {}\n", i, iterations);
164+
fmt::println("Task {}: #iterations = {}", i, iterations);
156165
iterations++;
157166
// NOTE: sleeping in this way allows the sleep to exit early when the
158167
// task is being stopped / destroyed
@@ -169,7 +178,7 @@ extern "C" void app_main(void) {
169178
tasks[i] = std::move(task);
170179
tasks[i]->start();
171180
}
172-
fmt::print("Tasks spawned, waiting for {} seconds!\n", num_seconds_to_run);
181+
fmt::println("Tasks spawned, waiting for {} seconds!", num_seconds_to_run);
173182
std::this_thread::sleep_until(start + num_seconds_to_run * 1s);
174183
//! [ManyTask example]
175184
}
@@ -194,7 +203,7 @@ extern "C" void app_main(void) {
194203
size_t iterations{0};
195204
// copy the loop variables and indicate that we intend to mutate them!
196205
auto task_fn = [i, iterations]() mutable {
197-
fmt::print("Task {}: #iterations = {}\n", i, iterations);
206+
fmt::println("Task {}: #iterations = {}", i, iterations);
198207
iterations++;
199208
// NOTE: sleeping in this way PREVENTS the sleep / task from early
200209
// exiting when the task is being stopped / destroyed.
@@ -213,7 +222,7 @@ extern "C" void app_main(void) {
213222
tasks[i] = std::move(task);
214223
tasks[i]->start();
215224
}
216-
fmt::print("Tasks spawned, waiting for {} seconds!\n", num_seconds_to_run);
225+
fmt::println("Tasks spawned, waiting for {} seconds!", num_seconds_to_run);
217226
std::this_thread::sleep_until(start + num_seconds_to_run * 1s);
218227
}
219228
test_end = std::chrono::high_resolution_clock::now();
@@ -235,7 +244,7 @@ extern "C" void app_main(void) {
235244
auto task_fn = [](std::mutex &m, std::condition_variable &cv) {
236245
static size_t task_iterations{0};
237246
const size_t num_steps_per_iteration = 10;
238-
fmt::print("Task processing iteration {}...\n", task_iterations);
247+
fmt::println("Task processing iteration {}...", task_iterations);
239248
for (size_t i = 0; i < num_steps_per_iteration; i++) {
240249
// NOTE: sleeping in this way allows the sleep to exit early when the
241250
// task is being stopped / destroyed
@@ -248,8 +257,8 @@ extern "C" void app_main(void) {
248257
if (cv_retval == std::cv_status::no_timeout) {
249258
// if there was no timeout, then we were notified, therefore we need
250259
// to shut down.
251-
fmt::print("Task stopping early (step {}/{}) on iteration {}\n", i,
252-
num_steps_per_iteration, task_iterations);
260+
fmt::println("Task stopping early (step {}/{}) on iteration {}", i,
261+
num_steps_per_iteration, task_iterations);
253262
// NOTE: use this_thread::sleep_for() to fake cleaning up work that
254263
// we would do
255264
std::this_thread::sleep_for(10ms);
@@ -259,7 +268,7 @@ extern "C" void app_main(void) {
259268
}
260269
}
261270
}
262-
fmt::print("Task processing iteration {} complete\n", task_iterations);
271+
fmt::println("Task processing iteration {} complete", task_iterations);
263272
task_iterations++;
264273
// we don't want to stop, so return false
265274
return false;
@@ -289,7 +298,7 @@ extern "C" void app_main(void) {
289298
auto task_fn = [](std::mutex &m, std::condition_variable &cv, bool &task_notified) {
290299
static size_t task_iterations{0};
291300
const size_t num_steps_per_iteration = 10;
292-
fmt::print("Task processing iteration {}...\n", task_iterations);
301+
fmt::println("Task processing iteration {}...", task_iterations);
293302
for (size_t i = 0; i < num_steps_per_iteration; i++) {
294303
// NOTE: sleeping in this way allows the sleep to exit early when the
295304
// task is being stopped / destroyed
@@ -301,8 +310,8 @@ extern "C" void app_main(void) {
301310
auto stop_requested = cv.wait_for(lk, std::chrono::milliseconds(100),
302311
[&task_notified] { return task_notified; });
303312
if (stop_requested) {
304-
fmt::print("Task was notified, stopping early (step {}/{}) on iteration {}\n", i,
305-
num_steps_per_iteration, task_iterations);
313+
fmt::println("Task was notified, stopping early (step {}/{}) on iteration {}", i,
314+
num_steps_per_iteration, task_iterations);
306315
// NOTE: use this_thread::sleep_for() to fake cleaning up work that
307316
// we would do
308317
std::this_thread::sleep_for(10ms);
@@ -312,7 +321,7 @@ extern "C" void app_main(void) {
312321
}
313322
}
314323
}
315-
fmt::print("Task processing iteration {} complete\n", task_iterations);
324+
fmt::println("Task processing iteration {} complete", task_iterations);
316325
task_iterations++;
317326
// we don't want to stop, so return false
318327
return false;
@@ -340,10 +349,14 @@ extern "C" void app_main(void) {
340349
task_iterations++;
341350
// allocate stack
342351
size_t num_bytes = 256 * task_iterations;
343-
char buffer[num_bytes];
352+
char buffer[num_bytes] = {0};
344353
// do something with the bufer (which also uses stack)
345-
snprintf(buffer, num_bytes, "%.06f\n", (float)task_iterations);
346-
fmt::print("{}\n", espp::Task::get_info());
354+
snprintf(buffer, num_bytes, "%.06f", (float)task_iterations);
355+
fmt::println("Task iteration {}: buffer = {:s}", task_iterations, (char *)buffer);
356+
fmt::println("{}", espp::Task::get_info());
357+
fmt::println("Core ID: {}", espp::Task::get_core_id());
358+
fmt::println("HWM: {} bytes", espp::Task::get_high_water_mark());
359+
fmt::println("Priority: {}", espp::Task::get_priority());
347360
// NOTE: sleeping in this way allows the sleep to exit early when the
348361
// task is being stopped / destroyed
349362
{
@@ -364,7 +377,7 @@ extern "C" void app_main(void) {
364377
now = std::chrono::high_resolution_clock::now();
365378
elapsed = std::chrono::duration<float>(now - test_start).count();
366379
}
367-
fmt::print("Final: {}\n", espp::Task::get_info(task));
380+
fmt::println("Final: {}", espp::Task::get_info(task));
368381
//! [Task Info example]
369382
}
370383
test_end = std::chrono::high_resolution_clock::now();
@@ -424,7 +437,7 @@ extern "C" void app_main(void) {
424437
auto elapsed = std::chrono::duration<float>(now - begin).count();
425438
if (elapsed > num_seconds_to_run) {
426439
static int num_times_run{0};
427-
fmt::print("Task stopping early after {} runs!\n", ++num_times_run);
440+
fmt::println("Task stopping early after {} runs!", ++num_times_run);
428441
// we've gone long enough, time to stop our task!
429442
return true;
430443
}
@@ -445,7 +458,7 @@ extern "C" void app_main(void) {
445458
std::this_thread::sleep_for(10ms);
446459
}
447460
// restart the task without explicitly cancelling it
448-
fmt::print("Restarting task...\n");
461+
fmt::println("Restarting task...");
449462
task.start();
450463
while (task.is_started()) {
451464
std::this_thread::sleep_for(10ms);
@@ -469,7 +482,7 @@ extern "C" void app_main(void) {
469482
static auto begin = std::chrono::high_resolution_clock::now();
470483
auto now = std::chrono::high_resolution_clock::now();
471484
auto elapsed = std::chrono::duration<float>(now - begin).count();
472-
fmt::print("Task has run for {:.03f} seconds\n", elapsed);
485+
fmt::println("Task has run for {:.03f} seconds", elapsed);
473486
// NOTE: sleeping in this way allows the sleep to exit early when the
474487
// task is being stopped / destroyed
475488
{
@@ -491,7 +504,7 @@ extern "C" void app_main(void) {
491504
std::this_thread::sleep_for(1s);
492505
// NOTE: on ESP-IDF, this is the same as xTaskGetCurrentTaskHandle();
493506
auto thread = espp::Task::get_current_id();
494-
fmt::print("Stopping task from thread {}...\n", thread);
507+
fmt::println("Stopping task from thread {}...", thread);
495508
task.stop();
496509
};
497510
// make vector of threads to stop the task
@@ -523,15 +536,15 @@ extern "C" void app_main(void) {
523536
static auto begin = std::chrono::high_resolution_clock::now();
524537
auto now = std::chrono::high_resolution_clock::now();
525538
auto elapsed = std::chrono::duration<float>(now - begin).count();
526-
fmt::print("Task has run for {:.03f} seconds\n", elapsed);
539+
fmt::println("Task has run for {:.03f} seconds", elapsed);
527540
// NOTE: sleeping in this way allows the sleep to exit early when the
528541
// task is being stopped / destroyed
529542
{
530543
std::unique_lock<std::mutex> lk(m);
531544
cv.wait_for(lk, 100ms);
532545
}
533546
if (elapsed > num_seconds_to_run) {
534-
fmt::print("Stopping task from within task...\n");
547+
fmt::println("Stopping task from within task...");
535548
task.stop();
536549
}
537550
// do some other work here which can't be preempted, this helps force the
@@ -559,34 +572,34 @@ extern "C" void app_main(void) {
559572
// so we're using 3k.
560573

561574
// test running a function that returns void on a specific core
562-
auto task_fn = []() -> void { fmt::print("Void Task running on core {}\n", xPortGetCoreID()); };
575+
auto task_fn = []() -> void { fmt::println("Void Task running on core {}", xPortGetCoreID()); };
563576
espp::task::run_on_core(task_fn, 0, 3 * 1024);
564-
fmt::print("Void Function returned\n");
577+
fmt::println("Void Function returned");
565578
espp::task::run_on_core(task_fn, 1, 3 * 1024);
566-
fmt::print("Void Function returned\n");
579+
fmt::println("Void Function returned");
567580

568581
// test running a function that returns bool on a specific core
569582
auto task_fn2 = []() -> bool {
570583
auto core_id = xPortGetCoreID();
571-
fmt::print("Bool Task running on core {}\n", core_id);
584+
fmt::println("Bool Task running on core {}", core_id);
572585
return core_id == 1;
573586
};
574587
auto result0 = espp::task::run_on_core(task_fn2, 0, 3 * 1024);
575-
fmt::print("Bool Function returned {}\n", result0);
588+
fmt::println("Bool Function returned {}", result0);
576589
auto result1 = espp::task::run_on_core(
577590
task_fn2, {.name = "test", .stack_size_bytes = 3 * 1024, .core_id = 1});
578-
fmt::print("Bool Function returned {}\n", result1);
591+
fmt::println("Bool Function returned {}", result1);
579592

580593
// test running a function that returns esp_err_t on a specific core
581594
auto task_fn3 = []() -> esp_err_t {
582595
auto core_id = xPortGetCoreID();
583-
fmt::print("esp_err_t Task running on core {}\n", core_id);
596+
fmt::println("esp_err_t Task running on core {}", core_id);
584597
return core_id == 1 ? ESP_OK : ESP_FAIL;
585598
};
586599
auto err0 = espp::task::run_on_core(task_fn3, 0, 3 * 1024);
587-
fmt::print("esp_err_t Function returned {}\n", esp_err_to_name(err0));
600+
fmt::println("esp_err_t Function returned {}", esp_err_to_name(err0));
588601
auto err1 = espp::task::run_on_core(task_fn3, 1, 3 * 1024);
589-
fmt::print("esp_err_t Function returned {}\n", esp_err_to_name(err1));
602+
fmt::println("esp_err_t Function returned {}", esp_err_to_name(err1));
590603
//! [run on core example]
591604
}
592605

@@ -600,13 +613,13 @@ extern "C" void app_main(void) {
600613

601614
// test running a function which takes a while to complete
602615
auto task_fn = []() -> void {
603-
fmt::print("[{0}] Task running on core {0}\n", xPortGetCoreID());
616+
fmt::println("[{0}] Task running on core {0}", xPortGetCoreID());
604617
std::this_thread::sleep_for(1s);
605-
fmt::print("[{0}] Task done!\n", xPortGetCoreID());
618+
fmt::println("[{0}] Task done!", xPortGetCoreID());
606619
};
607620
espp::task::run_on_core_non_blocking(task_fn, 0, 3 * 1024);
608621
espp::task::run_on_core_non_blocking(task_fn, {.name = "test", .core_id = 1});
609-
fmt::print("Started tasks on cores 0 and 1\n");
622+
fmt::println("Started tasks on cores 0 and 1");
610623

611624
// sleep for a bit to let the tasks run
612625
std::this_thread::sleep_for(2s);

0 commit comments

Comments
 (0)