/* This function start two tasks, one on each CPU. These tasks are started with high priority. These tasks are normally inactive, waiting until one of the esp_ipc_call_* functions to be used. One of these tasks will be woken up to execute the callback provided to esp_ipc_call_nonblocking or esp_ipc_call_blocking.  */
static void esp_ipc_init() __attribute__((constructor))
/* This function start two tasks, one on each CPU. These tasks are started with high priority. These tasks are normally inactive, waiting until one of the esp_ipc_call_* functions to be used. One of these tasks will be woken up to execute the callback provided to esp_ipc_call_nonblocking or esp_ipc_call_blocking.  */
static void esp_ipc_init() __attribute__((constructor))
{
    s_ipc_mutex = xSemaphoreCreateMutex();
    s_ipc_ack = xSemaphoreCreateBinary();
    char task_name[15];
    for (int i = 0; i < portNUM_PROCESSORS; ++i) {
        snprintf(task_name, sizeof(task_name), "ipc%d", i);
        s_ipc_sem[i] = xSemaphoreCreateBinary();
        portBASE_TYPE res = xTaskCreatePinnedToCore(ipc_task, task_name, CONFIG_IPC_TASK_STACK_SIZE, (void*) i,
                                                    configMAX_PRIORITIES - 1, NULL, i);
        assert(res == pdTRUE);
    }
}