// all the timers
static LIST_HEAD(esp_inactive_timer_list, esp_timer) s_inactive_timers =
LIST_HEAD_INITIALIZER(s_timers);
+// used to keep track of the timer when executing the callback
+static esp_timer_handle_t s_timer_in_callback;
#endif
// task used to dispatch timer callbacks
static TaskHandle_t s_timer_task;
// counting semaphore used to notify the timer task from ISR
static SemaphoreHandle_t s_timer_semaphore;
-// lock protecting s_timers and s_inactive_timers
+// lock protecting s_timers, s_inactive_timers, s_timer_in_callback
static portMUX_TYPE s_timer_lock = portMUX_INITIALIZER_UNLOCKED;
return ESP_ERR_INVALID_STATE;
}
#if WITH_PROFILING
+ if (timer == s_timer_in_callback) {
+ s_timer_in_callback = NULL;
+ }
timer_remove_inactive(timer);
#endif
if (timer == NULL) {
}
#if WITH_PROFILING
uint64_t callback_start = now;
+ s_timer_in_callback = it;
#endif
timer_list_unlock();
(*it->callback)(it->arg);
timer_list_lock();
now = esp_timer_impl_get_time();
#if WITH_PROFILING
- it->times_triggered++;
- it->total_callback_run_time += now - callback_start;
+ /* The callback might have deleted the timer.
+ * If this happens, esp_timer_delete will set s_timer_in_callback
+ * to NULL.
+ */
+ if (s_timer_in_callback) {
+ s_timer_in_callback->times_triggered++;
+ s_timer_in_callback->total_callback_run_time += now - callback_start;
+ }
#endif
it = LIST_FIRST(&s_timers);
}
#include <sys/time.h>
#include "unity.h"
#include "esp_timer.h"
+#include "esp_heap_caps.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
{
esp_timer_dump(stdout);
}
+
+TEST_CASE("Can delete timer from callback", "[esp_timer]")
+{
+ typedef struct {
+ SemaphoreHandle_t notify_from_timer_cb;
+ esp_timer_handle_t timer;
+ } test_arg_t;
+
+ void timer_func(void* varg)
+ {
+ test_arg_t arg = *(test_arg_t*) varg;
+ esp_timer_delete(arg.timer);
+ printf("Timer %p is deleted\n", arg.timer);
+ xSemaphoreGive(arg.notify_from_timer_cb);
+ }
+
+ test_arg_t args = {
+ .notify_from_timer_cb = xSemaphoreCreateBinary(),
+ };
+
+ esp_timer_create_args_t timer_args = {
+ .callback = &timer_func,
+ .arg = &args,
+ .name = "self_deleter"
+ };
+ esp_timer_create(&timer_args, &args.timer);
+ esp_timer_start_once(args.timer, 10000);
+
+ TEST_ASSERT_TRUE(xSemaphoreTake(args.notify_from_timer_cb, 1000 / portTICK_PERIOD_MS));
+ printf("Checking heap at %p\n", args.timer);
+ TEST_ASSERT_TRUE(heap_caps_check_integrity_addr((intptr_t) args.timer, true));
+
+ vSemaphoreDelete(args.notify_from_timer_cb);
+}