mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
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:
commit
4e770aec61
@ -30,12 +30,10 @@
|
|||||||
/* ---------------------------- Definitions --------------------------------- */
|
/* ---------------------------- Definitions --------------------------------- */
|
||||||
|
|
||||||
#ifdef CONFIG_EVENT_LOOP_PROFILING
|
#ifdef CONFIG_EVENT_LOOP_PROFILING
|
||||||
// loop@<address,name> rx:<total_recieved> dr:<total_dropped> inv:<total_number_of_invocations> run:<total_runtime>
|
// LOOP @<address, name> rx:<recieved events no.> dr:<dropped events no.>
|
||||||
#define LOOP_DUMP_FORMAT "loop@%p,%s rx:%u dr:%u inv:%u run:%lld us\n"
|
#define LOOP_DUMP_FORMAT "LOOP @%p,%s rx:%u dr:%u\n"
|
||||||
// event@<base:id> proc:<total_processed> run:<total_runtime>
|
// handler @<address> ev:<base, id> inv:<times invoked> time:<runtime>
|
||||||
#define EVENT_DUMP_FORMAT "\tevent@%s:%d proc:%u run:%lld us\n"
|
#define HANDLER_DUMP_FORMAT " HANDLER @%p ev:%s,%s inv:%u time:%lld us\n"
|
||||||
// handler@<address> inv:<total_invoked> run:<total_runtime>
|
|
||||||
#define HANDLER_DUMP_FORMAT "\t\thandler@%p inv:%u run:%lld us\n"
|
|
||||||
|
|
||||||
#define PRINT_DUMP_INFO(dst, sz, ...) do { \
|
#define PRINT_DUMP_INFO(dst, sz, ...) do { \
|
||||||
int cb = snprintf(dst, sz, __VA_ARGS__); \
|
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()
|
static int esp_event_dump_prepare()
|
||||||
{
|
{
|
||||||
esp_event_loop_instance_t* loop_it;
|
esp_event_loop_instance_t* loop_it;
|
||||||
esp_event_base_instance_t* base_it;
|
esp_event_loop_node_t *loop_node_it;
|
||||||
esp_event_id_instance_t* id_it;
|
esp_event_base_node_t* base_node_it;
|
||||||
|
esp_event_id_node_t* id_node_it;
|
||||||
esp_event_handler_instance_t* handler_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.
|
// 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);
|
portENTER_CRITICAL(&s_event_loops_spinlock);
|
||||||
|
|
||||||
SLIST_FOREACH(loop_it, &s_event_loops, loop_entry) {
|
SLIST_FOREACH(loop_it, &s_event_loops, next) {
|
||||||
SLIST_FOREACH(handler_it, &(loop_it->loop_handlers), handler_entry) {
|
SLIST_FOREACH(loop_node_it, &(loop_it->loop_nodes), next) {
|
||||||
handlers++;
|
SLIST_FOREACH(handler_it, &(loop_node_it->handlers), next) {
|
||||||
}
|
|
||||||
SLIST_FOREACH(base_it, &(loop_it->event_bases), event_base_entry) {
|
|
||||||
SLIST_FOREACH(handler_it, &(base_it->base_handlers), handler_entry) {
|
|
||||||
handlers++;
|
handlers++;
|
||||||
}
|
}
|
||||||
// Print event-level handlers
|
|
||||||
SLIST_FOREACH(id_it, &(base_it->event_ids), event_id_entry) {
|
SLIST_FOREACH(base_node_it, &(loop_node_it->base_nodes), next) {
|
||||||
SLIST_FOREACH(handler_it, &(id_it->handlers), handler_entry) {
|
SLIST_FOREACH(handler_it, &(base_node_it->handlers), next) {
|
||||||
handlers++;
|
handlers++;
|
||||||
}
|
}
|
||||||
events++;
|
SLIST_FOREACH(id_node_it, &(base_node_it->id_nodes), next) {
|
||||||
|
SLIST_FOREACH(handler_it, &(id_node_it->handlers), next) {
|
||||||
|
handlers++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
events++;
|
|
||||||
}
|
}
|
||||||
events++;
|
|
||||||
loops++;
|
loops++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,9 +95,8 @@ static int esp_event_dump_prepare()
|
|||||||
|
|
||||||
// Reserve slightly more memory than computed
|
// Reserve slightly more memory than computed
|
||||||
int allowance = 3;
|
int allowance = 3;
|
||||||
int size = (((loops + allowance) * (sizeof(LOOP_DUMP_FORMAT) + 10 + 20 + 3 * 11 + 20 )) +
|
int size = (((loops + allowance) * (sizeof(LOOP_DUMP_FORMAT) + 10 + 20 + 2 * 11)) +
|
||||||
((events + allowance) * (sizeof(EVENT_DUMP_FORMAT) + 10 + 20 + 11 + 20)) +
|
((handlers + allowance) * (sizeof(HANDLER_DUMP_FORMAT) + 10 + 2 * 20 + 11 + 20)));
|
||||||
((handlers + allowance) * (sizeof(HANDLER_DUMP_FORMAT) + 10 + 11 + 20)));
|
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
@ -123,167 +120,257 @@ static void esp_event_loop_run_task(void* args)
|
|||||||
vTaskSuspend(NULL);
|
vTaskSuspend(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Functions that operate on handler instance
|
static void handler_execute(esp_event_loop_instance_t* loop, esp_event_handler_instance_t *handler, esp_event_post_instance_t post)
|
||||||
static esp_event_handler_instance_t* handler_instance_create(esp_event_handler_t event_handler, void* event_handler_arg)
|
{
|
||||||
|
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));
|
esp_event_handler_instance_t* handler_instance = calloc(1, sizeof(*handler_instance));
|
||||||
|
|
||||||
if (handler_instance != NULL) {
|
if (!handler_instance) {
|
||||||
handler_instance->handler = event_handler;
|
return ESP_ERR_NO_MEM;
|
||||||
handler_instance->arg = event_handler_arg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
SLIST_INSERT_AFTER(last, handler_instance, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handler_instance_delete(esp_event_handler_instance_t* handler_instance)
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!last_id_node || !id_node) {
|
||||||
|
id_node = (esp_event_id_node_t*) calloc(1, sizeof(*id_node));
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Functions that operate on handler instance list
|
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)
|
||||||
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 (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, handlers, handler_entry) {
|
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) {
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_ERR_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handler_instances_remove(esp_event_handler_instances_t* handlers, esp_event_handler_instance_t* handler_instance)
|
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);
|
if (base == esp_event_any_base && id == ESP_EVENT_ANY_ID) {
|
||||||
handler_instance_delete(handler_instance);
|
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)
|
static void handler_instances_remove_all(esp_event_handler_instances_t* handlers)
|
||||||
{
|
{
|
||||||
esp_event_handler_instance_t* it;
|
esp_event_handler_instance_t *it, *temp;
|
||||||
esp_event_handler_instance_t* temp;
|
SLIST_FOREACH_SAFE(it, handlers, next, temp) {
|
||||||
|
SLIST_REMOVE(handlers, it, esp_event_handler_instance, next);
|
||||||
SLIST_FOREACH_SAFE(it, handlers, handler_entry, temp) {
|
free(it);
|
||||||
handler_instances_remove(handlers, it);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Functions that operate on event id instance
|
static void base_node_remove_all_handler(esp_event_base_node_t* base_node)
|
||||||
static void* event_id_instance_create(int32_t event_id)
|
|
||||||
{
|
{
|
||||||
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) {
|
esp_event_id_node_t *it, *temp;
|
||||||
event_id_instance->id = event_id;
|
SLIST_FOREACH_SAFE(it, &(base_node->id_nodes), next, temp) {
|
||||||
SLIST_INIT(&(event_id_instance->handlers));
|
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)
|
|
||||||
{
|
|
||||||
handler_instances_remove_all(&(event_id_instance->handlers));
|
|
||||||
free(event_id_instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
static void loop_node_remove_all_handler(esp_event_loop_node_t* loop_node)
|
||||||
{
|
{
|
||||||
esp_event_base_instance_t* it;
|
handler_instances_remove_all(&(loop_node->handlers));
|
||||||
|
|
||||||
SLIST_FOREACH(it, &(loop->event_bases), event_base_entry) {
|
esp_event_base_node_t *it, *temp;
|
||||||
if (it->base == event_base) {
|
SLIST_FOREACH_SAFE(it, &(loop_node->base_nodes), next, temp) {
|
||||||
break;
|
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 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)
|
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;
|
void* event_data_copy = NULL;
|
||||||
@ -314,33 +401,6 @@ static void post_instance_delete(esp_event_post_instance_t* post)
|
|||||||
free(post->data);
|
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 --------------------------------- */
|
/* ---------------------------- 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)
|
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
|
#endif
|
||||||
|
|
||||||
SLIST_INIT(&(loop->loop_handlers));
|
SLIST_INIT(&(loop->loop_nodes));
|
||||||
SLIST_INIT(&(loop->event_bases));
|
|
||||||
|
|
||||||
// Create the loop task if requested
|
// Create the loop task if requested
|
||||||
if (event_loop_args->task_name != NULL) {
|
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
|
#ifdef CONFIG_EVENT_LOOP_PROFILING
|
||||||
portENTER_CRITICAL(&s_event_loops_spinlock);
|
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);
|
portEXIT_CRITICAL(&s_event_loops_spinlock);
|
||||||
#endif
|
#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;
|
esp_event_post_instance_t post;
|
||||||
TickType_t marker = xTaskGetTickCount();
|
TickType_t marker = xTaskGetTickCount();
|
||||||
TickType_t end = 0;
|
TickType_t end = 0;
|
||||||
esp_event_handler_instance_t* temp;
|
|
||||||
|
|
||||||
#if( configUSE_16_BIT_TICKS == 1 )
|
#if( configUSE_16_BIT_TICKS == 1 )
|
||||||
int32_t remaining_ticks = ticks_to_run;
|
int32_t remaining_ticks = ticks_to_run;
|
||||||
@ -456,76 +514,46 @@ esp_err_t esp_event_loop_run(esp_event_loop_handle_t event_loop, TickType_t tick
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
while(xQueueReceive(loop->queue, &post, ticks_to_run) == pdTRUE) {
|
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.
|
// The event has already been unqueued, so ensure it gets executed.
|
||||||
xSemaphoreTakeRecursive(loop->mutex, portMAX_DELAY);
|
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);
|
loop->running_task = xTaskGetCurrentTaskHandle();
|
||||||
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;
|
bool exec = false;
|
||||||
|
|
||||||
for (int i = LOOP_LEVEL_HANDLER; i <= EVENT_LEVEL_HANDLER; i++) {
|
esp_event_handler_instance_t *handler;
|
||||||
if (handlers_list[i] != NULL) {
|
esp_event_loop_node_t *loop_node;
|
||||||
esp_event_handler_instance_t* it;
|
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
|
SLIST_FOREACH(loop_node, &(loop->loop_nodes), next) {
|
||||||
int64_t start, diff;
|
// Execute loop level handlers
|
||||||
start = esp_timer_get_time();
|
SLIST_FOREACH(handler, &(loop_node->handlers), next) {
|
||||||
#endif
|
handler_execute(loop, handler, post);
|
||||||
// Execute the handler
|
exec |= true;
|
||||||
(*(it->handler))(it->arg, post.base, post.id, post.data);
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_EVENT_LOOP_PROFILING
|
SLIST_FOREACH(base_node, &(loop_node->base_nodes), next) {
|
||||||
diff = esp_timer_get_time() - start;
|
if (base_node->base == post.base) {
|
||||||
|
// Execute base level handlers
|
||||||
xSemaphoreTake(loop->profiling_mutex, portMAX_DELAY);
|
SLIST_FOREACH(handler, &(base_node->handlers), next) {
|
||||||
|
handler_execute(loop, handler, post);
|
||||||
it->total_times_invoked++;
|
exec |= true;
|
||||||
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++;
|
SLIST_FOREACH(id_node, &(base_node->id_nodes), next) {
|
||||||
loop->total_handlers_runtime += diff;
|
if(id_node->id == post.id) {
|
||||||
|
// Execute id level handlers
|
||||||
xSemaphoreGive(loop->profiling_mutex);
|
SLIST_FOREACH(handler, &(id_node->handlers), next) {
|
||||||
#endif
|
handler_execute(loop, handler, post);
|
||||||
|
exec |= true;
|
||||||
|
}
|
||||||
|
// Skip to next base node
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exec |= true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
post_instance_delete(&post);
|
post_instance_delete(&post);
|
||||||
@ -570,7 +598,7 @@ esp_err_t esp_event_loop_delete(esp_event_loop_handle_t event_loop)
|
|||||||
#ifdef CONFIG_EVENT_LOOP_PROFILING
|
#ifdef CONFIG_EVENT_LOOP_PROFILING
|
||||||
xSemaphoreTakeRecursive(loop->profiling_mutex, portMAX_DELAY);
|
xSemaphoreTakeRecursive(loop->profiling_mutex, portMAX_DELAY);
|
||||||
portENTER_CRITICAL(&s_event_loops_spinlock);
|
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);
|
portEXIT_CRITICAL(&s_event_loops_spinlock);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -579,9 +607,13 @@ esp_err_t esp_event_loop_delete(esp_event_loop_handle_t event_loop)
|
|||||||
vTaskDelete(loop->task);
|
vTaskDelete(loop->task);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all registered events in the loop
|
// Remove all registered events and handlers in the loop
|
||||||
handler_instances_remove_all(&(loop->loop_handlers));
|
esp_event_loop_node_t *it, *temp;
|
||||||
loop_remove_all_event_base_instance(loop);
|
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
|
// Drop existing posts on the queue
|
||||||
esp_event_post_instance_t post;
|
esp_event_post_instance_t post;
|
||||||
@ -618,89 +650,55 @@ 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_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) {
|
if (event_base == ESP_EVENT_ANY_BASE) {
|
||||||
event_base = esp_event_any_base;
|
event_base = esp_event_any_base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
esp_err_t err = ESP_OK;
|
||||||
|
|
||||||
xSemaphoreTakeRecursive(loop->mutex, portMAX_DELAY);
|
xSemaphoreTakeRecursive(loop->mutex, portMAX_DELAY);
|
||||||
|
|
||||||
if (event_base == esp_event_any_base && event_id == ESP_EVENT_ANY_ID) {
|
esp_event_loop_node_t *loop_node = NULL, *last_loop_node = NULL;
|
||||||
// Add to the loop-level handlers
|
|
||||||
handlers = &(loop->loop_handlers);
|
SLIST_FOREACH(loop_node, &(loop->loop_nodes), next) {
|
||||||
} else {
|
last_loop_node = loop_node;
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add handler to the list
|
bool is_loop_level_handler = (event_base == esp_event_any_base) && (event_id == ESP_EVENT_ANY_ID);
|
||||||
if (base_created || event_created ||
|
|
||||||
(handler = handler_instances_find(handlers, event_handler)) == NULL) {
|
if (!last_loop_node ||
|
||||||
handler = handler_instance_create(event_handler, event_handler_arg);
|
(last_loop_node && !SLIST_EMPTY(&(last_loop_node->base_nodes)) && is_loop_level_handler)) {
|
||||||
if (handler == NULL) {
|
loop_node = (esp_event_loop_node_t*) calloc(1, sizeof(*loop_node));
|
||||||
if (event_created) {
|
|
||||||
event_id_instance_delete(event);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
if (base_created) {
|
else {
|
||||||
event_base_instance_delete(base);
|
SLIST_INSERT_AFTER(last_loop_node, loop_node, next);
|
||||||
}
|
}
|
||||||
xSemaphoreGiveRecursive(loop->mutex);
|
|
||||||
return ESP_ERR_NO_MEM;
|
|
||||||
}
|
}
|
||||||
handler_instances_add(handlers, handler);
|
}
|
||||||
// If a new event base/ event id instance was created, add them to the appropriate list
|
else {
|
||||||
if (event_created) {
|
err = loop_node_add_handler(last_loop_node, event_base, event_id, event_handler, event_handler_arg);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
on_err:
|
||||||
xSemaphoreGiveRecursive(loop->mutex);
|
xSemaphoreGiveRecursive(loop->mutex);
|
||||||
|
return err;
|
||||||
return ESP_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
esp_err_t esp_event_handler_unregister_with(esp_event_loop_handle_t event_loop, esp_event_base_t event_base,
|
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)
|
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_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);
|
xSemaphoreTakeRecursive(loop->mutex, portMAX_DELAY);
|
||||||
|
|
||||||
if (handlers != NULL &&
|
esp_event_loop_node_t *it, *temp;
|
||||||
(handler = handler_instances_find(handlers, event_handler)) != NULL) {
|
|
||||||
handler_instances_remove(handlers, handler);
|
SLIST_FOREACH_SAFE(it, &(loop->loop_nodes), next, temp) {
|
||||||
ESP_LOGD(TAG, "unregistered handler %p from event %s:%d", event_handler, event_base, event_id);
|
esp_err_t res = loop_node_remove_handler(it, event_base, event_id, event_handler);
|
||||||
} else {
|
|
||||||
ESP_LOGW(TAG, "handler %p for event %s:%d not registered, ignoring", event_handler, event_base, event_id);
|
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);
|
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;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
esp_err_t esp_event_dump(FILE* file)
|
esp_err_t esp_event_dump(FILE* file)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_EVENT_LOOP_PROFILING
|
#ifdef CONFIG_EVENT_LOOP_PROFILING
|
||||||
assert(file);
|
assert(file);
|
||||||
|
|
||||||
esp_event_loop_instance_t* loop_it;
|
esp_event_loop_instance_t* loop_it;
|
||||||
esp_event_base_instance_t* base_it;
|
esp_event_loop_node_t *loop_node_it;
|
||||||
esp_event_id_instance_t* id_it;
|
esp_event_base_node_t* base_node_it;
|
||||||
|
esp_event_id_node_t* id_node_it;
|
||||||
esp_event_handler_instance_t* handler_it;
|
esp_event_handler_instance_t* handler_it;
|
||||||
|
|
||||||
// Allocate memory for printing
|
// Allocate memory for printing
|
||||||
@ -819,46 +820,52 @@ esp_err_t esp_event_dump(FILE* file)
|
|||||||
char* buf = calloc(sz, sizeof(char));
|
char* buf = calloc(sz, sizeof(char));
|
||||||
char* dst = buf;
|
char* dst = buf;
|
||||||
|
|
||||||
|
char id_str_buf[20];
|
||||||
|
|
||||||
// Print info to buffer
|
// Print info to buffer
|
||||||
portENTER_CRITICAL(&s_event_loops_spinlock);
|
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
|
SLIST_FOREACH(loop_it, &s_event_loops, next) {
|
||||||
PRINT_DUMP_INFO(dst, sz, esp_event_any_base, ESP_EVENT_ANY_ID, loop_it->loop_handlers_invoked,
|
PRINT_DUMP_INFO(dst, sz, LOOP_DUMP_FORMAT, loop_it, loop_it->task != NULL ? loop_it->name : "none" ,
|
||||||
loop_it->loop_handlers_runtime);
|
loop_it->events_recieved, loop_it->events_dropped);
|
||||||
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(base_it, &(loop_it->event_bases), event_base_entry) {
|
int sz_bak = sz;
|
||||||
// Print base-level handler
|
|
||||||
PRINT_DUMP_INFO(dst, sz, EVENT_DUMP_FORMAT, base_it->base, ESP_EVENT_ANY_ID,
|
SLIST_FOREACH(loop_node_it, &(loop_it->loop_nodes), next) {
|
||||||
base_it->base_handlers_invoked, base_it->base_handlers_runtime);
|
SLIST_FOREACH(handler_it, &(loop_node_it->handlers), next) {
|
||||||
SLIST_FOREACH(handler_it, &(base_it->base_handlers), handler_entry) {
|
PRINT_DUMP_INFO(dst, sz, HANDLER_DUMP_FORMAT, handler_it->handler, "ESP_EVENT_ANY_BASE",
|
||||||
PRINT_DUMP_INFO(dst, sz, HANDLER_DUMP_FORMAT, handler_it->handler,
|
"ESP_EVENT_ANY_ID", handler_it->invoked, handler_it->time);
|
||||||
handler_it->total_times_invoked, handler_it->total_runtime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print event-level handlers
|
SLIST_FOREACH(base_node_it, &(loop_node_it->base_nodes), next) {
|
||||||
SLIST_FOREACH(id_it, &(base_it->event_ids), event_id_entry) {
|
SLIST_FOREACH(handler_it, &(base_node_it->handlers), next) {
|
||||||
PRINT_DUMP_INFO(dst, sz, EVENT_DUMP_FORMAT, base_it->base, id_it->id,
|
PRINT_DUMP_INFO(dst, sz, HANDLER_DUMP_FORMAT, handler_it->handler, base_node_it->base ,
|
||||||
id_it->handlers_invoked, id_it->handlers_runtime);
|
"ESP_EVENT_ANY_ID", handler_it->invoked, handler_it->time);
|
||||||
|
}
|
||||||
|
|
||||||
SLIST_FOREACH(handler_it, &(id_it->handlers), handler_entry) {
|
SLIST_FOREACH(id_node_it, &(base_node_it->id_nodes), next) {
|
||||||
PRINT_DUMP_INFO(dst, sz, HANDLER_DUMP_FORMAT, handler_it->handler,
|
SLIST_FOREACH(handler_it, &(id_node_it->handlers), next) {
|
||||||
handler_it->total_times_invoked, handler_it->total_runtime);
|
memset(id_str_buf, 0, sizeof(id_str_buf));
|
||||||
|
snprintf(id_str_buf, sizeof(id_str_buf), "%d", id_node_it->id);
|
||||||
|
|
||||||
|
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);
|
portEXIT_CRITICAL(&s_event_loops_spinlock);
|
||||||
|
|
||||||
// Print the contents of the buffer to the file
|
// Print the contents of the buffer to the file
|
||||||
fprintf(file, buf);
|
fprintf(file, buf);
|
||||||
|
|
||||||
// Free the allocated buffer
|
// Free the allocated buffer
|
||||||
free(buf);
|
free(buf);
|
||||||
#endif
|
#endif
|
||||||
|
@ -22,17 +22,41 @@ 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;
|
esp_event_loop_instance_t* loop = (esp_event_loop_instance_t*) event_loop;
|
||||||
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
xSemaphoreTake(loop->mutex, portMAX_DELAY);
|
|
||||||
|
|
||||||
esp_event_base_instance_t* base_it;
|
esp_event_loop_node_t* loop_node;
|
||||||
SLIST_FOREACH(base_it, &(loop->event_bases), event_base_entry) {
|
esp_event_base_node_t* base_node;
|
||||||
esp_event_id_instance_t* event_it;
|
esp_event_id_node_t* id_node;
|
||||||
SLIST_FOREACH(event_it, &(base_it->event_ids), event_id_entry) {
|
esp_event_handler_instance_t* handler;
|
||||||
esp_event_handler_instance_t* handler_it;
|
|
||||||
SLIST_FOREACH(handler_it, &(event_it->handlers), handler_entry) {
|
SLIST_FOREACH(loop_node, &(loop->loop_nodes), next) {
|
||||||
if (base_it->base == event_base && event_it->id == event_id && handler_it->handler == event_handler) {
|
SLIST_FOREACH(handler, &(loop_node->handlers), next) {
|
||||||
result = true;
|
if(event_base == ESP_EVENT_ANY_BASE && event_id == ESP_EVENT_ANY_ID && handler->handler == event_handler)
|
||||||
goto out;
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,11 +33,11 @@ extern "C" {
|
|||||||
/// Configuration for creating event loops
|
/// Configuration for creating event loops
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int32_t queue_size; /**< size of the event loop queue */
|
int32_t queue_size; /**< size of the event loop queue */
|
||||||
const char* task_name; /**< name of the event loop task; if NULL,
|
const char* task_name; /**< name of the event loop task; if NULL,
|
||||||
a dedicated task is not created for event loop*/
|
a dedicated task is not created for event loop*/
|
||||||
UBaseType_t task_priority; /**< priority of the event loop task, ignored if task name is NULL */
|
UBaseType_t task_priority; /**< priority of the event loop task, ignored if task name is NULL */
|
||||||
uint32_t task_stack_size; /**< stack size of the event loop task, ignored if task name is NULL */
|
uint32_t task_stack_size; /**< stack size of the event loop task, ignored if task name is NULL */
|
||||||
BaseType_t task_core_id; /**< core to which the event loop task is pinned to,
|
BaseType_t task_core_id; /**< core to which the event loop task is pinned to,
|
||||||
ignored if task name is NULL */
|
ignored if task name is NULL */
|
||||||
} esp_event_loop_args_t;
|
} esp_event_loop_args_t;
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ typedef struct {
|
|||||||
* @param[in] event_loop_args configuration structure for the event loop to create
|
* @param[in] event_loop_args configuration structure for the event loop to create
|
||||||
* @param[out] event_loop handle to the created event loop
|
* @param[out] event_loop handle to the created event loop
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: Success
|
* - ESP_OK: Success
|
||||||
* - ESP_ERR_NO_MEM: Cannot allocate memory for event loops list
|
* - ESP_ERR_NO_MEM: Cannot allocate memory for event loops list
|
||||||
* - ESP_FAIL: Failed to create task loop
|
* - ESP_FAIL: Failed to create task loop
|
||||||
@ -60,7 +60,7 @@ esp_err_t esp_event_loop_create(const esp_event_loop_args_t* event_loop_args, es
|
|||||||
*
|
*
|
||||||
* @param[in] event_loop event loop to delete
|
* @param[in] event_loop event loop to delete
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: Success
|
* - ESP_OK: Success
|
||||||
* - Others: Fail
|
* - Others: Fail
|
||||||
*/
|
*/
|
||||||
@ -68,8 +68,8 @@ esp_err_t esp_event_loop_delete(esp_event_loop_handle_t event_loop);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create default event loop
|
* @brief Create default event loop
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: Success
|
* - ESP_OK: Success
|
||||||
* - ESP_ERR_NO_MEM: Cannot allocate memory for event loops list
|
* - ESP_ERR_NO_MEM: Cannot allocate memory for event loops list
|
||||||
* - ESP_FAIL: Failed to create task loop
|
* - ESP_FAIL: Failed to create task loop
|
||||||
@ -79,8 +79,8 @@ esp_err_t esp_event_loop_create_default();
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Delete the default event loop
|
* @brief Delete the default event loop
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: Success
|
* - ESP_OK: Success
|
||||||
* - Others: Fail
|
* - Others: Fail
|
||||||
*/
|
*/
|
||||||
@ -89,18 +89,18 @@ esp_err_t esp_event_loop_delete_default();
|
|||||||
/**
|
/**
|
||||||
* @brief Dispatch events posted to an event loop.
|
* @brief Dispatch events posted to an event loop.
|
||||||
*
|
*
|
||||||
* This function is used to dispatch events posted to a loop with no dedicated task, i.e task name was set to NULL
|
* This function is used to dispatch events posted to a loop with no dedicated task, i.e task name was set to NULL
|
||||||
* in event_loop_args argument during loop creation. This function includes an argument to limit the amount of time
|
* in event_loop_args argument during loop creation. This function includes an argument to limit the amount of time
|
||||||
* it runs, returning control to the caller when that time expires (or some time afterwards). There is no guarantee
|
* it runs, returning control to the caller when that time expires (or some time afterwards). There is no guarantee
|
||||||
* that a call to this function will exit at exactly the time of expiry. There is also no guarantee that events have
|
* that a call to this function will exit at exactly the time of expiry. There is also no guarantee that events have
|
||||||
* been dispatched during the call, as the function might have spent all of the alloted time waiting on the event queue.
|
* been dispatched during the call, as the function might have spent all of the alloted time waiting on the event queue.
|
||||||
* Once an event has been unqueued, however, it is guaranteed to be dispatched. This guarantee contributes to not being
|
* Once an event has been unqueued, however, it is guaranteed to be dispatched. This guarantee contributes to not being
|
||||||
* able to exit exactly at time of expiry as (1) blocking on internal mutexes is necessary for dispatching the unqueued
|
* able to exit exactly at time of expiry as (1) blocking on internal mutexes is necessary for dispatching the unqueued
|
||||||
* event, and (2) during dispatch of the unqueued event there is no way to control the time occupied by handler code
|
* event, and (2) during dispatch of the unqueued event there is no way to control the time occupied by handler code
|
||||||
* execution. The guaranteed time of exit is therefore the alloted time + amount of time required to dispatch
|
* execution. The guaranteed time of exit is therefore the alloted time + amount of time required to dispatch
|
||||||
* the last unqueued event.
|
* the last unqueued event.
|
||||||
*
|
*
|
||||||
* In cases where waiting on the queue times out, ESP_OK is returned and not ESP_ERR_TIMEOUT, since it is
|
* In cases where waiting on the queue times out, ESP_OK is returned and not ESP_ERR_TIMEOUT, since it is
|
||||||
* normal behavior.
|
* normal behavior.
|
||||||
*
|
*
|
||||||
* @param[in] event_loop event loop to dispatch posted events from
|
* @param[in] event_loop event loop to dispatch posted events from
|
||||||
@ -108,7 +108,7 @@ esp_err_t esp_event_loop_delete_default();
|
|||||||
*
|
*
|
||||||
* @note encountering an unknown event that has been posted to the loop will only generate a warning, not an error.
|
* @note encountering an unknown event that has been posted to the loop will only generate a warning, not an error.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: Success
|
* - ESP_OK: Success
|
||||||
* - Others: Fail
|
* - Others: Fail
|
||||||
*/
|
*/
|
||||||
@ -124,8 +124,8 @@ esp_err_t esp_event_loop_run(esp_event_loop_handle_t event_loop, TickType_t tick
|
|||||||
* - all events of a certain base: specify exact event_base and use ESP_EVENT_ANY_ID as the event_id
|
* - all events of a certain base: specify exact event_base and use ESP_EVENT_ANY_ID as the event_id
|
||||||
* - all events known by the loop: use ESP_EVENT_ANY_BASE for event_base and ESP_EVENT_ANY_ID as the event_id
|
* - all events known by the loop: use ESP_EVENT_ANY_BASE for event_base and ESP_EVENT_ANY_ID as the event_id
|
||||||
*
|
*
|
||||||
* Registering multiple handlers to events is possible. Registering a single handler to multiple events is
|
* Registering multiple handlers to events is possible. Registering a single handler to multiple events is
|
||||||
* also possible. However, registering the same handler to the same event multiple times would cause the
|
* also possible. However, registering the same handler to the same event multiple times would cause the
|
||||||
* previous registrations to be overwritten.
|
* previous registrations to be overwritten.
|
||||||
*
|
*
|
||||||
* @param[in] event_base the base id of the event to register the handler for
|
* @param[in] event_base the base id of the event to register the handler for
|
||||||
@ -133,24 +133,24 @@ esp_err_t esp_event_loop_run(esp_event_loop_handle_t event_loop, TickType_t tick
|
|||||||
* @param[in] event_handler the handler function which gets called when the event is dispatched
|
* @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
|
* @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
|
* @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
|
* ensure that event_handler_arg still points to a valid location by the time the handler gets called
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: Success
|
* - ESP_OK: Success
|
||||||
* - ESP_ERR_NO_MEM: Cannot allocate memory for the handler
|
* - 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
|
* - Others: Fail
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_event_handler_register(esp_event_base_t event_base,
|
esp_err_t esp_event_handler_register(esp_event_base_t event_base,
|
||||||
int32_t event_id,
|
int32_t event_id,
|
||||||
esp_event_handler_t event_handler,
|
esp_event_handler_t event_handler,
|
||||||
void* event_handler_arg);
|
void* event_handler_arg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Register an event handler to a specific loop.
|
* @brief Register an event handler to a specific loop.
|
||||||
*
|
*
|
||||||
* This function behaves in the same manner as esp_event_handler_register, except the additional
|
* This function behaves in the same manner as esp_event_handler_register, except the additional
|
||||||
* specification of the event loop to register the handler to.
|
* specification of the event loop to register the handler to.
|
||||||
*
|
*
|
||||||
* @param[in] event_loop the event loop to register this handler function to
|
* @param[in] event_loop the event loop to register this handler function to
|
||||||
@ -159,23 +159,26 @@ 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 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
|
* @param[in] event_handler_arg data, aside from event data, that is passed to the handler when it is called
|
||||||
*
|
*
|
||||||
* @return
|
* @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_OK: Success
|
||||||
* - ESP_ERR_NO_MEM: Cannot allocate memory for the handler
|
* - 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
|
* - Others: Fail
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_event_handler_register_with(esp_event_loop_handle_t event_loop,
|
esp_err_t esp_event_handler_register_with(esp_event_loop_handle_t event_loop,
|
||||||
esp_event_base_t event_base,
|
esp_event_base_t event_base,
|
||||||
int32_t event_id,
|
int32_t event_id,
|
||||||
esp_event_handler_t event_handler,
|
esp_event_handler_t event_handler,
|
||||||
void* event_handler_arg);
|
void* event_handler_arg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Unregister a handler with the system event loop.
|
* @brief Unregister a handler with the system event loop.
|
||||||
*
|
*
|
||||||
* This function can be used to unregister a handler so that it no longer gets called during dispatch.
|
* This function can be used to unregister a handler so that it no longer gets called during dispatch.
|
||||||
* Handlers can be unregistered for either: (1) specific events, (2) all events of a certain event base,
|
* Handlers can be unregistered for either: (1) specific events, (2) all events of a certain event base,
|
||||||
* or (3) all events known by the system event loop
|
* or (3) all events known by the system event loop
|
||||||
*
|
*
|
||||||
* - specific events: specify exact event_base and event_id
|
* - specific events: specify exact event_base and event_id
|
||||||
@ -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
|
* @param[in] event_handler the handler to unregister
|
||||||
*
|
*
|
||||||
* @return ESP_OK success
|
* @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
|
* @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);
|
esp_err_t esp_event_handler_unregister(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler);
|
||||||
@ -197,7 +200,7 @@ esp_err_t esp_event_handler_unregister(esp_event_base_t event_base, int32_t even
|
|||||||
/**
|
/**
|
||||||
* @brief Unregister a handler with the system event loop.
|
* @brief Unregister a handler with the system event loop.
|
||||||
*
|
*
|
||||||
* This function behaves in the same manner as esp_event_handler_unregister, except the additional specification of
|
* This function behaves in the same manner as esp_event_handler_unregister, except the additional specification of
|
||||||
* the event loop to unregister the handler with.
|
* the event loop to unregister the handler with.
|
||||||
*
|
*
|
||||||
* @param[in] event_loop the event loop with which to unregister this handler function
|
* @param[in] event_loop the event loop with which to unregister this handler function
|
||||||
@ -205,21 +208,21 @@ esp_err_t esp_event_handler_unregister(esp_event_base_t event_base, int32_t even
|
|||||||
* @param[in] event_id the id of the event with which to unregister the handler
|
* @param[in] event_id the id of the event with which to unregister the handler
|
||||||
* @param[in] event_handler the handler to unregister
|
* @param[in] event_handler the handler to unregister
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: Success
|
* - 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
|
* - Others: Fail
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_event_handler_unregister_with(esp_event_loop_handle_t event_loop,
|
esp_err_t esp_event_handler_unregister_with(esp_event_loop_handle_t event_loop,
|
||||||
esp_event_base_t event_base,
|
esp_event_base_t event_base,
|
||||||
int32_t event_id,
|
int32_t event_id,
|
||||||
esp_event_handler_t event_handler);
|
esp_event_handler_t event_handler);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Posts an event to the system default event loop. The event loop library keeps a copy of event_data and manages
|
* @brief Posts an event to the system default event loop. The event loop library keeps a copy of event_data and manages
|
||||||
* the copy's lifetime automatically (allocation + deletion); this ensures that the data the
|
* the copy's lifetime automatically (allocation + deletion); this ensures that the data the
|
||||||
* handler recieves is always valid.
|
* handler recieves is always valid.
|
||||||
*
|
*
|
||||||
* @param[in] event_base the event base that identifies the event
|
* @param[in] event_base the event base that identifies the event
|
||||||
* @param[in] event_id the the event id that identifies the event
|
* @param[in] event_id the the event id that identifies the event
|
||||||
* @param[in] event_data the data, specific to the event occurence, that gets passed to the handler
|
* @param[in] event_data the data, specific to the event occurence, that gets passed to the handler
|
||||||
@ -228,21 +231,21 @@ esp_err_t esp_event_handler_unregister_with(esp_event_loop_handle_t event_loop,
|
|||||||
*
|
*
|
||||||
* @note posting events from an ISR is not supported
|
* @note posting events from an ISR is not supported
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: Success
|
* - ESP_OK: Success
|
||||||
* - ESP_ERR_TIMEOUT: Time to wait for event queue to unblock expired
|
* - 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
|
* - Others: Fail
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_event_post(esp_event_base_t event_base,
|
esp_err_t esp_event_post(esp_event_base_t event_base,
|
||||||
int32_t event_id,
|
int32_t event_id,
|
||||||
void* event_data,
|
void* event_data,
|
||||||
size_t event_data_size,
|
size_t event_data_size,
|
||||||
TickType_t ticks_to_wait);
|
TickType_t ticks_to_wait);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Posts an event to the specified event loop. The event loop library keeps a copy of event_data and manages
|
* @brief Posts an event to the specified event loop. The event loop library keeps a copy of event_data and manages
|
||||||
* the copy's lifetime automatically (allocation + deletion); this ensures that the data the
|
* the copy's lifetime automatically (allocation + deletion); this ensures that the data the
|
||||||
* handler recieves is always valid.
|
* handler recieves is always valid.
|
||||||
*
|
*
|
||||||
* This function behaves in the same manner as esp_event_post_to, except the additional specification of the event loop
|
* This function behaves in the same manner as esp_event_post_to, except the additional specification of the event loop
|
||||||
@ -256,73 +259,60 @@ esp_err_t esp_event_post(esp_event_base_t event_base,
|
|||||||
* @param[in] ticks_to_wait number of ticks to block on a full event queue
|
* @param[in] ticks_to_wait number of ticks to block on a full event queue
|
||||||
*
|
*
|
||||||
* @note posting events from an ISR is not supported
|
* @note posting events from an ISR is not supported
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: Success
|
* - ESP_OK: Success
|
||||||
* - ESP_ERR_TIMEOUT: Time to wait for event queue to unblock expired
|
* - 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
|
* - Others: Fail
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_event_post_to(esp_event_loop_handle_t event_loop,
|
esp_err_t esp_event_post_to(esp_event_loop_handle_t event_loop,
|
||||||
esp_event_base_t event_base,
|
esp_event_base_t event_base,
|
||||||
int32_t event_id,
|
int32_t event_id,
|
||||||
void* event_data,
|
void* event_data,
|
||||||
size_t event_data_size,
|
size_t event_data_size,
|
||||||
TickType_t ticks_to_wait);
|
TickType_t ticks_to_wait);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Dumps statistics of all event loops.
|
* @brief Dumps statistics of all event loops.
|
||||||
*
|
*
|
||||||
* Dumps event loop info in the format:
|
* Dumps event loop info in the format:
|
||||||
*
|
*
|
||||||
@verbatim
|
@verbatim
|
||||||
event loop
|
event loop
|
||||||
event
|
handler
|
||||||
handler
|
handler
|
||||||
handler
|
|
||||||
event
|
|
||||||
handler
|
|
||||||
handler
|
|
||||||
event loop
|
|
||||||
event
|
|
||||||
handler
|
|
||||||
...
|
|
||||||
...
|
...
|
||||||
...
|
event loop
|
||||||
|
handler
|
||||||
|
handler
|
||||||
|
...
|
||||||
|
|
||||||
where:
|
where:
|
||||||
|
|
||||||
event loop
|
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:
|
where:
|
||||||
address - memory address of the event loop
|
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_recieved - number of successfully posted events
|
||||||
total_number_of_invocations - total number of handler invocations performed so far
|
total_dropped - number of events unsucessfully posted due to queue being full
|
||||||
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
|
|
||||||
|
|
||||||
handler
|
handler
|
||||||
format: address inv:total_invoked run:total_runtime
|
format: address ev:base,id inv:total_invoked run:total_runtime
|
||||||
where:
|
where:
|
||||||
address - address of the handler function
|
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_invoked - number of times this handler has been invoked
|
||||||
total_runtime - total amount of time used for invoking this handler
|
total_runtime - total amount of time used for invoking this handler
|
||||||
|
|
||||||
@endverbatim
|
@endverbatim
|
||||||
*
|
*
|
||||||
* @param[in] file the file stream to output to
|
* @param[in] file the file stream to output to
|
||||||
*
|
*
|
||||||
* @note this function is a noop when CONFIG_EVENT_LOOP_PROFILING is disabled
|
* @note this function is a noop when CONFIG_EVENT_LOOP_PROFILING is disabled
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: Success
|
* - ESP_OK: Success
|
||||||
* - ESP_ERR_NO_MEM: Cannot allocate memory for event loops list
|
* - ESP_ERR_NO_MEM: Cannot allocate memory for event loops list
|
||||||
* - Others: Fail
|
* - Others: Fail
|
||||||
|
@ -21,68 +21,66 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef SLIST_HEAD(base_nodes, base_node) base_nodes_t;
|
||||||
|
|
||||||
/// Event handler
|
/// Event handler
|
||||||
typedef struct esp_event_handler_instance {
|
typedef struct esp_event_handler_instance {
|
||||||
esp_event_handler_t handler; /**< event handler function*/
|
esp_event_handler_t handler; /**< event handler function*/
|
||||||
void* arg; /**< event handler argument */
|
void* arg; /**< event handler argument */
|
||||||
#ifdef CONFIG_EVENT_LOOP_PROFILING
|
#ifdef CONFIG_EVENT_LOOP_PROFILING
|
||||||
uint32_t total_times_invoked; /**< number of times this handler has been invoked */
|
uint32_t invoked; /**< number of times this handler has been invoked */
|
||||||
int64_t total_runtime; /**< total runtime of this handler across all calls */
|
int64_t time; /**< total runtime of this handler across all calls */
|
||||||
#endif
|
#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;
|
} esp_event_handler_instance_t;
|
||||||
|
|
||||||
typedef SLIST_HEAD(esp_event_handler_instances, esp_event_handler_instance) esp_event_handler_instances_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;
|
|
||||||
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;
|
|
||||||
|
|
||||||
typedef SLIST_HEAD(esp_event_id_instances, esp_event_id_instance) esp_event_id_instances_t;
|
|
||||||
|
|
||||||
/// Event
|
/// Event
|
||||||
typedef struct esp_event_base_instance {
|
typedef struct esp_event_id_node {
|
||||||
esp_event_base_t base; /**< base identifier of the event */
|
int32_t id; /**< id number of the event */
|
||||||
esp_event_handler_instances_t base_handlers; /**< event base level handlers, handlers for
|
esp_event_handler_instances_t handlers; /**< list of handlers to be executed when
|
||||||
all events with this base */
|
this event is raised */
|
||||||
esp_event_id_instances_t event_ids; /**< list of event ids with this base */
|
SLIST_ENTRY(esp_event_id_node) next; /**< pointer to the next event node on the linked list */
|
||||||
SLIST_ENTRY(esp_event_base_instance) event_base_entry; /**< pointer to the next event node on the linked list */
|
} esp_event_id_node_t;
|
||||||
#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;
|
|
||||||
|
|
||||||
typedef SLIST_HEAD(esp_event_base_instances, esp_event_base_instance) esp_event_base_instances_t;
|
typedef SLIST_HEAD(esp_event_id_nodes, esp_event_id_node) esp_event_id_nodes_t;
|
||||||
|
|
||||||
|
typedef struct esp_event_base_node {
|
||||||
|
esp_event_base_t base; /**< base identifier of the event */
|
||||||
|
esp_event_handler_instances_t handlers; /**< event base level handlers, handlers for
|
||||||
|
all events with this base */
|
||||||
|
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_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
|
/// Event loop
|
||||||
typedef struct esp_event_loop_instance {
|
typedef struct esp_event_loop_instance {
|
||||||
const char* name; /**< name of this event loop */
|
const char* name; /**< name of this event loop */
|
||||||
QueueHandle_t queue; /**< event queue */
|
QueueHandle_t queue; /**< event queue */
|
||||||
TaskHandle_t task; /**< task that consumes the event queue */
|
TaskHandle_t task; /**< task that consumes the event queue */
|
||||||
TaskHandle_t running_task; /**< for loops with no dedicated task, the
|
TaskHandle_t running_task; /**< for loops with no dedicated task, the
|
||||||
task that consumes the queue */
|
task that consumes the queue */
|
||||||
SemaphoreHandle_t mutex; /**< mutex for updating the events linked list */
|
SemaphoreHandle_t mutex; /**< mutex for updating the events linked list */
|
||||||
esp_event_handler_instances_t loop_handlers; /**< loop level handlers, handlers for all events
|
esp_event_loop_nodes_t loop_nodes; /**< set of linked lists containing the
|
||||||
registered in the loop */
|
registered handlers for the loop */
|
||||||
esp_event_base_instances_t event_bases; /**< events linked list head pointer */
|
|
||||||
#ifdef CONFIG_EVENT_LOOP_PROFILING
|
#ifdef CONFIG_EVENT_LOOP_PROFILING
|
||||||
uint32_t events_recieved; /**< number of events successfully posted to the loop */
|
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 events_dropped; /**< number of events dropped due to queue being full */
|
||||||
uint32_t loop_handlers_invoked; /**< total number of loop-level handlers invoked */
|
SemaphoreHandle_t profiling_mutex; /**< mutex used for profiliing */
|
||||||
int64_t loop_handlers_runtime; /**< amount of time processing loop-level handlers */
|
SLIST_ENTRY(esp_event_loop_instance) next; /**< next event loop in the list */
|
||||||
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;
|
|
||||||
#endif
|
#endif
|
||||||
} esp_event_loop_instance_t;
|
} esp_event_loop_instance_t;
|
||||||
|
|
||||||
|
@ -74,6 +74,11 @@ typedef struct {
|
|||||||
SemaphoreHandle_t mutex;
|
SemaphoreHandle_t mutex;
|
||||||
} simple_arg_t;
|
} simple_arg_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int *arr;
|
||||||
|
int index;
|
||||||
|
} ordered_data_t;
|
||||||
|
|
||||||
static BaseType_t s_test_core_id;
|
static BaseType_t s_test_core_id;
|
||||||
static UBaseType_t s_test_priority;
|
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);
|
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)
|
static void test_event_performance_handler(void* event_handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
|
||||||
{
|
{
|
||||||
@ -193,7 +205,7 @@ static void test_handler_post_w_task(void* event_handler_arg, esp_event_base_t e
|
|||||||
int* count = (int*) arg->data;
|
int* count = (int*) arg->data;
|
||||||
|
|
||||||
(*count)++;
|
(*count)++;
|
||||||
|
|
||||||
if (*count <= 2) {
|
if (*count <= 2) {
|
||||||
if (event_base == s_test_base1 && event_id == TEST_EVENT_BASE1_EV1) {
|
if (event_base == s_test_base1 && event_id == TEST_EVENT_BASE1_EV1) {
|
||||||
TEST_ASSERT_EQUAL(ESP_OK, esp_event_post_to(*loop, s_test_base1, TEST_EVENT_BASE1_EV2, NULL, 0, portMAX_DELAY));
|
TEST_ASSERT_EQUAL(ESP_OK, esp_event_post_to(*loop, s_test_base1, TEST_EVENT_BASE1_EV2, NULL, 0, portMAX_DELAY));
|
||||||
@ -218,7 +230,7 @@ static void test_handler_post_wo_task(void* event_handler_arg, esp_event_base_t
|
|||||||
int* count = (int*) arg->data;
|
int* count = (int*) arg->data;
|
||||||
|
|
||||||
(*count)++;
|
(*count)++;
|
||||||
|
|
||||||
if (*count <= 2) {
|
if (*count <= 2) {
|
||||||
if (event_base == s_test_base1 && event_id == TEST_EVENT_BASE1_EV1) {
|
if (event_base == s_test_base1 && event_id == TEST_EVENT_BASE1_EV1) {
|
||||||
TEST_ASSERT_EQUAL(ESP_OK, esp_event_post_to(*loop, s_test_base1, TEST_EVENT_BASE1_EV2, NULL, 0, portMAX_DELAY));
|
TEST_ASSERT_EQUAL(ESP_OK, esp_event_post_to(*loop, s_test_base1, TEST_EVENT_BASE1_EV2, NULL, 0, portMAX_DELAY));
|
||||||
@ -846,7 +858,7 @@ TEST_CASE("can post to loop from handler - dedicated task", "[event]")
|
|||||||
|
|
||||||
// Test that other tasks can still post while there is still slots in the queue, while handler is executing
|
// Test that other tasks can still post while there is still slots in the queue, while handler is executing
|
||||||
count = 100;
|
count = 100;
|
||||||
|
|
||||||
TEST_ASSERT_EQUAL(ESP_OK, esp_event_post_to(loop_w_task, s_test_base1, TEST_EVENT_BASE1_EV1, &loop_w_task, sizeof(&loop_w_task), portMAX_DELAY));
|
TEST_ASSERT_EQUAL(ESP_OK, esp_event_post_to(loop_w_task, s_test_base1, TEST_EVENT_BASE1_EV1, &loop_w_task, sizeof(&loop_w_task), portMAX_DELAY));
|
||||||
|
|
||||||
for (int i = 0; i < loop_args.queue_size; i++) {
|
for (int i = 0; i < loop_args.queue_size; i++) {
|
||||||
@ -854,7 +866,7 @@ TEST_CASE("can post to loop from handler - dedicated task", "[event]")
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_ASSERT_EQUAL(ESP_ERR_TIMEOUT, esp_event_post_to(loop_w_task, s_test_base1, TEST_EVENT_BASE1_EV2, NULL, 0,
|
TEST_ASSERT_EQUAL(ESP_ERR_TIMEOUT, esp_event_post_to(loop_w_task, s_test_base1, TEST_EVENT_BASE1_EV2, NULL, 0,
|
||||||
pdMS_TO_TICKS(CONFIG_INT_WDT_TIMEOUT_MS * TEST_CONFIG_WAIT_MULTIPLIER)));
|
pdMS_TO_TICKS(CONFIG_INT_WDT_TIMEOUT_MS * TEST_CONFIG_WAIT_MULTIPLIER)));
|
||||||
|
|
||||||
xSemaphoreGive(arg.mutex);
|
xSemaphoreGive(arg.mutex);
|
||||||
|
|
||||||
@ -977,7 +989,7 @@ TEST_CASE("can register from handler", "[event]")
|
|||||||
|
|
||||||
TEST_ASSERT_EQUAL(ESP_OK, esp_event_handler_register_with(loop, s_test_base1, TEST_EVENT_BASE1_EV1, test_registration_from_handler_hdlr, &count));
|
TEST_ASSERT_EQUAL(ESP_OK, esp_event_handler_register_with(loop, s_test_base1, TEST_EVENT_BASE1_EV1, test_registration_from_handler_hdlr, &count));
|
||||||
TEST_ASSERT_EQUAL(ESP_OK, esp_event_handler_register_with(loop, s_test_base2, TEST_EVENT_BASE2_EV1, test_unregistration_from_handler_hdlr, &count));
|
TEST_ASSERT_EQUAL(ESP_OK, esp_event_handler_register_with(loop, s_test_base2, TEST_EVENT_BASE2_EV1, test_unregistration_from_handler_hdlr, &count));
|
||||||
|
|
||||||
TEST_ASSERT_EQUAL(ESP_OK, esp_event_post_to(loop, s_test_base1, TEST_EVENT_BASE1_EV1, &loop, sizeof(&loop), portMAX_DELAY));
|
TEST_ASSERT_EQUAL(ESP_OK, esp_event_post_to(loop, s_test_base1, TEST_EVENT_BASE1_EV1, &loop, sizeof(&loop), portMAX_DELAY));
|
||||||
TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_run(loop, pdMS_TO_TICKS(10)));
|
TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_run(loop, pdMS_TO_TICKS(10)));
|
||||||
|
|
||||||
@ -1024,7 +1036,7 @@ TEST_CASE("can create and delete loop from handler", "[event]")
|
|||||||
|
|
||||||
TEST_ASSERT_EQUAL(ESP_OK, esp_event_handler_register_with(loop, s_test_base1, TEST_EVENT_BASE1_EV1, test_create_loop_handler, &test_loop));
|
TEST_ASSERT_EQUAL(ESP_OK, esp_event_handler_register_with(loop, s_test_base1, TEST_EVENT_BASE1_EV1, test_create_loop_handler, &test_loop));
|
||||||
TEST_ASSERT_EQUAL(ESP_OK, esp_event_handler_register_with(loop, s_test_base1, TEST_EVENT_BASE1_EV2, test_create_loop_handler, &test_loop));
|
TEST_ASSERT_EQUAL(ESP_OK, esp_event_handler_register_with(loop, s_test_base1, TEST_EVENT_BASE1_EV2, test_create_loop_handler, &test_loop));
|
||||||
|
|
||||||
TEST_ASSERT_EQUAL(ESP_OK, esp_event_post_to(loop, s_test_base1, TEST_EVENT_BASE1_EV1, NULL, 0, portMAX_DELAY));
|
TEST_ASSERT_EQUAL(ESP_OK, esp_event_post_to(loop, s_test_base1, TEST_EVENT_BASE1_EV1, NULL, 0, portMAX_DELAY));
|
||||||
TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_run(loop, pdMS_TO_TICKS(10)));
|
TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_run(loop, pdMS_TO_TICKS(10)));
|
||||||
|
|
||||||
@ -1036,6 +1048,60 @@ TEST_CASE("can create and delete loop from handler", "[event]")
|
|||||||
TEST_TEARDOWN();
|
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
|
#ifdef CONFIG_EVENT_LOOP_PROFILING
|
||||||
TEST_CASE("can dump event loop profile", "[event]")
|
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, 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, 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_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));
|
TEST_ASSERT_EQUAL(ESP_OK, esp_event_handler_register_with(loop, s_test_base1, TEST_EVENT_BASE1_EV2, test_event_simple_handler, &arg));
|
||||||
|
|
||||||
|
@ -13,11 +13,11 @@ code execution to another context.
|
|||||||
Using ``esp_event`` APIs
|
Using ``esp_event`` APIs
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
There are two objects of concern for users of this library: events and event loops.
|
There are two objects of concern for users of this library: events and event loops.
|
||||||
|
|
||||||
Events are occurences of note. For example, for WiFi, a successful connection to the access point may be an event.
|
Events are occurences of note. For example, for WiFi, a successful connection to the access point may be an event.
|
||||||
Events are referenced using a two part identifier which are discussed more :ref:`here <esp-event-declaring-defining-events>`.
|
Events are referenced using a two part identifier which are discussed more :ref:`here <esp-event-declaring-defining-events>`.
|
||||||
Event loops are the vehicle by which events get posted by event sources and handled by event handler functions.
|
Event loops are the vehicle by which events get posted by event sources and handled by event handler functions.
|
||||||
These two appear prominently in the event loop library APIs.
|
These two appear prominently in the event loop library APIs.
|
||||||
|
|
||||||
Using this library roughly entails the following flow:
|
Using this library roughly entails the following flow:
|
||||||
@ -41,7 +41,7 @@ In code, the flow above may look like as follows:
|
|||||||
|
|
||||||
void app_main()
|
void app_main()
|
||||||
{
|
{
|
||||||
// 2. A configuration structure of type esp_event_loop_args_t is needed to specify the properties of the loop to be
|
// 2. A configuration structure of type esp_event_loop_args_t is needed to specify the properties of the loop to be
|
||||||
// created. A handle of type esp_event_loop_handle_t is obtained, which is needed by the other APIs to reference the loop
|
// created. A handle of type esp_event_loop_handle_t is obtained, which is needed by the other APIs to reference the loop
|
||||||
// to perform their operations on.
|
// to perform their operations on.
|
||||||
esp_event_loop_args_t loop_args = {
|
esp_event_loop_args_t loop_args = {
|
||||||
@ -56,8 +56,8 @@ In code, the flow above may look like as follows:
|
|||||||
|
|
||||||
esp_event_loop_create(&loop_args, &loop_handle)
|
esp_event_loop_create(&loop_args, &loop_handle)
|
||||||
|
|
||||||
// 3. Register event handler defined in (1). MY_EVENT_BASE and MY_EVENT_ID specifies a hypothetical
|
// 3. Register event handler defined in (1). MY_EVENT_BASE and MY_EVENT_ID specifies a hypothetical
|
||||||
// event that handler run_on_event should execute on when it gets posted to the loop.
|
// event that handler run_on_event should execute on when it gets posted to the loop.
|
||||||
esp_event_handler_register_with(loop_handle, MY_EVENT_BASE, MY_EVENT_ID, run_on_event, ...);
|
esp_event_handler_register_with(loop_handle, MY_EVENT_BASE, MY_EVENT_ID, run_on_event, ...);
|
||||||
|
|
||||||
...
|
...
|
||||||
@ -127,29 +127,29 @@ Default Event Loop
|
|||||||
------------------
|
------------------
|
||||||
|
|
||||||
The default event loop is a special type of loop used for system events (WiFi events, for example). The handle for this
|
The default event loop is a special type of loop used for system events (WiFi events, for example). The handle for this
|
||||||
loop is hidden from the user. The creation, deletion, handler registration/unregistration and posting of events is done
|
loop is hidden from the user. The creation, deletion, handler registration/unregistration and posting of events is done
|
||||||
through a variant of the APIs for user event loops. The table below enumerates those variants, and the user event
|
through a variant of the APIs for user event loops. The table below enumerates those variants, and the user event
|
||||||
loops equivalent.
|
loops equivalent.
|
||||||
|
|
||||||
+---------------------------------------------------+---------------------------------------------------+
|
+---------------------------------------------------+---------------------------------------------------+
|
||||||
| User Event Loops | Default Event Loops |
|
| User Event Loops | Default Event Loops |
|
||||||
+===================================================+===================================================+
|
+===================================================+===================================================+
|
||||||
| :cpp:func:`esp_event_loop_create` | :cpp:func:`esp_event_loop_create_default` |
|
| :cpp:func:`esp_event_loop_create` | :cpp:func:`esp_event_loop_create_default` |
|
||||||
+---------------------------------------------------+---------------------------------------------------+
|
+---------------------------------------------------+---------------------------------------------------+
|
||||||
| :cpp:func:`esp_event_loop_delete` | :cpp:func:`esp_event_loop_delete_default` |
|
| :cpp:func:`esp_event_loop_delete` | :cpp:func:`esp_event_loop_delete_default` |
|
||||||
+---------------------------------------------------+---------------------------------------------------+
|
+---------------------------------------------------+---------------------------------------------------+
|
||||||
| :cpp:func:`esp_event_handler_register_with` | :cpp:func:`esp_event_handler_register` |
|
| :cpp:func:`esp_event_handler_register_with` | :cpp:func:`esp_event_handler_register` |
|
||||||
+---------------------------------------------------+---------------------------------------------------+
|
+---------------------------------------------------+---------------------------------------------------+
|
||||||
| :cpp:func:`esp_event_handler_unregister_with` | :cpp:func:`esp_event_handler_unregister` |
|
| :cpp:func:`esp_event_handler_unregister_with` | :cpp:func:`esp_event_handler_unregister` |
|
||||||
+---------------------------------------------------+---------------------------------------------------+
|
+---------------------------------------------------+---------------------------------------------------+
|
||||||
| :cpp:func:`esp_event_post_to` | :cpp:func:`esp_event_post` |
|
| :cpp:func:`esp_event_post_to` | :cpp:func:`esp_event_post` |
|
||||||
+---------------------------------------------------+---------------------------------------------------+
|
+---------------------------------------------------+---------------------------------------------------+
|
||||||
|
|
||||||
If you compare the signatures for both, they are mostly similar except the for the lack of loop handle
|
If you compare the signatures for both, they are mostly similar except the for the lack of loop handle
|
||||||
specification for the default event loop APIs.
|
specification for the default event loop APIs.
|
||||||
|
|
||||||
Other than the API difference and the special designation to which system events are posted to, there is no difference
|
Other than the API difference and the special designation to which system events are posted to, there is no difference
|
||||||
to how default event loops and user event loops behave. It is even possible for users to post their own events
|
to how default event loops and user event loops behave. It is even possible for users to post their own events
|
||||||
to the default event loop, should the user opt to not create their own loops to save memory.
|
to the default event loop, should the user opt to not create their own loops to save memory.
|
||||||
|
|
||||||
.. _esp-event-handler-registration:
|
.. _esp-event-handler-registration:
|
||||||
@ -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.
|
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
|
Event loop profiling
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user