Hi guys! I found strange behaviour in libuv. Help me to understand is it a 
bug, or something wrong with me:-)

Info:
libuv from github (master, 1.4.2, 1.x) tested with optimization and 
without, in debug and in release mode
gcc version 4.9.1 (Ubuntu 4.9.1-16ubuntu6)
Ubuntu 14.10

My use case:
I want to send lots of unique uv_async_t, and all callbacks should be 
invoked. So I need to have different uv_async_t for each sending.
In each callback that would be invoked I need to close a handle because 
it's not need anymore.
To keep event loop running I send "blocking" uv_async_t and don't close it 
to keep a handle in active state.

Strange:
I found that !sometimes! uv_run() stops.

Trying to figure out:
I started to debug my code and found that uv_run sometimes quits because 
uv__loop_alive(loop) return 0.
It happens because uv__has_active_handles(loop) becomes false, due to 
((loop)->active_handles > 0) condition is false.
Why the condition is false when there should be at least one active handle 
in the loop, which was sent and was not closed?
It sounds like a joke, but in case uv_run don't quit the value of 
loop->active_handles is about UINT_MAX!
Look the code of libuv: "unsigned int active_handles". If we have value 
about UINT_MAX than we decrement this variable more than needed!

I found that there is 1 place where loop->active_handles decrements: 
uv__active_handle_rm(h).
And there is 2 sequences of function invocation which lead to this call, 
they are:
    1. uv_run -> uv_async_close -> uv_handles_stop -> uv_active_handle_rm
    2. uv_close -> uv_async_close -> uv_handles_stop -> uv_active_handle_rm

I supose that there is 2 ways why it can be:
    1. libuv don't increment loop->active_handles sometimes but decrement it
    2. libuv decrement loop->active_handles more than needed

Test example:
#include <uv.h>

int main()
{
    uv_loop_t *loop = uv_default_loop();
    
    // Blocking async, need to loop don't quit from run
    uv_async_t async;
    uv_async_init(loop, &async, [](uv_async_t* a){
        std::cout << "blocking active handle\n";
        // no close! it's an active handle
    });
    uv_async_send(&async);
    
    // Create thread for event loop
    uv_thread_t th;
    uv_thread_create(&th,
                    [](void *arg)
                    {
                        uv_run((uv_loop_t*)arg, UV_RUN_DEFAULT);
                        std::cout << "Quit from event loop\n";
                    },
                    loop
    ); // uv_thread_create
                    
    // Send lots of async events
    uv_async_t asyncs[1000];
    for (int i=0; i<1000; i++)
    {
        asyncs[i] = uv_async_t();
        uv_async_init(loop, &asyncs[i], [](uv_async_t* a)
        {
            std::cout << "async\n";
            // async not need anymore - close it
            // after that handle becomes inactive
            uv_close((uv_handle_t*)a, [](uv_handle_t*)
            {
                // may free uv_handle_t->data here
                std::cout << "close\n";
            });
        });
        uv_async_send(&asyncs[i]);
    }                
    
    uv_thread_join(&th);
    
    return 0;
}





-- 
You received this message because you are subscribed to the Google Groups 
"libuv" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/libuv.
For more options, visit https://groups.google.com/d/optout.

Reply via email to