[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[Libevent-users] Is evthread_use_pthreads required for isolated evdns event_bases?



Hi there,

I'm developing a multithreaded proxy server (running on Linux 2.6.32;
libevent-2.0.20-stable), where each event_base is isolated to a single
thread.

As I understand, by isolating the event_bases per thread and not calling
evthread_use_pthreads(), I can avoid locking overheads.  AFAIK,
evthread_use_pthreads() only needs to be called when multiple threads share
an event_base.  If this is incorrect, then please disregard this email.
Otherwise, read on... :)

On one particular site, after about two weaks of heavy load (e.g. 500
req/sec), the evdns.c:transaction_id_pick() gets stuck in an infinite loop
(all threads using evdns get stuck and requests cannot be served).

Via a gdb debug session, I found that transaction_id_pick()'s call to
evutil_secure_rng_get_bytes() always returns the same trans_id.  I could
not get any further due to compiler optimizations, so I rebuilt libevent
without optimizations and allowed it to run for another two weeks on the
customers site.  Again, evdns.c:transaction_id_pick() got stuck in an
infinite loop.

This time I found that evdns's RC4-ish pseudorandom number generator
arc4random.c:arc4_getbyte() is always returning the same value.  Inspecting
further, I found that the prng's permutation table (rs) is in an impossible
state (according to the arc4 logic):

(gdb) p rs
$1 = {i = 212 '\324', j = 102 'f',
  s =
"\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\357\
 357\357\
357\357\357\357\357\357",
<incomplete sequence \357>}
(gdb) p arc4_count
$2 = 1053737

So, something has trampled the memory.

Looking back through the libevent code, it seems that the prng's locks are
only initialised if evthread_use_pthreads() or
evthread_enable_lock_debuging() is called.

evthread_use_pthreads()
evthread_set_lock_callbacks()
event_global_setup_locks_()
evutil_secure_rng_global_setup_locks_()
arc4rand_lock()

Meanwhile, the arc4 permutation table appears to be shared by all
event_bases.

struct arc4_stream {
        unsigned char i;
        unsigned char j;
        unsigned char s[256];
};

....

static struct arc4_stream rs;

Is this a bug or is evthread_use_pthreads() required for multiple --
isolated -- threads to use evdns?

Cheers.
*Joe

***********************************************************************
To unsubscribe, send an e-mail to majordomo@xxxxxxxxxxxxx with
unsubscribe libevent-users    in the body.