-
Philip Withnall authored
res_query() uses global state in the form of the struct __res_state which contains the contents of resolv.conf (and other things). On Linux, this state seems to be thread-local, so there is no problem. On OS X, however, it is not, and hence multiple res_query() calls from parallel threads will compete and return bogus results. The fix for this is to use res_nquery(), introduced in BIND 8.2, which takes an explicit state argument. This allows us to manually store the state thread-locally. If res_nquery() isn’t available, we fall back to res_query(). It should be available on OS X though. As a data point, it’s available on Fedora 27. There’s a slight complication in the fact that OS X requires the state to be freed using res_ndestroy() rather than res_nclose(). Linux uses res_nclose(). (See, for example, the NetBSD man page: https://www.unix.com/man-page/netbsd/3/res_ninit/. The Linux one is incomplete and not so useful: http://man7.org/linux/man-pages/man3/resolver.3.html. ) The new code will call res_ninit() once per res_nquery() task. This is not optimal, but no worse than before — since res_query() was being called in a worker thread, on Linux, it would implicitly initialise the thread-local struct __res_state when it was called. We’ve essentially just made that explicit. In practical terms, this means a stat("/etc/resolv.conf") call per res_nquery() task. In future, we could improve this by using an explicit thread pool with some manually-created worker threads, each of which initialises a struct __res_state on spawning, and only updates it on receiving the #GResolver::reload signal. Signed-off-by: Philip Withnall <withnall@endlessm.com> https://bugzilla.gnome.org/show_bug.cgi?id=792050
40be86bb