From owner-p4-projects@FreeBSD.ORG Sun Jan 2 13:26:33 2005 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 0132716A4D0; Sun, 2 Jan 2005 13:26:32 +0000 (GMT) Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id D037916A4CE for ; Sun, 2 Jan 2005 13:26:32 +0000 (GMT) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id 99D7743D54 for ; Sun, 2 Jan 2005 13:26:32 +0000 (GMT) (envelope-from davidxu@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.1/8.13.1) with ESMTP id j02DQWQ0013890 for ; Sun, 2 Jan 2005 13:26:32 GMT (envelope-from davidxu@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.1/8.13.1/Submit) id j02DQWCV013887 for perforce@freebsd.org; Sun, 2 Jan 2005 13:26:32 GMT (envelope-from davidxu@freebsd.org) Date: Sun, 2 Jan 2005 13:26:32 GMT Message-Id: <200501021326.j02DQWCV013887@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to davidxu@freebsd.org using -f From: David Xu To: Perforce Change Reviews Subject: PERFORCE change 68138 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 02 Jan 2005 13:26:33 -0000 http://perforce.freebsd.org/chv.cgi?CH=68138 Change 68138 by davidxu@davidxu_tiger on 2005/01/02 13:26:06 simplicy cancellation code by not using thread lock. Affected files ... .. //depot/projects/davidxu_thread/src/lib/libthread/thread/thr_cancel.c#5 edit .. //depot/projects/davidxu_thread/src/lib/libthread/thread/thr_exit.c#5 edit .. //depot/projects/davidxu_thread/src/lib/libthread/thread/thr_mutex.c#8 edit .. //depot/projects/davidxu_thread/src/lib/libthread/thread/thr_private.h#10 edit .. //depot/projects/davidxu_thread/src/lib/libthread/thread/thr_sig.c#5 edit Differences ... ==== //depot/projects/davidxu_thread/src/lib/libthread/thread/thr_cancel.c#5 (text+ko) ==== @@ -1,8 +1,32 @@ /* - * David Leonard , 1999. Public domain. - * $FreeBSD: src/lib/libpthread/thread/thr_cancel.c,v 1.31 2003/12/09 02:20:56 davidxu Exp $ + * Copyright (c) 2005, David Xu + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + * */ -#include + #include #include "thr_private.h" @@ -11,183 +35,124 @@ __weak_reference(_pthread_setcanceltype, pthread_setcanceltype); __weak_reference(_pthread_testcancel, pthread_testcancel); -static inline int -checkcancel(struct pthread *curthread) -{ - /* - * Don't do cancellation again if it was already in progress. - */ - if ((curthread->cancelflags & - (THR_CANCEL_EXITING | THR_CANCELLING | THR_CANCEL_DISABLE | - THR_CANCEL_NEEDED)) == THR_CANCEL_NEEDED) { - curthread->cancelflags |= THR_CANCELLING; - return (1); - } - return (0); -} - -static inline void -testcancel(struct pthread *curthread) -{ - if (checkcancel(curthread) != 0) { - /* Unlock before exiting: */ - THR_UNLOCK(curthread); - pthread_exit(PTHREAD_CANCELED); - PANIC("cancel"); - } -} - int _pthread_cancel(pthread_t pthread) { struct pthread *curthread = _get_curthread(); - long tid = -1; - int ret; + int oldval, newval, ret; + + if ((ret = _thr_ref_add(curthread, pthread, 0)) != 0) + return (ret); + do { + oldval = pthread->cancelflags; + if (oldval & THR_CANCEL_NEEDED) + break; + newval = oldval | THR_CANCEL_NEEDED; + } while (!atomic_cmpset_acq_int(&pthread->cancelflags, oldval, newval)); + + if (!(oldval & THR_CANCEL_NEEDED) && SHOULD_ASYNC_CANCEL(newval)) + thr_kill(pthread->tid, SIGCANCEL); - THREAD_LIST_LOCK(curthread); - if ((ret = _thr_find_thread(curthread, pthread, 0)) == 0) { - /* - * Take the thread's lock while we change the cancel flags. - */ - THR_THREAD_LOCK(curthread, pthread); - THREAD_LIST_UNLOCK(curthread); - if (pthread->cancelflags & - (THR_CANCELLING | THR_CANCEL_EXITING)) { - THR_THREAD_UNLOCK(curthread, pthread); - return (0); - } - pthread->cancelflags |= THR_CANCEL_NEEDED; - if ((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0 && - ((pthread->cancelflags & THR_CANCEL_AT_POINT) != 0 || - (pthread->cancelflags & THR_CANCEL_ASYNCHRONOUS) != 0)) { - tid = pthread->tid; - thr_kill(tid, SIGCANCEL); - } - /* - * Release the thread's lock and remove the - * reference: - */ - THR_THREAD_UNLOCK(curthread, pthread); - } else { - THREAD_LIST_UNLOCK(curthread); - } - return (ret); + _thr_ref_delete(curthread, pthread); + return (0); } int _pthread_setcancelstate(int state, int *oldstate) { - struct pthread *curthread = _get_curthread(); - int need_exit = 0; - int ostate; - int ret; + struct pthread *curthread = _get_curthread(); + int oldval, newval; + + if (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE) + return (EINVAL); - /* Take the thread's lock while fiddling with the state: */ - THR_LOCK(curthread); + for (;;) { + oldval = curthread->cancelflags; + newval = (state == PTHREAD_CANCEL_DISABLE ? + oldval | THR_CANCEL_DISABLE : + oldval & ~THR_CANCEL_DISABLE); - if (curthread->cancelflags & THR_CANCEL_DISABLE) - ostate = PTHREAD_CANCEL_DISABLE; - else - ostate = PTHREAD_CANCEL_ENABLE; + if (oldstate != NULL) + *oldstate = ((oldval & THR_CANCEL_DISABLE) ? + PTHREAD_CANCEL_DISABLE : PTHREAD_CANCEL_ENABLE); - switch (state) { - case PTHREAD_CANCEL_ENABLE: - curthread->cancelflags &= ~THR_CANCEL_DISABLE; - if ((curthread->cancelflags & THR_CANCEL_ASYNCHRONOUS) != 0) - need_exit = checkcancel(curthread); - ret = 0; - break; - case PTHREAD_CANCEL_DISABLE: - curthread->cancelflags |= THR_CANCEL_DISABLE; - ret = 0; - break; - default: - ret = EINVAL; - } + if (oldval == newval) + break; - THR_UNLOCK(curthread); - if (need_exit != 0) { - pthread_exit(PTHREAD_CANCELED); - PANIC("cancel"); + if (atomic_cmpset_acq_int(&curthread->cancelflags, oldval, + newval)) { + if (SHOULD_CANCEL(newval)) + pthread_exit(PTHREAD_CANCELED); + break; + } } - if (ret == 0 && oldstate != NULL) - *oldstate = ostate; - - return (ret); + + return (0); } int _pthread_setcanceltype(int type, int *oldtype) { struct pthread *curthread = _get_curthread(); - int need_exit = 0; - int otype; - int ret; + int oldval, newval; - /* Take the thread's lock while fiddling with the state: */ - THR_LOCK(curthread); + if (type != PTHREAD_CANCEL_DEFERRED && + type != PTHREAD_CANCEL_ASYNCHRONOUS) + return (EINVAL); - if (curthread->cancelflags & THR_CANCEL_ASYNCHRONOUS) - otype = PTHREAD_CANCEL_ASYNCHRONOUS; - else - otype = PTHREAD_CANCEL_DEFERRED; - switch (type) { - case PTHREAD_CANCEL_ASYNCHRONOUS: - curthread->cancelflags |= THR_CANCEL_ASYNCHRONOUS; - need_exit = checkcancel(curthread); - ret = 0; - break; - case PTHREAD_CANCEL_DEFERRED: - curthread->cancelflags &= ~THR_CANCEL_ASYNCHRONOUS; - ret = 0; - break; - default: - ret = EINVAL; + for (;;) { + oldval = curthread->cancelflags; + if (oldtype != NULL) + *oldtype = ((oldval & THR_CANCEL_AT_POINT) ? + PTHREAD_CANCEL_ASYNCHRONOUS : + PTHREAD_CANCEL_DEFERRED); + newval = (type == PTHREAD_CANCEL_ASYNCHRONOUS ? + oldval | THR_CANCEL_AT_POINT : + oldval & ~THR_CANCEL_AT_POINT); + if (oldval == newval) + break; + if (atomic_cmpset_acq_int(&curthread->cancelflags, oldval, + newval)) { + if (SHOULD_CANCEL(newval)) + pthread_exit(PTHREAD_CANCELED); + break; + } } - - THR_UNLOCK(curthread); - if (need_exit != 0) { - pthread_exit(PTHREAD_CANCELED); - PANIC("cancel"); - } - if (ret == 0 && oldtype != NULL) - *oldtype = otype; - - return (ret); + + return (0); } void _pthread_testcancel(void) { - struct pthread *curthread = _get_curthread(); - - THR_LOCK(curthread); - testcancel(curthread); - THR_UNLOCK(curthread); + struct pthread *curthread = _get_curthread(); + + if (SHOULD_CANCEL(curthread->cancelflags)) + pthread_exit(PTHREAD_CANCELED); } int _thr_cancel_enter(struct pthread *curthread) { - int old; + int oldval; - /* Look for a cancellation before we block: */ - THR_LOCK(curthread); - old = curthread->cancelflags; - if (!(curthread->cancelflags & THR_CANCEL_AT_POINT)) { - testcancel(curthread); - curthread->cancelflags |= THR_CANCEL_AT_POINT; - } - THR_UNLOCK(curthread); - return (old); + for (;;) { + oldval = curthread->cancelflags; + if (oldval & THR_CANCEL_AT_POINT) + break; + int newval = oldval | THR_CANCEL_AT_POINT; + if (atomic_cmpset_acq_int(&curthread->cancelflags, oldval, + newval)) { + if (SHOULD_CANCEL(newval)) + pthread_exit(PTHREAD_CANCELED); + } + } + return (oldval); } void _thr_cancel_leave(struct pthread *curthread, int previous) { if (!(previous & THR_CANCEL_AT_POINT)) - return; - THR_LOCK(curthread); - curthread->cancelflags &= ~THR_CANCEL_AT_POINT; - THR_UNLOCK(curthread); + atomic_clear_int(&curthread->cancelflags, THR_CANCEL_AT_POINT); } ==== //depot/projects/davidxu_thread/src/lib/libthread/thread/thr_exit.c#5 (text+ko) ==== @@ -101,9 +101,7 @@ * Flag this thread as exiting. Threads should now be prevented * from joining to this thread. */ - THR_LOCK(curthread); - curthread->cancelflags |= THR_CANCEL_EXITING; - THR_UNLOCK(curthread); + atomic_set_int(&curthread->cancelflags, THR_CANCEL_EXITING); _thr_exit_cleanup(); ==== //depot/projects/davidxu_thread/src/lib/libthread/thread/thr_mutex.c#8 (text+ko) ==== ==== //depot/projects/davidxu_thread/src/lib/libthread/thread/thr_private.h#10 (text+ko) ==== @@ -177,6 +177,7 @@ volatile long c_seqno; volatile long c_waiters; volatile long c_wakeups; + long c_count; long c_flags; }; @@ -412,9 +413,15 @@ #define THR_CANCEL_DISABLE 0x0001 #define THR_CANCEL_EXITING 0x0002 #define THR_CANCEL_AT_POINT 0x0004 -#define THR_CANCELLING 0x0008 -#define THR_CANCEL_NEEDED 0x0010 -#define THR_CANCEL_ASYNCHRONOUS 0x0020 +#define THR_CANCEL_NEEDED 0x0008 +#define SHOULD_CANCEL(val) \ + (((val) & (THR_CANCEL_DISABLE | THR_CANCEL_EXITING | \ + THR_CANCEL_NEEDED)) == THR_CANCEL_NEEDED) + +#define SHOULD_ASYNC_CANCEL(val) \ + (((val) & (THR_CANCEL_DISABLE | THR_CANCEL_EXITING | \ + THR_CANCEL_NEEDED | THR_CANCEL_AT_POINT)) == \ + (THR_CANCEL_NEEDED | THR_CANCEL_AT_POINT)) int cancelflags; /* Thread temporary signal mask. */ ==== //depot/projects/davidxu_thread/src/lib/libthread/thread/thr_sig.c#5 (text+ko) ==== @@ -186,10 +186,8 @@ static void thr_cancel_handler(struct pthread *curthread) { - if ((curthread->cancelflags & - (THR_CANCEL_AT_POINT | THR_CANCEL_ASYNCHRONOUS))) { + if (curthread->cancelflags & THR_CANCEL_AT_POINT) pthread_testcancel(); - } _thr_suspend_check(curthread); } @@ -197,7 +195,6 @@ void _thr_suspend_check(struct pthread *curthread) { -#if 0 sigset_t set; long cycle; @@ -218,7 +215,6 @@ curthread->flags &= ~THR_FLAGS_SUSPENDED; } THR_UNLOCK(curthread); -#endif } void