commit 3eb4f9edd0509bc40d38cfd3dfae08e489e0cc76 Author: Mikolaj Golub Date: Sun Sep 1 00:34:24 2013 +0300 QUEUE_INSERT2/TAKE2 are used for queues that may have several consumers and producers, so use cv_broadcast() insted of cv_signal() when waiking up threads waiting on empty queue. Before the fix the following scenario was possible: 2 threads are waiting on empty queue, 2 threads are inserting simultaneously. The first inserting thread detects that the queue is empty and is going to send the signal, but before it sends the second thread inserts too. When the first sends the signal only one of the waiting threads receive it while the other one may wait forever. The scenario above is is beleved to be the cause of observed cases, when ggate_recv_thread() was getting stuck on taking free request, while the free queue was not empty. diff --git a/sbin/hastd/primary.c b/sbin/hastd/primary.c index a1cad51..83770fa 100644 --- a/sbin/hastd/primary.c +++ b/sbin/hastd/primary.c @@ -186,7 +186,7 @@ static pthread_mutex_t metadata_lock; TAILQ_INSERT_TAIL(&hio_##name##_list, (hio), hio_##name##_next);\ mtx_unlock(&hio_##name##_list_lock); \ if (_wakeup) \ - cv_signal(&hio_##name##_list_cond); \ + cv_broadcast(&hio_##name##_list_cond); \ } while (0) #define QUEUE_TAKE1(hio, name, ncomp, timeout) do { \ bool _last; \