From owner-freebsd-threads@FreeBSD.ORG Thu Aug 12 09:33:58 2010 Return-Path: Delivered-To: freebsd-threads@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id EDEE3106564A; Thu, 12 Aug 2010 09:33:58 +0000 (UTC) (envelope-from kostikbel@gmail.com) Received: from mail.zoral.com.ua (mx0.zoral.com.ua [91.193.166.200]) by mx1.freebsd.org (Postfix) with ESMTP id 6F1558FC13; Thu, 12 Aug 2010 09:33:58 +0000 (UTC) Received: from deviant.kiev.zoral.com.ua (root@deviant.kiev.zoral.com.ua [10.1.1.148]) by mail.zoral.com.ua (8.14.2/8.14.2) with ESMTP id o7C9XrBf006722 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Thu, 12 Aug 2010 12:33:53 +0300 (EEST) (envelope-from kostikbel@gmail.com) Received: from deviant.kiev.zoral.com.ua (kostik@localhost [127.0.0.1]) by deviant.kiev.zoral.com.ua (8.14.4/8.14.4) with ESMTP id o7C9XrfC005628; Thu, 12 Aug 2010 12:33:53 +0300 (EEST) (envelope-from kostikbel@gmail.com) Received: (from kostik@localhost) by deviant.kiev.zoral.com.ua (8.14.4/8.14.4/Submit) id o7C9Xr9B005627; Thu, 12 Aug 2010 12:33:53 +0300 (EEST) (envelope-from kostikbel@gmail.com) X-Authentication-Warning: deviant.kiev.zoral.com.ua: kostik set sender to kostikbel@gmail.com using -f Date: Thu, 12 Aug 2010 12:33:53 +0300 From: Kostik Belousov To: David Xu Message-ID: <20100812093353.GS2396@deviant.kiev.zoral.com.ua> References: <20100811204758.GQ2396@deviant.kiev.zoral.com.ua> <4C63D42D.8040606@freebsd.org> <20100812083006.GR2396@deviant.kiev.zoral.com.ua> <4C642E9B.8000300@freebsd.org> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="2uzDqHpccQJpqF2n" Content-Disposition: inline In-Reply-To: <4C642E9B.8000300@freebsd.org> User-Agent: Mutt/1.4.2.3i X-Virus-Scanned: clamav-milter 0.95.2 at skuns.kiev.zoral.com.ua X-Virus-Status: Clean X-Spam-Status: No, score=-2.2 required=5.0 tests=ALL_TRUSTED,AWL,BAYES_50, DNS_FROM_OPENWHOIS autolearn=no version=3.2.5 X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on skuns.kiev.zoral.com.ua Cc: freebsd-threads@freebsd.org Subject: Re: PTHREAD_CANCEL_DEFERRED X-BeenThere: freebsd-threads@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Threading on FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 12 Aug 2010 09:33:59 -0000 --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--