<commit_before>// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>

#include "esp_log.h"

#include "esp_event.h"
#include "esp_event_internal.h"
#include "esp_event_private.h"

#ifdef CONFIG_ESP_EVENT_LOOP_PROFILING
#include "esp_timer.h"
#endif

/* ---------------------------- Definitions --------------------------------- */

#ifdef CONFIG_ESP_EVENT_LOOP_PROFILING
// LOOP @<address, name> rx:<recieved events no.> dr:<dropped events no.>
#define LOOP_DUMP_FORMAT              "LOOP @%p,%s rx:%u dr:%u\n"
 // handler @<address> ev:<base, id> inv:<times invoked> time:<runtime>
#define HANDLER_DUMP_FORMAT           "  HANDLER @%p ev:%s,%s inv:%u time:%lld us\n"

#define PRINT_DUMP_INFO(dst, sz, ...)  do { \
                                            int cb = snprintf(dst, sz, __VA_ARGS__); \
                                            dst += cb; \
                                            sz -= cb; \
                                        } while(0);
#endif

/* ------------------------- Static Variables ------------------------------- */

static const char* TAG = "event";
static const char* esp_event_any_base = "any";

#ifdef CONFIG_ESP_EVENT_LOOP_PROFILING
static SLIST_HEAD(esp_event_loop_instance_list_t, esp_event_loop_instance) s_event_loops =
        SLIST_HEAD_INITIALIZER(s_event_loops);

static portMUX_TYPE s_event_loops_spinlock = portMUX_INITIALIZER_UNLOCKED;
#endif


/* ------------------------- Static Functions ------------------------------- */

#ifdef CONFIG_ESP_EVENT_LOOP_PROFILING


static int esp_event_dump_prepare()
{
    esp_event_loop_instance_t* loop_it;
    esp_event_loop_node_t *loop_node_it;
    esp_event_base_node_t* base_node_it;
    esp_event_id_node_t* id_node_it;
    esp_event_handler_instance_t* handler_it;

    // Count the number of items to be printed. This is needed to compute how much memory to reserve.
    int loops = 0, handlers = 0;

    portENTER_CRITICAL(&s_event_loops_spinlock);

    SLIST_FOREACH(loop_it, &s_event_loops, next) {
        SLIST_FOREACH(loop_node_it, &(loop_it->loop_nodes), next) {
            SLIST_FOREACH(handler_it, &(loop_node_it->handlers), next) {
                handlers++;
            }

            SLIST_FOREACH(base_node_it, &(loop_node_it->base_nodes), next) {
                SLIST_FOREACH(handler_it, &(base_node_it->handlers), next) {
                    handlers++;
                }
                SLIST_FOREACH(id_node_it, &(base_node_it->id_nodes), next) {
                    SLIST_FOREACH(handler_it, &(id_node_it->handlers), next) {
                        handlers++;
                    }
                }
            }
        }
        loops++;
    }

    portEXIT_CRITICAL(&s_event_loops_spinlock);

    // Reserve slightly more memory than computed
    int allowance = 3;
    int size = (((loops + allowance) * (sizeof(LOOP_DUMP_FORMAT) + 10 + 20 + 2 * 11)) +
                        ((handlers + allowance) * (sizeof(HANDLER_DUMP_FORMAT) + 10 + 2 * 20 + 11 + 20)));

    return size;
}
#endif

static void esp_event_loop_run_task(void* args)
{
    esp_err_t err;
    esp_event_loop_handle_t event_loop = (esp_event_loop_handle_t) args;

    ESP_LOGD(TAG, "running task for loop %p", event_loop);

    while(1) {
        err = esp_event_loop_run(event_loop, portMAX_DELAY);
        if (err != ESP_OK) {
            break;
        }
    }

    ESP_LOGE(TAG, "suspended task for loop %p", event_loop);
    vTaskSuspend(NULL);
}

static void handler_execute(esp_event_loop_instance_t* loop, esp_event_handler_instance_t *handler, esp_event_post_instance_t post)
{
    ESP_LOGD(TAG, "running post %s:%d with handler %p on loop %p", post.base, post.id, handler->handler, loop);

#ifdef CONFIG_ESP_EVENT_LOOP_PROFILING
    int64_t start, diff;
    start = esp_timer_get_time();
#endif
    // Execute the handler
#if CONFIG_ESP_EVENT_POST_FROM_ISR
    void* data_ptr = NULL;

    if (post.data_set) {
        if (post.data_allocated) {
            data_ptr = post.data.ptr;
        } else {
            data_ptr = &post.data.val;
        }
    }

    (*(handler->handler))(handler->arg, post.base, post.id, data_ptr);
#else
    (*(handler->handler))(handler->arg, post.base, post.id, post.data);
#endif

#ifdef CONFIG_ESP_EVENT_LOOP_PROFILING
    diff = esp_timer_get_time() - start;

    xSemaphoreTake(loop->profiling_mutex, portMAX_DELAY);

    handler->invoked++;
    handler->time += diff;

    xSemaphoreGive(loop->profiling_mutex);
#endif
}

