Bug 94849

Summary: libasyncns using pthreads blocks until workers die on free()
Product: libasyncns Reporter: Danylenko Mykhailo <isbear>
Component: generalAssignee: Lennart Poettering <lennart>
Status: NEW --- QA Contact: Lennart Poettering <lennart>
Severity: major    
Priority: medium    
Version: unspecified   
Hardware: x86-64 (AMD64)   
OS: Linux (All)   
Whiteboard:
i915 platform: i915 features:

Description Danylenko Mykhailo 2016-04-06 19:52:29 UTC
When using libasyncns with pthreads support, it freezes entire application, when you try to asyncns_free() instance, that have one of its workers blocked by getaddrinfo() (worker may be blocked eg. because of some problem with resolver servers).

An easy way to reproduce this bug is to set your nameserver in resolv.conf to something non-existent (like 1.2.3.4), then create asyncns resolver, make a request, and then immediately asyncns_free() resolver. It will block the application, until worker gets network timeout.

The problem, as I see it, lies in this code (in asyncns_free()):

    /* Now terminate them and wait until they are gone. */
    for (p = 0; p < asyncns->valid_workers; p++) {
#ifndef HAVE_PTHREAD
        kill(asyncns->workers[p], SIGTERM);
        for (;;) {
            if (waitpid(asyncns->workers[p], NULL, 0) >= 0 || errno != EINTR)
                break;
        }
#else
        for (;;) {
            if (pthread_join(asyncns->workers[p], NULL) != EINTR)
                break;
        }
#endif
    }

So, when pthreads are not in use, it kill()'s worker, then wait()'s for it. When they are used - it just pthread_join()'s them, which, AFAICS, is equal to just wait(). I'm no expert on threading, but I've found, that pthread_cancel() just before waiting cycle solves this problem. Please, consider including this fix (or any other, that resolves the problem) into the upstream.

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.