diff options
author | dormando <dormando@rydia.net> | 2011-07-27 08:46:24 -0700 |
---|---|---|
committer | dormando <dormando@rydia.net> | 2011-07-30 10:47:21 -0700 |
commit | 2c56090933e01ea5ab7d0c6e6530ea73b0933cf9 (patch) | |
tree | 74f0d9532a1192a314691ad78997806c8f76e4df | |
parent | d07bfbe0f4afa842735712939fefad1bbafe577b (diff) | |
download | memcached-2c56090933e01ea5ab7d0c6e6530ea73b0933cf9.tar.gz |
Fix incredibly slim race for maxconns handler
I am an idiot: inbetween setting allow_new_conns -> false and calling the
maxconns subroutine, another thread could have already flipped it back. This
is probably due to a lack of strict memory barriers allowing the assignments
to the allow_new_conns variable to be reordered outside of the lock.
Instead of copy/pasting the handler enabler code, we now treat an fd argument
of -42 as special and force the callback to run once. Normally fd is -1 since there's no associated socket for the callback.
-rw-r--r-- | memcached.c | 4 |
1 files changed, 2 insertions, 2 deletions
diff --git a/memcached.c b/memcached.c index 7905e6c..c82f5c5 100644 --- a/memcached.c +++ b/memcached.c @@ -130,7 +130,7 @@ static struct event maxconnsevent; static void maxconns_handler(const int fd, const short which, void *arg) { struct timeval t = {.tv_sec = 0, .tv_usec = 10000}; - if (allow_new_conns == false) { + if (fd == -42 || allow_new_conns == false) { /* reschedule in 10ms if we need to keep polling */ evtimer_set(&maxconnsevent, maxconns_handler, 0); event_base_set(main_base, &maxconnsevent); @@ -3386,7 +3386,7 @@ void do_accept_new_conns(const bool do_accept) { stats.listen_disabled_num++; STATS_UNLOCK(); allow_new_conns = false; - maxconns_handler(0, 0, 0); + maxconns_handler(-42, 0, 0); } } |