haproxy/include/common
Willy Tarreau 01abd02508 BUG/MEDIUM: listener: use a self-locked list for the dequeue lists
There is a very difficult to reproduce race in the listener's accept
code, which is much easier to reproduce once connection limits are
properly enforced. It's an ABBA lock issue :

  - the following functions take l->lock then lq_lock :
      disable_listener, pause_listener, listener_full, limit_listener,
      do_unbind_listener

  - the following ones take lq_lock then l->lock :
      resume_listener, dequeue_all_listener

This is because __resume_listener() only takes the listener's lock
and expects to be called with lq_lock held. The problem can easily
happen when listener_full() and limit_listener() are called a lot
while in parallel another thread releases sessions for the same
listener using listener_release() which in turn calls resume_listener().

This scenario is more prevalent in 2.0-dev since the removal of the
accept lock in listener_accept(). However in 1.9 and before, a different
but extremely unlikely scenario can happen :

      thread1                                  thread2
         ............................  enter listener_accept()
  limit_listener()
         ............................  long pause before taking the lock
  session_free()
    dequeue_all_listeners()
      lock(lq_lock) [1]
         ............................  try_lock(l->lock) [2]
      __resume_listener()
        spin_lock(l->lock) =>WAIT[2]
         ............................  accept()
                                       l->accept()
                                       nbconn==maxconn =>
                                         listener_full()
                                           state==LI_LIMITED =>
                                             lock(lq_lock) =>DEADLOCK[1]!

In practice it is almost impossible to trigger it because it requires
to limit both on the listener's maxconn and the frontend's rate limit,
at the same time, and to release the listener when the connection rate
goes below the limit between poll() returns the FD and the lock is
taken (a few nanoseconds). But maybe with threads competing on the
same core it has more chances to appear.

This patch removes the lq_lock and replaces it with a lockless queue
for the listener's wait queue (well, technically speaking a self-locked
queue) brought by commit a8434ec14 ("MINOR: lists: Implement locked
variations.") and its few subsequent fixes. This relieves us from the
need of the lq_lock and removes the deadlock. It also gets rid of the
distinction between __resume_listener() and resume_listener() since the
only difference was the lq_lock. All listener removals from the list
are now unconditional to avoid races on the state. It's worth noting
that the list used to never be initialized and that it used to work
only thanks to the state tests, so the initialization has now been
added.

This patch must carefully be backported to 1.9 and very likely 1.8.
It is mandatory to be careful about replacing all manipulations of
l->wait_queue, global.listener_queue and p->listener_queue.
2019-02-28 16:08:54 +01:00
..
accept4.h BUILD: syscalls: remove improper inline statement in front of syscalls 2014-05-08 22:38:02 +02:00
base64.h [MINOR] add encode/decode function for 30-bit integers from/to base64 2010-10-30 19:04:33 +02:00
buf.h BUG/MEDIUM: buffer: Make sure b_is_null handles buffers waiting for allocation. 2019-01-31 08:07:17 +01:00
buffer.h MEDIUM: memory: make the pool cache an array and not a thread_local 2018-11-26 19:50:32 +01:00
cfgparse.h MINOR: cfgparse: make the process/thread parser support a maximum value 2019-01-26 13:25:14 +01:00
chunk.h CLEANUP: Fix typo in the chunk headers file 2018-12-02 18:37:56 +01:00
compat.h MINOR: compat: automatically detect support for crypt_r() 2018-10-29 19:14:14 +01:00
compiler.h MINOR: compiler: add a new macro ALREADY_CHECKED() 2018-12-08 15:27:03 +01:00
config.h MINOR: debug: Add an option that causes random allocation failures. 2019-01-31 19:38:25 +01:00
debug.h MINOR: debug: make the ABORT_NOW macro use a volatile int 2018-12-16 08:17:23 +01:00
defaults.h MINOR: config: make MAX_PROCS configurable at build time 2019-02-07 15:10:19 +01:00
epoll.h MAJOR: polling: replace epoll with sepoll and remove sepoll 2012-11-11 20:53:30 +01:00
errors.h [MINOR] errors: provide new status codes for config parsing functions 2010-08-10 14:01:15 +02:00
h1.h MINOR: h1: make the H1 headers block parser able to parse headers only 2019-01-04 10:48:03 +01:00
h2.h BUG/MEDIUM: h2/htx: Correctly handle interim responses when HTX is enabled 2019-02-19 16:26:14 +01:00
hash.h MINOR: hash: add new function hash_crc32c 2018-03-21 05:04:01 +01:00
hathreads.h BUG/MEDIUM: listener: use a self-locked list for the dequeue lists 2019-02-28 16:08:54 +01:00
hpack-dec.h MAJOR: chunks: replace struct chunk with struct buffer 2018-07-19 16:23:43 +02:00
hpack-enc.h MINOR: hpack: provide a function to encode an HTTP path 2018-12-11 09:07:02 +01:00
hpack-huff.h MINOR: hpack: implement the HPACK Huffman table decoder 2017-10-31 18:03:24 +01:00
hpack-tbl.h BUG/MINOR: hpack: return a compression error on invalid table size updates 2019-01-24 15:27:06 +01:00
http-hdr.h MINOR: http: add http_hdr_del() to remove a header from a list 2018-09-14 17:40:35 +02:00
http.h MEDIUM: proto_htx: Convert all HTTP error messages into HTX 2018-12-01 17:37:27 +01:00
htx.h MINOR: htx: Add function to drain data from an HTX message 2019-02-26 14:04:23 +01:00
initcall.h BUILD/MEDIUM: initcall: Fix build on MacOS. 2019-02-15 14:32:35 +01:00
ist.h MEDIUM: ist: use local conversion arrays to case conversion 2018-12-07 13:25:59 +01:00
istbuf.h MINOR: buffer: rename the data length member to '->data' 2018-07-19 16:23:43 +02:00
memory.h MINOR: pools: Cast to volatile int * instead of int *. 2018-12-16 08:15:16 +01:00
mini-clist.h MINOR: list: make the delete and pop operations idempotent 2019-02-28 16:03:29 +01:00
namespace.h MINOR: namespaces: don't build namespace.c if disabled 2018-11-12 19:15:15 +01:00
net_helper.h MINOR: net_helper: add 64-bit read/write functions 2017-09-21 06:27:08 +02:00
regex.h MINOR: threads/regex: Change Regex trash buffer into a thread local variable 2017-10-31 13:58:31 +01:00
splice.h BUILD: syscalls: remove improper inline statement in front of syscalls 2014-05-08 22:38:02 +02:00
standard.h MINOR: tools: implement functions to look up the nth bit set in a mask 2019-02-27 14:27:07 +01:00
syscall.h BUILD: enable build on Linux/s390x 2015-10-12 20:58:51 +02:00
template.h [CLEANUP] included common/version.h everywhere 2006-06-29 18:54:54 +02:00
ticks.h [MEDIUM] scheduler: get rid of the 4 trees thanks and use ebtree v4.1 2009-03-21 10:25:14 +01:00
time.h MINOR: poller: move the call of tv_update_date() back to the pollers 2018-11-22 18:57:37 +01:00
tools.h [MINOR] tools: add two macros MID_RANGE and MAX_RANGE 2011-03-28 15:55:43 +02:00
uri_auth.h MINOR: stats: add ST_SHOWADMIN to pass the admin info in the regular flags 2016-03-11 17:08:05 +01:00
version.h BUILD: add a new file "version.c" to carry version updates 2019-01-04 18:20:32 +01:00
xref.h MINOR: xref: Add missing barriers. 2019-01-31 19:38:25 +01:00