Merge branch 'feature/predictable_event_dispatch_via_duplication' into 'master'

Predictable event handler dispatch

See merge request idf/esp-idf!3932
This commit is contained in:
Angus Gratton 2019-02-05 08:47:03 +08:00
commit 4e770aec61
6 changed files with 608 additions and 511 deletions

View File

@ -30,12 +30,10 @@
/* ---------------------------- Definitions --------------------------------- */
#ifdef CONFIG_EVENT_LOOP_PROFILING
// loop@<address,name> rx:<total_recieved> dr:<total_dropped> inv:<total_number_of_invocations> run:<total_runtime>
#define LOOP_DUMP_FORMAT "loop@%p,%s rx:%u dr:%u inv:%u run:%lld us\n"
// event@<base:id> proc:<total_processed> run:<total_runtime>
#define EVENT_DUMP_FORMAT "\tevent@%s:%d proc:%u run:%lld us\n"
// handler@<address> inv:<total_invoked> run:<total_runtime>
#define HANDLER_DUMP_FORMAT "\t\thandler@%p inv:%u run:%lld us\n"
// LOOP @<address, name> rx:<recieved events no.> dr:<dropped events no.>
#define LOOP_DUMP_FORMAT "LOOP @%p,%s rx:%u dr:%u\n"
// handler @<address> ev:<base, id> inv:<times invoked> time:<runtime>
#define HANDLER_DUMP_FORMAT " HANDLER @%p ev:%s,%s inv:%u time:%lld us\n"
#define PRINT_DUMP_INFO(dst, sz, ...) do { \
int cb = snprintf(dst, sz, __VA_ARGS__); \
@ -63,33 +61,33 @@ static portMUX_TYPE s_event_loops_spinlock = portMUX_INITIALIZER_UNLOCKED;
static int esp_event_dump_prepare()
{
esp_event_loop_instance_t* loop_it;
esp_event_base_instance_t* base_it;
esp_event_id_instance_t* id_it;
esp_event_loop_node_t *loop_node_it;
esp_event_base_node_t* base_node_it;
esp_event_id_node_t* id_node_it;
esp_event_handler_instance_t* handler_it;
// Count the number of items to be printed. This is needed to compute how much memory to reserve.
int loops = 0, events = 0, handlers = 0;
int loops = 0, handlers = 0;
portENTER_CRITICAL(&s_event_loops_spinlock);
SLIST_FOREACH(loop_it, &s_event_loops, loop_entry) {
SLIST_FOREACH(handler_it, &(loop_it->loop_handlers), handler_entry) {
SLIST_FOREACH(loop_it, &s_event_loops, next) {
SLIST_FOREACH(loop_node_it, &(loop_it->loop_nodes), next) {
SLIST_FOREACH(handler_it, &(loop_node_it->handlers), next) {
handlers++;
}
SLIST_FOREACH(base_it, &(loop_it->event_bases), event_base_entry) {
SLIST_FOREACH(handler_it, &(base_it->base_handlers), handler_entry) {
SLIST_FOREACH(base_node_it, &(loop_node_it->base_nodes), next) {
SLIST_FOREACH(handler_it, &(base_node_it->handlers), next) {
handlers++;
}
// Print event-level handlers
SLIST_FOREACH(id_it, &(base_it->event_ids), event_id_entry) {
SLIST_FOREACH(handler_it, &(id_it->handlers), handler_entry) {
SLIST_FOREACH(id_node_it, &(base_node_it->id_nodes), next) {
SLIST_FOREACH(handler_it, &(id_node_it->handlers), next) {
handlers++;
}
events++;
}
events++;
}
events++;
}
loops++;
}
@ -97,9 +95,8 @@ static int esp_event_dump_prepare()
// Reserve slightly more memory than computed
int allowance = 3;
int size = (((loops + allowance) * (sizeof(LOOP_DUMP_FORMAT) + 10 + 20 + 3 * 11 + 20 )) +
((events + allowance) * (sizeof(EVENT_DUMP_FORMAT) + 10 + 20 + 11 + 20)) +
((handlers + allowance) * (sizeof(HANDLER_DUMP_FORMAT) + 10 + 11 + 20)));
int size = (((loops + allowance) * (sizeof(LOOP_DUMP_FORMAT) + 10 + 20 + 2 * 11)) +
((handlers + allowance) * (sizeof(HANDLER_DUMP_FORMAT) + 10 + 2 * 20 + 11 + 20)));
return size;
}
@ -123,167 +120,257 @@ static void esp_event_loop_run_task(void* args)
vTaskSuspend(NULL);
}
// Functions that operate on handler instance
static esp_event_handler_instance_t* handler_instance_create(esp_event_handler_t event_handler, void* event_handler_arg)
static void handler_execute(esp_event_loop_instance_t* loop, esp_event_handler_instance_t *handler, esp_event_post_instance_t post)
{
ESP_LOGD(TAG, "running post %s:%d with handler %p on loop %p", post.base, post.id, handler->handler, loop);
#ifdef CONFIG_EVENT_LOOP_PROFILING
int64_t start, diff;
start = esp_timer_get_time();
#endif
// Execute the handler
(*(handler->handler))(handler->arg, post.base, post.id, post.data);
#ifdef CONFIG_EVENT_LOOP_PROFILING
diff = esp_timer_get_time() - start;
xSemaphoreTake(loop->profiling_mutex, portMAX_DELAY);
handler->invoked++;
handler->time += diff;
xSemaphoreGive(loop->profiling_mutex);
#endif
}
static esp_err_t handler_instances_add(esp_event_handler_instances_t* handlers, esp_event_handler_t handler, void* handler_arg)
{
esp_event_handler_instance_t* handler_instance = calloc(1, sizeof(*handler_instance));
if (handler_instance != NULL) {
handler_instance->handler = event_handler;
handler_instance->arg = event_handler_arg;
if (!handler_instance) {
return ESP_ERR_NO_MEM;
}
return handler_instance;
handler_instance->handler = handler;
handler_instance->arg = handler_arg;
if(SLIST_EMPTY(handlers)) {
SLIST_INSERT_HEAD(handlers, handler_instance, next);
}
else {
esp_event_handler_instance_t *it = NULL, *last = NULL;
SLIST_FOREACH(it, handlers, next) {
if (handler == it->handler) {
it->arg = handler_arg;
ESP_LOGW(TAG, "handler already registered, overwriting");
return ESP_OK;
}
last = it;
}
static void handler_instance_delete(esp_event_handler_instance_t* handler_instance)
SLIST_INSERT_AFTER(last, handler_instance, next);
}
return ESP_OK;
}
static esp_err_t base_node_add_handler(esp_event_base_node_t* base_node, int32_t id, esp_event_handler_t handler, void* handler_arg)
{
free(handler_instance);
if (id == ESP_EVENT_ANY_ID) {
return handler_instances_add(&(base_node->handlers), handler, handler_arg);
}
else {
esp_err_t err = ESP_OK;
esp_event_id_node_t *it = NULL, *id_node = NULL, *last_id_node = NULL;
SLIST_FOREACH(it, &(base_node->id_nodes), next) {
if (it->id == id) {
id_node = it;
}
last_id_node = it;
}
// Functions that operate on handler instance list
static esp_event_handler_instance_t* handler_instances_find(esp_event_handler_instances_t* handlers, esp_event_handler_t handler)
{
esp_event_handler_instance_t* it;
if (!last_id_node || !id_node) {
id_node = (esp_event_id_node_t*) calloc(1, sizeof(*id_node));
SLIST_FOREACH(it, handlers, handler_entry) {
if (!id_node) {
ESP_LOGI(TAG, "alloc for new id node failed");
return ESP_ERR_NO_MEM;
}
id_node->id = id;
SLIST_INIT(&(id_node->handlers));
err = handler_instances_add(&(id_node->handlers), handler, handler_arg);
if (err == ESP_OK) {
if (!last_id_node) {
SLIST_INSERT_HEAD(&(base_node->id_nodes), id_node, next);
}
else {
SLIST_INSERT_AFTER(last_id_node, id_node, next);
}
}
return err;
}
else {
return handler_instances_add(&(id_node->handlers), handler, handler_arg);
}
}
}
static esp_err_t loop_node_add_handler(esp_event_loop_node_t* loop_node, esp_event_base_t base, int32_t id, esp_event_handler_t handler, void* handler_arg)
{
if (base == esp_event_any_base && id == ESP_EVENT_ANY_ID) {
return handler_instances_add(&(loop_node->handlers), handler, handler_arg);
}
else {
esp_err_t err = ESP_OK;
esp_event_base_node_t *it = NULL, *base_node = NULL, *last_base_node = NULL;
SLIST_FOREACH(it, &(loop_node->base_nodes), next) {
if (it->base == base) {
base_node = it;
}
last_base_node = it;
}
if (!last_base_node ||
!base_node ||
(base_node && !SLIST_EMPTY(&(base_node->id_nodes)) && id == ESP_EVENT_ANY_ID) ||
(last_base_node && last_base_node->base != base && !SLIST_EMPTY(&(last_base_node->id_nodes)) && id == ESP_EVENT_ANY_ID)) {
base_node = (esp_event_base_node_t*) calloc(1, sizeof(*base_node));
if (!base_node) {
ESP_LOGE(TAG, "alloc mem for new base node failed");
return ESP_ERR_NO_MEM;
}
base_node->base = base;
SLIST_INIT(&(base_node->handlers));
SLIST_INIT(&(base_node->id_nodes));
err = base_node_add_handler(base_node, id, handler, handler_arg);
if (err == ESP_OK) {
if (!last_base_node) {
SLIST_INSERT_HEAD(&(loop_node->base_nodes), base_node, next);
}
else {
SLIST_INSERT_AFTER(last_base_node, base_node, next);
}
}
return err;
} else {
return base_node_add_handler(base_node, id, handler, handler_arg);
}
}
}
static esp_err_t handler_instances_remove(esp_event_handler_instances_t* handlers, esp_event_handler_t handler)
{
esp_event_handler_instance_t *it, *temp;
SLIST_FOREACH_SAFE(it, handlers, next, temp) {
if (it->handler == handler) {
break;
SLIST_REMOVE(handlers, it, esp_event_handler_instance, next);
free(it);
return ESP_OK;
}
}
return it;
return ESP_ERR_NOT_FOUND;
}
static void handler_instances_add(esp_event_handler_instances_t* handlers, esp_event_handler_instance_t* handler_instance)
static esp_err_t base_node_remove_handler(esp_event_base_node_t* base_node, int32_t id, esp_event_handler_t handler)
{
SLIST_INSERT_HEAD(handlers, handler_instance, handler_entry);
if (id == ESP_EVENT_ANY_ID) {
return handler_instances_remove(&(base_node->handlers), handler);
}
else {
esp_event_id_node_t *it, *temp;
SLIST_FOREACH_SAFE(it, &(base_node->id_nodes), next, temp) {
if (it->id == id) {
esp_err_t res = handler_instances_remove(&(it->handlers), handler);
if (res == ESP_OK) {
if (SLIST_EMPTY(&(it->handlers))) {
SLIST_REMOVE(&(base_node->id_nodes), it, esp_event_id_node, next);
free(it);
return ESP_OK;
}
}
}
}
}
static void handler_instances_remove(esp_event_handler_instances_t* handlers, esp_event_handler_instance_t* handler_instance)
return ESP_ERR_NOT_FOUND;
}
static esp_err_t loop_node_remove_handler(esp_event_loop_node_t* loop_node, esp_event_base_t base, int32_t id, esp_event_handler_t handler)
{
SLIST_REMOVE(handlers, handler_instance, esp_event_handler_instance, handler_entry);
handler_instance_delete(handler_instance);
if (base == esp_event_any_base && id == ESP_EVENT_ANY_ID) {
return handler_instances_remove(&(loop_node->handlers), handler);
}
else {
esp_event_base_node_t *it, *temp;
SLIST_FOREACH_SAFE(it, &(loop_node->base_nodes), next, temp) {
if (it->base == base) {
esp_err_t res = base_node_remove_handler(it, id, handler);
if (res == ESP_OK) {
if (SLIST_EMPTY(&(it->handlers)) && SLIST_EMPTY(&(it->id_nodes))) {
SLIST_REMOVE(&(loop_node->base_nodes), it, esp_event_base_node, next);
free(it);
return ESP_OK;
}
}
}
}
}
return ESP_ERR_NOT_FOUND;
}
static void handler_instances_remove_all(esp_event_handler_instances_t* handlers)
{
esp_event_handler_instance_t* it;
esp_event_handler_instance_t* temp;
SLIST_FOREACH_SAFE(it, handlers, handler_entry, temp) {
handler_instances_remove(handlers, it);
esp_event_handler_instance_t *it, *temp;
SLIST_FOREACH_SAFE(it, handlers, next, temp) {
SLIST_REMOVE(handlers, it, esp_event_handler_instance, next);
free(it);
}
}
// Functions that operate on event id instance
static void* event_id_instance_create(int32_t event_id)
static void base_node_remove_all_handler(esp_event_base_node_t* base_node)
{
esp_event_id_instance_t* event_id_instance = calloc(1, sizeof(*event_id_instance));
handler_instances_remove_all(&(base_node->handlers));
if (event_id_instance != NULL) {
event_id_instance->id = event_id;
SLIST_INIT(&(event_id_instance->handlers));
esp_event_id_node_t *it, *temp;
SLIST_FOREACH_SAFE(it, &(base_node->id_nodes), next, temp) {
handler_instances_remove_all(&(it->handlers));
SLIST_REMOVE(&(base_node->id_nodes), it, esp_event_id_node, next);
free(it);
}
}
return event_id_instance;
}
static void event_id_instance_delete(esp_event_id_instance_t* event_id_instance)
static void loop_node_remove_all_handler(esp_event_loop_node_t* loop_node)
{
handler_instances_remove_all(&(event_id_instance->handlers));
free(event_id_instance);
}
handler_instances_remove_all(&(loop_node->handlers));
// Functions that operate on event id instance list
static void event_id_instances_remove(esp_event_id_instances_t* head, esp_event_id_instance_t* event_id_instance)
{
SLIST_REMOVE(head, event_id_instance, esp_event_id_instance, event_id_entry);
event_id_instance_delete(event_id_instance);
}
// Functions that operate on event base instance
static esp_event_base_instance_t* event_base_instance_create(esp_event_base_t event_base)
{
esp_event_base_instance_t* event_base_instance = calloc(1, sizeof(*event_base_instance));
if (event_base_instance != NULL) {
event_base_instance->base = event_base;
SLIST_INIT(&(event_base_instance->base_handlers));
SLIST_INIT(&(event_base_instance->event_ids));
}
return event_base_instance;
}
static void event_base_instance_delete(esp_event_base_instance_t* event_base_instance)
{
esp_event_id_instance_t* it;
esp_event_id_instance_t* temp;
handler_instances_remove_all(&(event_base_instance->base_handlers));
SLIST_FOREACH_SAFE(it, &(event_base_instance->event_ids), event_id_entry, temp) {
event_id_instances_remove(&(event_base_instance->event_ids), it);
}
free(event_base_instance);
}
static void event_base_instance_add_event_id_instance(esp_event_base_instance_t* event_base_instance, esp_event_id_instance_t* event_id_instance)
{
SLIST_INSERT_HEAD(&(event_base_instance->event_ids), event_id_instance, event_id_entry);
}
static esp_event_id_instance_t* event_base_instance_find_event_id_instance(esp_event_base_instance_t* event_base_instance, int32_t event_id)
{
esp_event_id_instance_t* it;
SLIST_FOREACH(it, &(event_base_instance->event_ids), event_id_entry) {
if (it->id == event_id) {
break;
esp_event_base_node_t *it, *temp;
SLIST_FOREACH_SAFE(it, &(loop_node->base_nodes), next, temp) {
base_node_remove_all_handler(it);
SLIST_REMOVE(&(loop_node->base_nodes), it, esp_event_base_node, next);
free(it);
}
}
return it;
}
// Functions that operate on event base instances list
static void event_base_instances_remove(esp_event_base_instances_t* head, esp_event_base_instance_t* event_base_instance)
{
SLIST_REMOVE(head, event_base_instance, esp_event_base_instance, event_base_entry);
event_base_instance_delete(event_base_instance);
}
// Functions that operate on loop instances
static void loop_add_event_base_instance(esp_event_loop_instance_t* loop, esp_event_base_instance_t* event_base_instance) {
SLIST_INSERT_HEAD(&(loop->event_bases), event_base_instance, event_base_entry);
}
static void loop_remove_all_event_base_instance(esp_event_loop_instance_t* loop)
{
esp_event_base_instance_t* it;
esp_event_base_instance_t* temp;
SLIST_FOREACH_SAFE(it, &(loop->event_bases), event_base_entry, temp) {
event_base_instances_remove(&(loop->event_bases), it);
}
}
static esp_event_base_instance_t* loop_find_event_base_instance(esp_event_loop_instance_t* loop, esp_event_base_t event_base)
{
esp_event_base_instance_t* it;
SLIST_FOREACH(it, &(loop->event_bases), event_base_entry) {
if (it->base == event_base) {
break;
}
}
return it;
}
// Functions that operate on post instance
static esp_err_t post_instance_create(esp_event_base_t event_base, int32_t event_id, void* event_data, int32_t event_data_size, esp_event_post_instance_t* post)
{
void* event_data_copy = NULL;
@ -314,33 +401,6 @@ static void post_instance_delete(esp_event_post_instance_t* post)
free(post->data);
}
static esp_event_handler_instances_t* find_handlers_list(esp_event_loop_instance_t* loop, esp_event_base_t event_base,
int32_t event_id)
{
esp_event_handler_instances_t* handlers = NULL;
esp_event_base_instance_t* base = NULL;
esp_event_id_instance_t* event = NULL;
if (event_base == esp_event_any_base && event_id == ESP_EVENT_ANY_ID) {
handlers = &(loop->loop_handlers);
} else {
base = loop_find_event_base_instance(loop, event_base);
if (base != NULL) {
if (event_id == ESP_EVENT_ANY_ID) {
handlers = &(base->base_handlers);
} else {
event = event_base_instance_find_event_id_instance(base, event_id);
if (event != NULL) {
handlers = &(event->handlers);
}
}
}
}
return handlers;
}
/* ---------------------------- Public API --------------------------------- */
esp_err_t esp_event_loop_create(const esp_event_loop_args_t* event_loop_args, esp_event_loop_handle_t* event_loop)
@ -376,8 +436,7 @@ esp_err_t esp_event_loop_create(const esp_event_loop_args_t* event_loop_args, es
}
#endif
SLIST_INIT(&(loop->loop_handlers));
SLIST_INIT(&(loop->event_bases));
SLIST_INIT(&(loop->loop_nodes));
// Create the loop task if requested
if (event_loop_args->task_name != NULL) {
@ -403,7 +462,7 @@ esp_err_t esp_event_loop_create(const esp_event_loop_args_t* event_loop_args, es
#ifdef CONFIG_EVENT_LOOP_PROFILING
portENTER_CRITICAL(&s_event_loops_spinlock);
SLIST_INSERT_HEAD(&s_event_loops, loop, loop_entry);
SLIST_INSERT_HEAD(&s_event_loops, loop, next);
portEXIT_CRITICAL(&s_event_loops_spinlock);
#endif
@ -447,7 +506,6 @@ esp_err_t esp_event_loop_run(esp_event_loop_handle_t event_loop, TickType_t tick
esp_event_post_instance_t post;
TickType_t marker = xTaskGetTickCount();
TickType_t end = 0;
esp_event_handler_instance_t* temp;
#if( configUSE_16_BIT_TICKS == 1 )
int32_t remaining_ticks = ticks_to_run;
@ -456,78 +514,48 @@ esp_err_t esp_event_loop_run(esp_event_loop_handle_t event_loop, TickType_t tick
#endif
while(xQueueReceive(loop->queue, &post, ticks_to_run) == pdTRUE) {
esp_event_base_instance_t* base = NULL;
esp_event_id_instance_t* event = NULL;
// Reserve space for three possible matches: (1) the entry for handlers registered to all events in the loop, the
// (2) entry matching events with a specified base and (3) the entry matching both base and id.
#define LOOP_LEVEL_HANDLER 0
#define BASE_LEVEL_HANDLER 1
#define EVENT_LEVEL_HANDLER 2
esp_event_handler_instances_t* handlers_list[EVENT_LEVEL_HANDLER + 1] = {0};
// The event has already been unqueued, so ensure it gets executed.
xSemaphoreTakeRecursive(loop->mutex, portMAX_DELAY);
loop->running_task = xTaskGetCurrentTaskHandle();
handlers_list[LOOP_LEVEL_HANDLER] = &(loop->loop_handlers);
base = loop_find_event_base_instance(loop, post.base);
if (base) {
event = event_base_instance_find_event_id_instance(base, post.id);
handlers_list[BASE_LEVEL_HANDLER] = &(base->base_handlers);
if (event) {
handlers_list[EVENT_LEVEL_HANDLER] = &(event->handlers);
}
}
bool exec = false;
for (int i = LOOP_LEVEL_HANDLER; i <= EVENT_LEVEL_HANDLER; i++) {
if (handlers_list[i] != NULL) {
esp_event_handler_instance_t* it;
esp_event_handler_instance_t *handler;
esp_event_loop_node_t *loop_node;
esp_event_base_node_t *base_node;
esp_event_id_node_t *id_node;
SLIST_FOREACH_SAFE(it, handlers_list[i], handler_entry, temp) {
ESP_LOGD(TAG, "running post %s:%d with handler %p on loop %p", post.base, post.id, it->handler, event_loop);
#ifdef CONFIG_EVENT_LOOP_PROFILING
int64_t start, diff;
start = esp_timer_get_time();
#endif
// Execute the handler
(*(it->handler))(it->arg, post.base, post.id, post.data);
#ifdef CONFIG_EVENT_LOOP_PROFILING
diff = esp_timer_get_time() - start;
xSemaphoreTake(loop->profiling_mutex, portMAX_DELAY);
it->total_times_invoked++;
it->total_runtime += diff;
if (i == LOOP_LEVEL_HANDLER) {
loop->loop_handlers_invoked++;
loop->loop_handlers_runtime += diff;
} else if (i == BASE_LEVEL_HANDLER) {
base->base_handlers_invoked++;
base->base_handlers_runtime += diff;
} else {
event->handlers_invoked++;
event->handlers_runtime += diff;
}
loop->total_handlers_invoked++;
loop->total_handlers_runtime += diff;
xSemaphoreGive(loop->profiling_mutex);
#endif
}
}
SLIST_FOREACH(loop_node, &(loop->loop_nodes), next) {
// Execute loop level handlers
SLIST_FOREACH(handler, &(loop_node->handlers), next) {
handler_execute(loop, handler, post);
exec |= true;
}
SLIST_FOREACH(base_node, &(loop_node->base_nodes), next) {
if (base_node->base == post.base) {
// Execute base level handlers
SLIST_FOREACH(handler, &(base_node->handlers), next) {
handler_execute(loop, handler, post);
exec |= true;
}
SLIST_FOREACH(id_node, &(base_node->id_nodes), next) {
if(id_node->id == post.id) {
// Execute id level handlers
SLIST_FOREACH(handler, &(id_node->handlers), next) {
handler_execute(loop, handler, post);
exec |= true;
}
// Skip to next base node
break;
}
}
}
}
}
post_instance_delete(&post);
if (ticks_to_run != portMAX_DELAY) {
@ -570,7 +598,7 @@ esp_err_t esp_event_loop_delete(esp_event_loop_handle_t event_loop)
#ifdef CONFIG_EVENT_LOOP_PROFILING
xSemaphoreTakeRecursive(loop->profiling_mutex, portMAX_DELAY);
portENTER_CRITICAL(&s_event_loops_spinlock);
SLIST_REMOVE(&s_event_loops, loop, esp_event_loop_instance, loop_entry);
SLIST_REMOVE(&s_event_loops, loop, esp_event_loop_instance, next);
portEXIT_CRITICAL(&s_event_loops_spinlock);
#endif
@ -579,9 +607,13 @@ esp_err_t esp_event_loop_delete(esp_event_loop_handle_t event_loop)
vTaskDelete(loop->task);
}
// Remove all registered events in the loop
handler_instances_remove_all(&(loop->loop_handlers));
loop_remove_all_event_base_instance(loop);
// Remove all registered events and handlers in the loop
esp_event_loop_node_t *it, *temp;
SLIST_FOREACH_SAFE(it, &(loop->loop_nodes), next, temp) {
loop_node_remove_all_handler(it);
SLIST_REMOVE(&(loop->loop_nodes), it, esp_event_loop_node, next);
free(it);
}
// Drop existing posts on the queue
esp_event_post_instance_t post;
@ -618,88 +650,54 @@ esp_err_t esp_event_handler_register_with(esp_event_loop_handle_t event_loop, es
esp_event_loop_instance_t* loop = (esp_event_loop_instance_t*) event_loop;
esp_event_base_instance_t* base = NULL;
esp_event_id_instance_t* event = NULL;
esp_event_handler_instance_t* handler = NULL;
esp_event_handler_instances_t* handlers = NULL;
bool base_created = false;
bool event_created = false;
if (event_base == ESP_EVENT_ANY_BASE) {
event_base = esp_event_any_base;
}
esp_err_t err = ESP_OK;
xSemaphoreTakeRecursive(loop->mutex, portMAX_DELAY);
if (event_base == esp_event_any_base && event_id == ESP_EVENT_ANY_ID) {
// Add to the loop-level handlers
handlers = &(loop->loop_handlers);
} else {
// If base instance does not exist, create one
if ((base = loop_find_event_base_instance(loop, event_base)) == NULL) {
base = event_base_instance_create(event_base);
if (base == NULL) {
xSemaphoreGiveRecursive(loop->mutex);
return ESP_ERR_NO_MEM;
}
base_created = true;
}
// Add to the event base instance level handlers
if (event_id == ESP_EVENT_ANY_ID) {
handlers = &(base->base_handlers);
} else {
if (base_created ||
(event = event_base_instance_find_event_id_instance(base, event_id)) == NULL) {
event = event_id_instance_create(event_id);
// If it does not exist, create one
if (event == NULL) {
if (base_created) {
event_base_instance_delete(base);
}
xSemaphoreGiveRecursive(loop->mutex);
return ESP_ERR_NO_MEM;
}
event_created = true;
}
// Add to the event id instance level handlers
handlers = &(event->handlers);
}
esp_event_loop_node_t *loop_node = NULL, *last_loop_node = NULL;
SLIST_FOREACH(loop_node, &(loop->loop_nodes), next) {
last_loop_node = loop_node;
}
// Add handler to the list
if (base_created || event_created ||
(handler = handler_instances_find(handlers, event_handler)) == NULL) {
handler = handler_instance_create(event_handler, event_handler_arg);
if (handler == NULL) {
if (event_created) {
event_id_instance_delete(event);
bool is_loop_level_handler = (event_base == esp_event_any_base) && (event_id == ESP_EVENT_ANY_ID);
if (!last_loop_node ||
(last_loop_node && !SLIST_EMPTY(&(last_loop_node->base_nodes)) && is_loop_level_handler)) {
loop_node = (esp_event_loop_node_t*) calloc(1, sizeof(*loop_node));
SLIST_INIT(&(loop_node->handlers));
SLIST_INIT(&(loop_node->base_nodes));
if (!loop_node) {
ESP_LOGE(TAG, "alloc for new loop node failed");
err = ESP_ERR_NO_MEM;
goto on_err;
}
if (base_created) {
event_base_instance_delete(base);
err = loop_node_add_handler(loop_node, event_base, event_id, event_handler, event_handler_arg);
if (err == ESP_OK) {
if (!last_loop_node) {
SLIST_INSERT_HEAD(&(loop->loop_nodes), loop_node, next);
}
else {
SLIST_INSERT_AFTER(last_loop_node, loop_node, next);
}
}
}
else {
err = loop_node_add_handler(last_loop_node, event_base, event_id, event_handler, event_handler_arg);
}
on_err:
xSemaphoreGiveRecursive(loop->mutex);
return ESP_ERR_NO_MEM;
return err;
}
handler_instances_add(handlers, handler);
// If a new event base/ event id instance was created, add them to the appropriate list
if (event_created) {
event_base_instance_add_event_id_instance(base, event);
}
if (base_created) {
loop_add_event_base_instance(loop, base);
}
ESP_LOGD(TAG, "registered handler %p for event %s:%d", event_handler, event_base, event_id);
} else {
handler->arg = event_handler_arg;
ESP_LOGW(TAG, "handler %p for event %s:%d already registered, overwriting", event_handler, event_base, event_id);
}
xSemaphoreGiveRecursive(loop->mutex);
return ESP_OK;
}
esp_err_t esp_event_handler_unregister_with(esp_event_loop_handle_t event_loop, esp_event_base_t event_base,
int32_t event_id, esp_event_handler_t event_handler)
@ -718,17 +716,18 @@ esp_err_t esp_event_handler_unregister_with(esp_event_loop_handle_t event_loop,
esp_event_loop_instance_t* loop = (esp_event_loop_instance_t*) event_loop;
esp_event_handler_instance_t* handler = NULL;
esp_event_handler_instances_t* handlers = find_handlers_list(loop, event_base, event_id);
xSemaphoreTakeRecursive(loop->mutex, portMAX_DELAY);
if (handlers != NULL &&
(handler = handler_instances_find(handlers, event_handler)) != NULL) {
handler_instances_remove(handlers, handler);
ESP_LOGD(TAG, "unregistered handler %p from event %s:%d", event_handler, event_base, event_id);
} else {
ESP_LOGW(TAG, "handler %p for event %s:%d not registered, ignoring", event_handler, event_base, event_id);
esp_event_loop_node_t *it, *temp;
SLIST_FOREACH_SAFE(it, &(loop->loop_nodes), next, temp) {
esp_err_t res = loop_node_remove_handler(it, event_base, event_id, event_handler);
if (res == ESP_OK && SLIST_EMPTY(&(it->base_nodes)) && SLIST_EMPTY(&(it->handlers))) {
SLIST_REMOVE(&(loop->loop_nodes), it, esp_event_loop_node, next);
free(it);
break;
}
}
xSemaphoreGiveRecursive(loop->mutex);
@ -804,14 +803,16 @@ esp_err_t esp_event_post_to(esp_event_loop_handle_t event_loop, esp_event_base_t
return ESP_OK;
}
esp_err_t esp_event_dump(FILE* file)
{
#ifdef CONFIG_EVENT_LOOP_PROFILING
assert(file);
esp_event_loop_instance_t* loop_it;
esp_event_base_instance_t* base_it;
esp_event_id_instance_t* id_it;
esp_event_loop_node_t *loop_node_it;
esp_event_base_node_t* base_node_it;
esp_event_id_node_t* id_node_it;
esp_event_handler_instance_t* handler_it;
// Allocate memory for printing
@ -819,41 +820,47 @@ esp_err_t esp_event_dump(FILE* file)
char* buf = calloc(sz, sizeof(char));
char* dst = buf;
char id_str_buf[20];
// Print info to buffer
portENTER_CRITICAL(&s_event_loops_spinlock);
SLIST_FOREACH(loop_it, &s_event_loops, loop_entry) {
PRINT_DUMP_INFO(dst, sz, LOOP_DUMP_FORMAT, loop_it, loop_it->name, loop_it->events_recieved,
loop_it->events_dropped, loop_it->total_handlers_invoked, loop_it->total_handlers_runtime);
// Print loop-level handler
PRINT_DUMP_INFO(dst, sz, esp_event_any_base, ESP_EVENT_ANY_ID, loop_it->loop_handlers_invoked,
loop_it->loop_handlers_runtime);
SLIST_FOREACH(handler_it, &(loop_it->loop_handlers), handler_entry) {
PRINT_DUMP_INFO(dst, sz, HANDLER_DUMP_FORMAT, handler_it->handler, handler_it->total_times_invoked,
handler_it->total_runtime);
SLIST_FOREACH(loop_it, &s_event_loops, next) {
PRINT_DUMP_INFO(dst, sz, LOOP_DUMP_FORMAT, loop_it, loop_it->task != NULL ? loop_it->name : "none" ,
loop_it->events_recieved, loop_it->events_dropped);
int sz_bak = sz;
SLIST_FOREACH(loop_node_it, &(loop_it->loop_nodes), next) {
SLIST_FOREACH(handler_it, &(loop_node_it->handlers), next) {
PRINT_DUMP_INFO(dst, sz, HANDLER_DUMP_FORMAT, handler_it->handler, "ESP_EVENT_ANY_BASE",
"ESP_EVENT_ANY_ID", handler_it->invoked, handler_it->time);
}
SLIST_FOREACH(base_it, &(loop_it->event_bases), event_base_entry) {
// Print base-level handler
PRINT_DUMP_INFO(dst, sz, EVENT_DUMP_FORMAT, base_it->base, ESP_EVENT_ANY_ID,
base_it->base_handlers_invoked, base_it->base_handlers_runtime);
SLIST_FOREACH(handler_it, &(base_it->base_handlers), handler_entry) {
PRINT_DUMP_INFO(dst, sz, HANDLER_DUMP_FORMAT, handler_it->handler,
handler_it->total_times_invoked, handler_it->total_runtime);
SLIST_FOREACH(base_node_it, &(loop_node_it->base_nodes), next) {
SLIST_FOREACH(handler_it, &(base_node_it->handlers), next) {
PRINT_DUMP_INFO(dst, sz, HANDLER_DUMP_FORMAT, handler_it->handler, base_node_it->base ,
"ESP_EVENT_ANY_ID", handler_it->invoked, handler_it->time);
}
// Print event-level handlers
SLIST_FOREACH(id_it, &(base_it->event_ids), event_id_entry) {
PRINT_DUMP_INFO(dst, sz, EVENT_DUMP_FORMAT, base_it->base, id_it->id,
id_it->handlers_invoked, id_it->handlers_runtime);
SLIST_FOREACH(id_node_it, &(base_node_it->id_nodes), next) {
SLIST_FOREACH(handler_it, &(id_node_it->handlers), next) {
memset(id_str_buf, 0, sizeof(id_str_buf));
snprintf(id_str_buf, sizeof(id_str_buf), "%d", id_node_it->id);
SLIST_FOREACH(handler_it, &(id_it->handlers), handler_entry) {
PRINT_DUMP_INFO(dst, sz, HANDLER_DUMP_FORMAT, handler_it->handler,
handler_it->total_times_invoked, handler_it->total_runtime);
PRINT_DUMP_INFO(dst, sz, HANDLER_DUMP_FORMAT, handler_it->handler, base_node_it->base ,
id_str_buf, handler_it->invoked, handler_it->time);
}
}
}
}
// No handlers registered for this loop
if (sz == sz_bak) {
PRINT_DUMP_INFO(dst, sz, " NO HANDLERS REGISTERED\n");
}
}
portEXIT_CRITICAL(&s_event_loops_spinlock);
// Print the contents of the buffer to the file

View File

@ -22,19 +22,43 @@ bool esp_event_is_handler_registered(esp_event_loop_handle_t event_loop, esp_eve
esp_event_loop_instance_t* loop = (esp_event_loop_instance_t*) event_loop;
bool result = false;
xSemaphoreTake(loop->mutex, portMAX_DELAY);
esp_event_base_instance_t* base_it;
SLIST_FOREACH(base_it, &(loop->event_bases), event_base_entry) {
esp_event_id_instance_t* event_it;
SLIST_FOREACH(event_it, &(base_it->event_ids), event_id_entry) {
esp_event_handler_instance_t* handler_it;
SLIST_FOREACH(handler_it, &(event_it->handlers), handler_entry) {
if (base_it->base == event_base && event_it->id == event_id && handler_it->handler == event_handler) {
esp_event_loop_node_t* loop_node;
esp_event_base_node_t* base_node;
esp_event_id_node_t* id_node;
esp_event_handler_instance_t* handler;
SLIST_FOREACH(loop_node, &(loop->loop_nodes), next) {
SLIST_FOREACH(handler, &(loop_node->handlers), next) {
if(event_base == ESP_EVENT_ANY_BASE && event_id == ESP_EVENT_ANY_ID && handler->handler == event_handler)
{
result = true;
goto out;
}
}
SLIST_FOREACH(base_node, &(loop_node->base_nodes), next) {
if (base_node->base == event_base) {
SLIST_FOREACH(handler, &(base_node->handlers), next) {
if(event_id == ESP_EVENT_ANY_ID && handler->handler == event_handler)
{
result = true;
goto out;
}
}
SLIST_FOREACH(id_node, &(base_node->id_nodes), next) {
if(id_node->id == event_id) {
SLIST_FOREACH(handler, &(id_node->handlers), next) {
if(handler->handler == event_handler)
{
result = true;
goto out;
}
}
}
}
}
}
}

View File

@ -139,7 +139,7 @@ esp_err_t esp_event_loop_run(esp_event_loop_handle_t event_loop, TickType_t tick
* @return
* - ESP_OK: Success
* - ESP_ERR_NO_MEM: Cannot allocate memory for the handler
* - ESP_ERR_INVALIG_ARG: Invalid combination of event base and event id
* - ESP_ERR_INVALID_ARG: Invalid combination of event base and event id
* - Others: Fail
*/
esp_err_t esp_event_handler_register(esp_event_base_t event_base,
@ -159,10 +159,13 @@ esp_err_t esp_event_handler_register(esp_event_base_t event_base,
* @param[in] event_handler the handler function which gets called when the event is dispatched
* @param[in] event_handler_arg data, aside from event data, that is passed to the handler when it is called
*
* @note the event loop library does not maintain a copy of event_handler_arg, therefore the user should
* ensure that event_handler_arg still points to a valid location by the time the handler gets called
*
* @return
* - ESP_OK: Success
* - ESP_ERR_NO_MEM: Cannot allocate memory for the handler
* - ESP_ERR_INVALIG_ARG: Invalid combination of event base and event id
* - ESP_ERR_INVALID_ARG: Invalid combination of event base and event id
* - Others: Fail
*/
esp_err_t esp_event_handler_register_with(esp_event_loop_handle_t event_loop,
@ -189,7 +192,7 @@ esp_err_t esp_event_handler_register_with(esp_event_loop_handle_t event_loop,
* @param[in] event_handler the handler to unregister
*
* @return ESP_OK success
* @return ESP_ERR_INVALIG_ARG invalid combination of event base and event id
* @return ESP_ERR_INVALID_ARG invalid combination of event base and event id
* @return others fail
*/
esp_err_t esp_event_handler_unregister(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler);
@ -207,7 +210,7 @@ esp_err_t esp_event_handler_unregister(esp_event_base_t event_base, int32_t even
*
* @return
* - ESP_OK: Success
* - ESP_ERR_INVALIG_ARG: Invalid combination of event base and event id
* - ESP_ERR_INVALID_ARG: Invalid combination of event base and event id
* - Others: Fail
*/
esp_err_t esp_event_handler_unregister_with(esp_event_loop_handle_t event_loop,
@ -231,7 +234,7 @@ esp_err_t esp_event_handler_unregister_with(esp_event_loop_handle_t event_loop,
* @return
* - ESP_OK: Success
* - ESP_ERR_TIMEOUT: Time to wait for event queue to unblock expired
* - ESP_ERR_INVALIG_ARG: Invalid combination of event base and event id
* - ESP_ERR_INVALID_ARG: Invalid combination of event base and event id
* - Others: Fail
*/
esp_err_t esp_event_post(esp_event_base_t event_base,
@ -260,7 +263,7 @@ esp_err_t esp_event_post(esp_event_base_t event_base,
* @return
* - ESP_OK: Success
* - ESP_ERR_TIMEOUT: Time to wait for event queue to unblock expired
* - ESP_ERR_INVALIG_ARG: Invalid combination of event base and event id
* - ESP_ERR_INVALID_ARG: Invalid combination of event base and event id
* - Others: Fail
*/
esp_err_t esp_event_post_to(esp_event_loop_handle_t event_loop,
@ -277,42 +280,29 @@ esp_err_t esp_event_post_to(esp_event_loop_handle_t event_loop,
*
@verbatim
event loop
event
handler
handler
event
handler
handler
...
event loop
event
handler
...
...
handler
...
where:
event loop
format: address,name rx:total_recieved dr:total_dropped inv:total_number_of_invocations run:total_runtime
format: address,name rx:total_recieved dr:total_dropped
where:
address - memory address of the event loop
name - name of the event loop
name - name of the event loop, 'none' if no dedicated task
total_recieved - number of successfully posted events
total_number_of_invocations - total number of handler invocations performed so far
total_runtime - total runtime of all invocations so far
event
format: base:id proc:total_processed run:total_runtime
where:
base - event base
id - event id
total_processed - number of instances of this event that has been processed
total_runtime - total amount of time in microseconds used for invoking handlers of this event
total_dropped - number of events unsucessfully posted due to queue being full
handler
format: address inv:total_invoked run:total_runtime
format: address ev:base,id inv:total_invoked run:total_runtime
where:
address - address of the handler function
base,id - the event specified by event base and id this handler executes
total_invoked - number of times this handler has been invoked
total_runtime - total amount of time used for invoking this handler

View File

@ -21,47 +21,50 @@
extern "C" {
#endif
typedef SLIST_HEAD(base_nodes, base_node) base_nodes_t;
/// Event handler
typedef struct esp_event_handler_instance {
esp_event_handler_t handler; /**< event handler function*/
void* arg; /**< event handler argument */
#ifdef CONFIG_EVENT_LOOP_PROFILING
uint32_t total_times_invoked; /**< number of times this handler has been invoked */
int64_t total_runtime; /**< total runtime of this handler across all calls */
uint32_t invoked; /**< number of times this handler has been invoked */
int64_t time; /**< total runtime of this handler across all calls */
#endif
SLIST_ENTRY(esp_event_handler_instance) handler_entry; /**< next event handler in the list */
SLIST_ENTRY(esp_event_handler_instance) next; /**< next event handler in the list */
} esp_event_handler_instance_t;
typedef SLIST_HEAD(esp_event_handler_instances, esp_event_handler_instance) esp_event_handler_instances_t;
typedef struct esp_event_id_instance {
int32_t id;
/// Event
typedef struct esp_event_id_node {
int32_t id; /**< id number of the event */
esp_event_handler_instances_t handlers; /**< list of handlers to be executed when
this event is raised */
SLIST_ENTRY(esp_event_id_instance) event_id_entry; /**< pointer to the next event node on the linked list */
#ifdef CONFIG_EVENT_LOOP_PROFILING
uint32_t handlers_invoked; /**< total number of times the event has been
raised and processed in the loop */
int64_t handlers_runtime; /**< total time spent in executing handlers */
#endif
} esp_event_id_instance_t;
SLIST_ENTRY(esp_event_id_node) next; /**< pointer to the next event node on the linked list */
} esp_event_id_node_t;
typedef SLIST_HEAD(esp_event_id_instances, esp_event_id_instance) esp_event_id_instances_t;
typedef SLIST_HEAD(esp_event_id_nodes, esp_event_id_node) esp_event_id_nodes_t;
/// Event
typedef struct esp_event_base_instance {
typedef struct esp_event_base_node {
esp_event_base_t base; /**< base identifier of the event */
esp_event_handler_instances_t base_handlers; /**< event base level handlers, handlers for
esp_event_handler_instances_t handlers; /**< event base level handlers, handlers for
all events with this base */
esp_event_id_instances_t event_ids; /**< list of event ids with this base */
SLIST_ENTRY(esp_event_base_instance) event_base_entry; /**< pointer to the next event node on the linked list */
#ifdef CONFIG_EVENT_LOOP_PROFILING
uint32_t base_handlers_invoked; /**< total number of base-level handlers invoked */
int64_t base_handlers_runtime; /**< amount of time processing base-level handlers */
#endif
} esp_event_base_instance_t;
esp_event_id_nodes_t id_nodes; /**< list of event ids with this base */
SLIST_ENTRY(esp_event_base_node) next; /**< pointer to the next base node on the linked list */
} esp_event_base_node_t;
typedef SLIST_HEAD(esp_event_base_instances, esp_event_base_instance) esp_event_base_instances_t;
typedef SLIST_HEAD(esp_event_base_nodes, esp_event_base_node) esp_event_base_nodes_t;
typedef struct esp_event_loop_node {
esp_event_handler_instances_t handlers; /** event loop level handlers */
esp_event_base_nodes_t base_nodes; /** list of event bases registered to the loop */
SLIST_ENTRY(esp_event_loop_node) next; /** pointer to the next loop node containing
event loop level handlers and the rest of
event bases registered to the loop */
} esp_event_loop_node_t;
typedef SLIST_HEAD(esp_event_loop_nodes, esp_event_loop_node) esp_event_loop_nodes_t;
/// Event loop
typedef struct esp_event_loop_instance {
@ -71,18 +74,13 @@ typedef struct esp_event_loop_instance {
TaskHandle_t running_task; /**< for loops with no dedicated task, the
task that consumes the queue */
SemaphoreHandle_t mutex; /**< mutex for updating the events linked list */
esp_event_handler_instances_t loop_handlers; /**< loop level handlers, handlers for all events
registered in the loop */
esp_event_base_instances_t event_bases; /**< events linked list head pointer */
esp_event_loop_nodes_t loop_nodes; /**< set of linked lists containing the
registered handlers for the loop */
#ifdef CONFIG_EVENT_LOOP_PROFILING
uint32_t events_recieved; /**< number of events successfully posted to the loop */
uint32_t events_dropped; /**< number of events dropped due to queue being full */
uint32_t loop_handlers_invoked; /**< total number of loop-level handlers invoked */
int64_t loop_handlers_runtime; /**< amount of time processing loop-level handlers */
uint32_t total_handlers_invoked; /**< total number of handlers invoked */
int64_t total_handlers_runtime; /**< total amount of time dedicated to processing this loop */
SLIST_ENTRY(esp_event_loop_instance) loop_entry; /**< next event loop in the list */
SemaphoreHandle_t profiling_mutex;
SemaphoreHandle_t profiling_mutex; /**< mutex used for profiliing */
SLIST_ENTRY(esp_event_loop_instance) next; /**< next event loop in the list */
#endif
} esp_event_loop_instance_t;

View File

@ -74,6 +74,11 @@ typedef struct {
SemaphoreHandle_t mutex;
} simple_arg_t;
typedef struct {
int *arr;
int index;
} ordered_data_t;
static BaseType_t s_test_core_id;
static UBaseType_t s_test_priority;
@ -135,6 +140,13 @@ static void test_event_simple_handler(void* event_handler_arg, esp_event_base_t
xSemaphoreGive(arg->mutex);
}
static void test_event_ordered_dispatch(void* event_handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
{
int *arg = (int*) event_handler_arg;
ordered_data_t *data = *((ordered_data_t**) (event_data));
data->arr[data->index++] = *arg;
}
static void test_event_performance_handler(void* event_handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
{
@ -1036,6 +1048,60 @@ TEST_CASE("can create and delete loop from handler", "[event]")
TEST_TEARDOWN();
}
TEST_CASE("events are dispatched in the order they are registered", "[event]")
{
TEST_SETUP();
esp_event_loop_handle_t loop;
esp_event_loop_args_t loop_args = test_event_get_default_loop_args();
loop_args.task_name = NULL;
TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_create(&loop_args, &loop));
int id_arr[7];
for (int i = 0; i < 7; i++) {
id_arr[i] = i;
}
int data_arr[12] = {0};
TEST_ASSERT_EQUAL(ESP_OK, esp_event_handler_register_with(loop, s_test_base2, TEST_EVENT_BASE2_EV1, test_event_ordered_dispatch, id_arr + 0));
TEST_ASSERT_EQUAL(ESP_OK, esp_event_handler_register_with(loop, ESP_EVENT_ANY_BASE, ESP_EVENT_ANY_ID, test_event_ordered_dispatch, id_arr + 1));
TEST_ASSERT_EQUAL(ESP_OK, esp_event_handler_register_with(loop, s_test_base1, ESP_EVENT_ANY_ID, test_event_ordered_dispatch, id_arr + 2));
TEST_ASSERT_EQUAL(ESP_OK, esp_event_handler_register_with(loop, s_test_base2, TEST_EVENT_BASE2_EV2, test_event_ordered_dispatch, id_arr + 3));
TEST_ASSERT_EQUAL(ESP_OK, esp_event_handler_register_with(loop, s_test_base1, TEST_EVENT_BASE1_EV1, test_event_ordered_dispatch, id_arr + 4));
TEST_ASSERT_EQUAL(ESP_OK, esp_event_handler_register_with(loop, s_test_base2, ESP_EVENT_ANY_ID, test_event_ordered_dispatch, id_arr + 5));
TEST_ASSERT_EQUAL(ESP_OK, esp_event_handler_register_with(loop, s_test_base1, TEST_EVENT_BASE1_EV2, test_event_ordered_dispatch, id_arr + 6));
esp_event_dump(stdout);
ordered_data_t data = {
.arr = data_arr,
.index = 0
};
ordered_data_t* dptr = &data;
TEST_ASSERT_EQUAL(ESP_OK, esp_event_post_to(loop, s_test_base2, TEST_EVENT_BASE1_EV2, &dptr, sizeof(dptr), portMAX_DELAY));
TEST_ASSERT_EQUAL(ESP_OK, esp_event_post_to(loop, s_test_base1, TEST_EVENT_BASE1_EV1, &dptr, sizeof(dptr), portMAX_DELAY));
TEST_ASSERT_EQUAL(ESP_OK, esp_event_post_to(loop, s_test_base1, TEST_EVENT_BASE1_EV2, &dptr, sizeof(dptr), portMAX_DELAY));
TEST_ASSERT_EQUAL(ESP_OK, esp_event_post_to(loop, s_test_base2, TEST_EVENT_BASE1_EV1, &dptr, sizeof(dptr), portMAX_DELAY));
TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_run(loop, pdMS_TO_TICKS(10)));
// Expected data executing the posts above
int ref_arr[12] = {1, 3, 5, 1, 2, 4, 1, 2, 6, 0, 1, 5};
for (int i = 0; i < 12; i++) {
TEST_ASSERT_EQUAL(ref_arr[i], data_arr[i]);
}
TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_delete(loop));
TEST_TEARDOWN();
}
#ifdef CONFIG_EVENT_LOOP_PROFILING
TEST_CASE("can dump event loop profile", "[event]")
{
@ -1060,6 +1126,7 @@ TEST_CASE("can dump event loop profile", "[event]")
TEST_ASSERT_EQUAL(ESP_OK, esp_event_handler_register_with(loop, ESP_EVENT_ANY_BASE, ESP_EVENT_ANY_ID, test_event_simple_handler, &arg));
TEST_ASSERT_EQUAL(ESP_OK, esp_event_handler_register_with(loop, s_test_base1, ESP_EVENT_ANY_ID, test_event_simple_handler, &arg));
TEST_ASSERT_EQUAL(ESP_OK, esp_event_handler_register_with(loop, s_test_base1, TEST_EVENT_BASE1_EV1, test_event_simple_handler, &arg));
TEST_ASSERT_EQUAL(ESP_OK, esp_event_handler_register_with(loop, s_test_base1, TEST_EVENT_BASE1_EV2, test_event_simple_handler, &arg));

View File

@ -186,6 +186,17 @@ If the hypothetical event ``MY_EVENT_BASE``, ``MY_OTHER_EVENT_ID`` is posted, on
If the hypothetical event ``MY_OTHER_EVENT_BASE``, ``MY_OTHER_EVENT_ID`` is posted, only ``run_on_event_3`` would execute.
Handler Registration and Handler Dispatch Order
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The general rule is that for handlers that match a certain posted event during dispatch, those which are registered first also gets executed first. The user can then control which handlers get executed first by
registering them before other handlers, provided that all registrations are performed using a single task.
If the user plans to take advantage of this behavior, caution must be exercised if there are multiple tasks registering handlers. While the 'first registered, first executed'
behavior still holds true, the task which gets executed first will also get their handlers registered first. Handlers registered one after the other by a single task
will still be dispatched in the order relative to each other, but if that task gets pre-empted in between registration by another task which also registers handlers; then during dispatch those
handlers will also get executed in between.
Event loop profiling
--------------------