Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 12 Aug 2010 12:33:53 +0300
From:      Kostik Belousov <kostikbel@gmail.com>
To:        David Xu <davidxu@freebsd.org>
Cc:        freebsd-threads@freebsd.org
Subject:   Re: PTHREAD_CANCEL_DEFERRED
Message-ID:  <20100812093353.GS2396@deviant.kiev.zoral.com.ua>
In-Reply-To: <4C642E9B.8000300@freebsd.org>
References:  <20100811204758.GQ2396@deviant.kiev.zoral.com.ua> <4C63D42D.8040606@freebsd.org> <20100812083006.GR2396@deviant.kiev.zoral.com.ua> <4C642E9B.8000300@freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help

--2uzDqHpccQJpqF2n
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

On Thu, Aug 12, 2010 at 05:25:47PM +0000, David Xu wrote:
> Kostik Belousov wrote:
> >On Thu, Aug 12, 2010 at 10:59:57AM +0000, David Xu wrote:
> >>Kostik Belousov wrote:
> >>>Hi,
> >>>Let consider the thread in the state where the cancelation is enabled
> >>>and cancelation mode set to the PTHREAD_CANCEL_DEFERRED.
> >>>
> >>>SUSv4 says the following:
> >>>Whenever a thread has cancelability enabled and a cancellation request
> >>>has been made with that thread as the target, and the thread then
> >>>calls any function that is a cancellation point (such as
> >>>pthread_testcancel() or read()), the cancellation request shall be
> >>>acted upon before the function returns. If a thread has cancelability
> >>>enabled and a cancellation request is made with the thread as a target
> >>>while the thread is suspended at a cancellation point, the thread
> >>>shall be awakened and the cancellation request shall be acted upon.
> >>>
> >>>Take the close(2) as example, and assume that the cancel is enabled
> >>>for the thread in deferred mode. libthr wrapper around the syscall
> >>>executes this:
> >>>
> >>>    	curthread->cancel_point++;
> >>>	testcancel(curthread);
> >>>	__sys_close(fd);
> >>>	curthread->cancel_point--;
> >>>
> >>>The pthread_cancel() sends the SIGCANCEL signal to the
> >>>thread. SIGCANCEL handler calls pthread_exit() if thread has the
> >>>cancel_point greater then 0.
> >>>
> >>>I think this is not right. For instance, thread can be canceled due to
> >>>SIGCANCEL delivery at the point after the return into the usermode
> >>>from close(), but before cancel_point is decremented. IMO, the cited
> >>>statements from the SUSv4 prohibit such behaviour. We should cancel
> >>>either before closing fd, or during the sleep in close(), but then the
> >>>syscall should be aborted ("as if signal is delivered"), and again fd
> >>>should not be closed.
> >>>
> >>>Actually, besides not being compliant, I think that the current
> >>>behaviour is not useful, since in deferred case, we cannot know
> >>>whether the action by the call that is cancelation point was performed
> >>>or not.
> >>>
> >>>This is not a rant, I probably will fix the issue if it is agreed
> >>>upon. Opinions ?
> >>it is true that a cancellation point does not return when cancellation
> >>happens, so we really does not know if it did something or not,
> >>and SUSv4 does not say cancellation point is an atomic transaction,
> >>and whether it will rollback when cancellation happens, the problem may
> >>happen even if you want to fix it, if the cancellation request is sent
> >>after int 0x80 instruction returns (on i386) but before libc close()
> >>stub returns, the cancellation still can happen, so could you tell
> >>if the file handle is closed or not ? there is no way to tell
> >>caller that the close() really did something.
> >>I found the issue when I wrote the code, and it seems Linux does
> >>it in same way, so I had not done further work on it.
> >
> >What I am proposing is to not cancel if close() indeed closed the
> >descriptor. The same could be done for all other cancelation points that
> >are syscalls.
> >
> >I evaluated the possible implementation. It looks like it is enough,
> >when thread is switched to cancel enabled and deferred mode, to make
> >SIGCANCEL delivery special. Namely, it should be only delivered at the
> >cancelable syscall _entry_ point and on syscall return when error is
> >EINTR or ERESTART. pthread_testcancel() is also becoming a dummy syscall,
> >with the same rules of SIGCANCEL delivery.
> >
> >Cancelable syscalls would be marked in the syscall table, the cost of
> >the change is that pthread_setcanceltype() becomes a syscall.
>=20
> This might be not enough, because I found a scenario:
> suppose there are two threads A and B:
>=20
> B: pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED)
> A: pthread_cancel(B)
>    it sets cancel_pending to 1 and send SIGCANCEL to B
> B: got SIGCANCEL delivered to userland and did nothing
>    because it is not at cancel point.
[1]

> B: still doing other things...
> B: call close()
[2]

> B: sleep in kernel because no SIGCANCEL found.
>=20
> if you don't call testcancel() in close() stub like current libthr did,
> B won't response to the cancel request, you lost the race.
This situation should be handled by my proposal, since SIGCANCEL is
delivered only
- at the syscall entry point
- at the syscall premature return
Userspace would not get SIGCANCEL at time of [1], instead, signal will
be delivered at [2].

--2uzDqHpccQJpqF2n
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (FreeBSD)

iEYEARECAAYFAkxjwAEACgkQC3+MBN1Mb4jk1QCg96cshPEi1eqB6PqzMYLB0caU
C9EAoLXYRM8eQHm0Qxtx/TCiT4ISe4r2
=X/WM
-----END PGP SIGNATURE-----

--2uzDqHpccQJpqF2n--



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