Date: Fri, 6 May 2016 14:00:48 +0100 From: Martin Simmons <martin@lispworks.com> To: Konstantin Belousov <kostikbel@gmail.com> Cc: threads@freebsd.org, arch@freebsd.org Subject: Re: Robust mutexes implementation Message-ID: <201605061300.u46D0mhN008053@higson.cam.lispworks.com> In-Reply-To: <20160505185810.GF2422@kib.kiev.ua> (message from Konstantin Belousov on Thu, 5 May 2016 21:58:10 %2B0300) References: <20160505131029.GE2422@kib.kiev.ua> <201605051720.u45HKZ76021094@higson.cam.lispworks.com> <20160505185810.GF2422@kib.kiev.ua>
next in thread | previous in thread | raw e-mail | index | archive | help
>>>>> On Thu, 5 May 2016 21:58:10 +0300, Konstantin Belousov said: > > Yes. In fact I wrote the __containerof stuff only later, initial > version of the patch did relied on the fact that m_lock is at the > beginning of pthread_mutex. > > I rewrote the code in enqueue, and there is one more similar check in > dequeue_mutex(). > > Updated patch is at https://kib.kiev.ua/kib/pshared/robust.2.patch . OK. > On Thu, May 05, 2016 at 06:20:35PM +0100, Martin Simmons wrote: > > Also, is it safe to assume memory ordering between the assignments of > > m->m_lock.m_rb_lnk and curthread->robust_list? Maybe it is OK because the > > kernel will never read curthread->robust_list until after the CPU executing > > enqueue_mutex has passed a memory barrier? > > Inter-CPU ordering (I suppose you mean this, because you mention > barriers) only matter when we consider multi-threaded interaction. > In case of dequeue_mutex, paired to corresponding enqueue_mutex(), > the calls occur in the same thread, and the thread is always > self-consistent. Agreed. > WRT possible reordering, we in fact only care that enqueue writes do > not become visible before lock is obtained, and dequeue must finish > for external observers before lock is released. This is ensured by > the umutex lock semantic, which has neccessary acquire barrier on > lock and release barrier on unlock. I meant the case where CPU 1 claims the lock, executing this from enqueue_mutex: m->m_lock.m_rb_lnk = 0; /* A */ *rl = (uintptr_t)&m->m_lock; /* B */ and then the thread dies and CPU 2 cleans up the dead thread executing this from umtx_handle_rb: error = copyin((void *)rbp, &m, sizeof(m)); /* C */ *rb_list = m.m_rb_lnk; /* D */ where rbp is the value stored into *rl at B by CPU 1. What ensures that CPU 1's store at A is seen by CPU 2 when it reads the value at D? I'm hoping this is covered by something that I don't understand, but I was worried by the comment "consistent even in the case of thread termination at arbitrary moment" above enqueue_mutex. __Martin
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201605061300.u46D0mhN008053>