This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: Is this pthread_cond_wait() race possible
- From: Torvald Riegel <triegel at redhat dot com>
- To: Sebastian Andrzej Siewior <bigeasy at linutronix dot de>
- Cc: libc-alpha at sourceware dot org, tglx at linutronix dot de, Peter Zijlstra <peterz at infradead dot org>, Darren Hart <dvhart at infradead dot org>
- Date: Wed, 07 Jun 2017 21:41:38 +0200
- Subject: Re: Is this pthread_cond_wait() race possible
- Authentication-results: sourceware.org; auth=none
- Authentication-results: ext-mx09.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com
- Authentication-results: ext-mx09.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=triegel at redhat dot com
- Dkim-filter: OpenDKIM Filter v2.11.0 mx1.redhat.com A90126198B
- Dmarc-filter: OpenDMARC Filter v1.3.2 mx1.redhat.com A90126198B
- References: <20170607164839.dtzwiag27lvo62vu@linutronix.de>
On Wed, 2017-06-07 at 18:48 +0200, Sebastian Andrzej Siewior wrote:
> Hi Torvald,
>
> I've been staring at the new pthread_cond_* code. Could you please tell
> if this race possible (two wait threads looking at the same __g_signals
> value while a third thread signals a wake before going to futex_wait()):
>
> T1 T2 T3
>
> __pthread_cond_wait_common()
> __condvar_fetch_add_wseq_acquire (cond, 2);
> __pthread_mutex_unlock_usercnt();
>
> __pthread_cond_wait_common()
> __condvar_fetch_add_wseq_acquire (cond, 2);
> __pthread_mutex_unlock_usercnt();
>
> __pthread_cond_signal()
> if ((cond->__data.__g_size[g1] != 0) …
>
> /* Add a signal. */
> atomic_fetch_add_relaxed (cond->__data.__g_signals + g1, 2);
>
> signals = atomic_load_acquire (cond->__data.__g_signals + g);
> signals = atomic_load_acquire (cond->__data.__g_signals + g);
>
> signals = 2 signals = 2
>
> /* If there is an available signal, don't block. */
> if (signals != 0) if (signals != 0)
> break; break;
>
> while (!atomic_compare_exchange_weak_acquire (cond->__data.__g_signals + g,
> &signals, signals - 2));
> signals = 0
> while (!atomic_compare_exchange_weak_acquire (cond->__data.__g_signals + g,
> &signals, signals - 2));
> signals = (int) -2
The second CAS would expect a value of 2 in *(cond->__data.__g_signals +
g). Because the first CAS succeeded in your example, the second CAS
will fail, and T2 will update it's view of __g_signals and store that in
signals.