Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 17 Jan 2016 22:18:53 +0100
From:      Jilles Tjoelker <jilles@stack.nl>
To:        Konstantin Belousov <kib@kib.kiev.ua>
Cc:        Boris Astardzhiev <boris.astardzhiev@gmail.com>, net@freebsd.org
Subject:   Re: Does FreeBSD have sendmmsg or recvmmsg system calls?
Message-ID:  <20160117211853.GA37847@stack.nl>
In-Reply-To: <20160116202534.GK3942@kib.kiev.ua>
References:  <20160108172323.W1815@besplex.bde.org> <20160108075815.3243.qmail@f5-external.bushwire.net> <CAJ-VmonYPhcN-gikuYQU_k5GaTAqTijoxR_0ORV4BZqsHMRJSg@mail.gmail.com> <20160108204606.G2420@besplex.bde.org> <CAJ-Vmom26mukSv3JmsmNiAONvpc6f1bQ%2BujO25qefGHY=5przA@mail.gmail.com> <CAP=KkTwG0SVUmrBuWm33EC-tG4tMTdF5rLZQ_u6G1=-ujnfjkA@mail.gmail.com> <20160113080349.GC72455@kib.kiev.ua> <CAP=KkTxVaqZvigg78Dg%2Bv8kuTCaZyky8x15NHqD9uabuRKRkMw@mail.gmail.com> <20160116195657.GJ3942@kib.kiev.ua> <20160116202534.GK3942@kib.kiev.ua>

next in thread | previous in thread | raw e-mail | index | archive | help
On Sat, Jan 16, 2016 at 10:25:34PM +0200, Konstantin Belousov wrote:
> On Sat, Jan 16, 2016 at 09:56:57PM +0200, Konstantin Belousov wrote:
> > After thinking some more, I believe I managed to construct a possible
> > way to implement this, in libc, with some libthr extensions.  Basically,
> > the idea is to have function pthread_cancel_is_pending_np(), which
> > would return the state of pending cancel.  For some time I thought that
> > this cannot work, because cancellation could happen between call to
> > the cancel_is_pending() and next recvmmsg().  But, libc has a privilege
> > of having access to the syscalls without libthr interposing, just
> > call __sys_recvmmsg(), which would give EINTR on the cancel attempt.
> > This is an implementation detail, but we can rely on it in implementation.
> > In other words, the structure of the code would be  like this
> > 	for (i = 0; i < vlen; i++) {
> > 		if (pthread_cancel_is_pending_np())
> > 			goto out;
> Right after writing the text and hitting send, I realized that the
> pthread_cancel_is_pending_np() is not needed at all.  You get EINTR
> from __sys_recvmsg() on the cancel attempt, so everything would just
> work without the function.

> The crusial part is to use __sys_recvmsg instead of interposable
> _recvmsg().

This will typically work (if the cancellation occurs while blocked
inside __sys_recvmsg()) but has the usual problem of relying on [EINTR]:
lost wakeups. This is certainly less bad than using the interposable
recvmsg(), though, which would discard the already received data.

As a slight modification, the first recvmsg could use the interposable
version, since there is no pending data at that point. This avoids
needing to call pthread_testcancel() manually.

The regular cancellation code closes this race window using the
undocumented thr_wake() system call, on the thread itself, in the signal
handler for the cancellation signal. This causes the next attempt to
sleep(9) to fail with [EINTR]. (On another note, it appears to be
possible for user code (cleanup handlers and pthread_key_create()
destructors) to be called with thr_wake() still active, if the
cancellation signal handler is called immediately after the cancellation
point system call returns.)

The race in recvmmsg could be removed using this mechanism but it
requires either a separate version of recvmmsg in libthr or a new
interface in libthr. I imagine the new interface as a new cancellation
type which causes cancellation point functions such as recvmsg() to fail
with a new errno when cancelled while leaving cancellation pending. This
seems conceptually possible but adds some code to the common path for
cancellation points. A new version of pthread_testcancel() with a return
value would be needed.

-- 
Jilles Tjoelker



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20160117211853.GA37847>