Does LVGL need (or can it work with) another event loop?

I’ve more or less settled on using libuv — it has a nice interface and extremely good documentation. But I do have one more question: according to the porting docs, I need to have a mutex around the lv_task_handler() call and around any other lv_...() calls from other tasks or threads. But

  1. Is there a built-in lv_...() function that does this? I know lv_tick_inc() doesn’t need this protection, what about say, lv_task_create()?
  2. Failing that, if I only call lv_ functions from the thread that runs lv_task_handler(), will that suffice? For example, in libuv, I might do:
uv_timer_t timer_lvgl_handler;
uv_timer_init(&loop, &timer_lvgl_handler);
uv_timer_start(&timer_lvgl_handler, lvgl_handler_cb, LVGL_TICK_MS/2, LVGL_TICK_MS);

To run lv_task_handler() in a timer task (offset from lv_tick_inc() by half the period). A simple version of that might be:

void lvgl_handler_cb(uv_timer_t * timer)
{
    lv_task_handler();
}

But what if I had something like:

void lvgl_handler_cb(uv_timer_t * timer)
{
    // bit of pseudocode here - store an event queue
    // or whatever as user data
    event_queue = timer->data;
    while (next_event = non_blocking_pop(timer->data))
    {
        lv_task_create(something_based_on_next_event);
    }
    lv_task_handler();
}

The way I’m thinking about it is that this exploits whatever mutexes/protection libuv or queue is using, right? Calls from within LVGL code could also post events to a similar queue for other libs to process. Does that make sense?