static esp_err_t handler_instances_add(esp_event_handler_instances_t* handlers, esp_event_handler_t handler, void* handler_arg)
{
    esp_event_handler_instance_t* handler_instance = calloc(1, sizeof(*handler_instance));

    if (!handler_instance) {
        return ESP_ERR_NO_MEM;
    }

    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 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)
{<commit_msg>esp_event: fix minor memory leak when overwriting alredy registered handler<commit_after>// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>

#include "esp_log.h"

#include "esp_event.h"
#include "esp_event_internal.h"
#include "esp_event_private.h"

#ifdef CONFIG_ESP_EVENT_LOOP_PROFILING
#include "esp_timer.h"
#endif

/* ---------------------------- Definitions --------------------------------- */

#ifdef CONFIG_ESP_EVENT_LOOP_PROFILING
// LOOP @<address, name> rx:<recieved events no.> dr:<dropped events no.>
#define LOOP_DUMP_FORMAT              "LOOP @%p,%s rx:%u dr:%u\n"
 // handler @<address> ev:<base, id> inv:<times invoked> time:<runtime>
#define HANDLER_DUMP_FORMAT           "  HANDLER @%p ev:%s,%s inv:%u time:%lld us\n"

#define PRINT_DUMP_INFO(dst, sz, ...)  do { \
                                            int cb = snprintf(dst, sz, __VA_ARGS__); \
                                            dst += cb; \
                                            sz -= cb; \
                                        } while(0);
#endif

/* ------------------------- Static Variables ------------------------------- */

static const char* TAG = "event";
static const char* esp_event_any_base = "any";

#ifdef CONFIG_ESP_EVENT_LOOP_PROFILING
static SLIST_HEAD(esp_event_loop_instance_list_t, esp_event_loop_instance) s_event_loops =
        SLIST_HEAD_INITIALIZER(s_event_loops);

static portMUX_TYPE s_event_loops_spinlock = portMUX_INITIALIZER_UNLOCKED;
#endif


/* ------------------------- Static Functions ------------------------------- */

#ifdef CONFIG_ESP_EVENT_LOOP_PROFILING


static int esp_event_dump_prepare()
{
    esp_event_loop_instance_t* loop_it;
    esp_event_loop_node_t *loop_node_it;
    esp_event_base_node_t* base_node_it;
    esp_event_id_node_t* id_node_it;
    esp_event_handler_instance_t* handler_it;

    // Count the number of items to be printed. This is needed to compute how much memory to reserve.
    int loops = 0, handlers = 0;

    portENTER_CRITICAL(&s_event_loops_spinlock);

    SLIST_FOREACH(loop_it, &s_event_loops, next) {
        SLIST_FOREACH(loop_node_it, &(loop_it->loop_nodes), next) {
            SLIST_FOREACH(handler_it, &(loop_node_it->handlers), next) {
                handlers++;
            }

            SLIST_FOREACH(base_node_it, &(loop_node_it->base_nodes), next) {
                SLIST_FOREACH(handler_it, &(base_node_it->handlers), next) {
                    handlers++;
                }
                SLIST_FOREACH(id_node_it, &(base_node_it->id_nodes), next) {
                    SLIST_FOREACH(handler_it, &(id_node_it->handlers), next) {
                        handlers++;
                    }
                }
            }
        }
        loops++;
    }

    portEXIT_CRITICAL(&s_event_loops_spinlock);

    // Reserve slightly more memory than computed
    int allowance = 3;
    int size = (((loops + allowance) * (sizeof(LOOP_DUMP_FORMAT) + 10 + 20 + 2 * 11)) +
                        ((handlers + allowance) * (sizeof(HANDLER_DUMP_FORMAT) + 10 + 2 * 20 + 11 + 20)));

    return size;
}
#endif

static void esp_event_loop_run_task(void* args)
{
    esp_err_t err;
    esp_event_loop_handle_t event_loop = (esp_event_loop_handle_t) args;

    ESP_LOGD(TAG, "running task for loop %p", event_loop);

    while(1) {
        err = esp_event_loop_run(event_loop, portMAX_DELAY);
        if (err != ESP_OK) {
            break;
        }
    }

    ESP_LOGE(TAG, "suspended task for loop %p", event_loop);
    vTaskSuspend(NULL);
}

static void handler_execute(esp_event_loop_instance_t* loop, esp_event_handler_instance_t *handler, esp_event_post_instance_t post)
{
    ESP_LOGD(TAG, "running post %s:%d with handler %p on loop %p", post.base, post.id, handler->handler, loop);

#ifdef CONFIG_ESP_EVENT_LOOP_PROFILING
    int64_t start, diff;
    start = esp_timer_get_time();
#endif
    // Execute the handler
#if CONFIG_ESP_EVENT_POST_FROM_ISR
    void* data_ptr = NULL;

    if (post.data_set) {
        if (post.data_allocated) {
            data_ptr = post.data.ptr;
        } else {
            data_ptr = &post.data.val;
        }
    }

    (*(handler->handler))(handler->arg, post.base, post.id, data_ptr);
#else
    (*(handler->handler))(handler->arg, post.base, post.id, post.data);
#endif

#ifdef CONFIG_ESP_EVENT_LOOP_PROFILING
    diff = esp_timer_get_time() - start;

    xSemaphoreTake(loop->profiling_mutex, portMAX_DELAY);

    handler->invoked++;
    handler->time += diff;

    xSemaphoreGive(loop->profiling_mutex);
#endif
}

static esp_err_t handler_instances_add(esp_event_handler_instances_t* handlers, esp_event_handler_t handler, void* handler_arg)
{
    esp_event_handler_instance_t* handler_instance = calloc(1, sizeof(*handler_instance));

    if (!handler_instance) {
        return ESP_ERR_NO_MEM;
    }

    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");
                free(handler_instance);
                return ESP_OK;
            }
            last = it;
        }

        SLIST_INSERT_AFTER(last, handler_instance, next);
    }

    return ESP_OK;
}

static esp_err_t base_node_add_handler(esp_event_base_node_t* base_node, int32_t id, esp_event_handler_t handler, void* handler_arg)
{
{'fraction_non_alphanumeric': 0.12960875865400096, 'fraction_numerical': 0.005474158750603767, 'mean_word_length': 2.5103136479231423, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 63, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5915110', 'n_tokens_mistral': 4127, 'n_tokens_neox': 3979, 'n_words': 890}