3

I have a function that needs to schedule a task to the libuv event loop. My idea was to create a timer with 0ms timeout. I have tried the following code:

void myFunction() {
    ...
    uv_timer_t* timer = new uv_timer_t();
    uv_timer_init(uv_default_loop(), timer);
    uv_timer_start(timer, [&](uv_timer_t* timer, int status) {
        // Scheduled task
    }, 0, 0);
}

This approach works well but the problem is, that the dynamically allocated timer will never be freed. I have tried freeing the timer in the callback, but that have led to segmentation fault:

void myFunction() {
    ...
    uv_timer_t* timer = new uv_timer_t();
    uv_timer_init(uv_default_loop(), timer);
    uv_timer_start(timer, [&](uv_timer_t* timer, int status) {
        // Scheduled task
        delete timer;
    }, 0, 0);
}

I have also tried to call uv_timer_stop(timer); and uv_unref((uv_handle_t*) timer); before the actual memory freeing, but the segmentation fault still remians.

Daniel Frey
  • 55,810
  • 13
  • 122
  • 180
Marian Galik
  • 876
  • 8
  • 21

2 Answers2

9

I had the same problem, and here is the way you handle it:

First, you will want to create a callback for when your timer handle gets closed:

void on_timer_close_complete(uv_handle_t* handle)
{
    free(handle);
}

Notice that the handle will be freed in the callback.

When you go to stop and free your timer, you would do it like this:

uv_timer_stop(pTimerHandle);
uv_close((uv_handle_t *)pTimerHandle,on_timer_close_complete);

The part that is not intuitive is the uv_close() call. I don't think I have seen it anywhere in the documentation. I was only able to figure this out by following the source.

This way, libuv will execute your callback when it is done with the timer, and then you can free it safely within that callback.

IntelliAdmin
  • 184
  • 1
  • 2
  • Thank you. I had same probelm. But documentation clearly expresses it. http://docs.libuv.org/en/v1.x/handle.html?highlight=uv_close And doc capitalize MUST. I never noticed it. It's also true sample code show nothing about uv_close when using uv_timer_t – robert Jan 09 '18 at 14:05
  • @BernardoRamos The [documentation for the base handle type](http://docs.libuv.org/en/latest/handle.html#c.uv_close) still says it, and explicitly mentions memory freeing. There's nothing in the [timer docs](http://docs.libuv.org/en/latest/timer.html) about it not applying. Is it a documentation error? Do you if this is still the way to free memory for eg. idle tasks? – detly Aug 13 '20 at 02:40
1

Based on the @IntelliAdmin answer, if you don't want to close it on your own, and just want it to be closed when there are no more references back to it, you can use smart pointers:

template<typename T>
using deleted_unique_ptr = std::unique_ptr<T, std::function<void( T* )>>;


deleted_unique_ptr<uv_timer_t> timer = deleted_unique_ptr<uv_timer_t>( new uv_timer_t, [&]( uv_timer_t *timerhandl ) {
    uv_close( reinterpret_cast<uv_handle_t *>( timerhandl ), OnTimerClose );
});

Then for the callback just delete the pointer:

void OnTimerClose( uv_handle_t *handle )
{
    delete handle;
}
jonathancardoso
  • 11,737
  • 7
  • 53
  • 72