Home | History | Annotate | Line # | Download | only in libpthread
pthread_lock.c revision 1.1.2.11
      1 /*	$NetBSD: pthread_lock.c,v 1.1.2.11 2002/11/03 12:29:03 skrll Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Nathan J. Williams.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 #include <assert.h>
     40 #include <errno.h>
     41 
     42 #include "pthread.h"
     43 #include "pthread_int.h"
     44 
     45 #undef PTHREAD_SA_DEBUG
     46 
     47 #ifdef PTHREAD_SA_DEBUG
     48 #define SDPRINTF(x) DPRINTF(x)
     49 #else
     50 #define SDPRINTF(x)
     51 #endif
     52 
     53 /* How many times to try before checking whether we've been continued. */
     54 #define NSPINS 1	/* no point in actually spinning until MP works */
     55 
     56 static int nspins = NSPINS;
     57 
     58 void
     59 pthread_lockinit(pthread_spin_t *lock)
     60 {
     61 
     62 	__cpu_simple_lock_init(lock);
     63 }
     64 
     65 void
     66 pthread_spinlock(pthread_t thread, pthread_spin_t *lock)
     67 {
     68 	int count, ret;
     69 
     70 	count = nspins;
     71 	SDPRINTF(("(pthread_spinlock %p) incrementing spinlock from %d\n",
     72 		thread, thread->pt_spinlocks));
     73 	++thread->pt_spinlocks;
     74 
     75 	do {
     76 		while (((ret = __cpu_simple_lock_try(lock)) == 0) && --count)
     77 			;
     78 
     79 		if (ret == 1)
     80 			break;
     81 
     82 	SDPRINTF(("(pthread_spinlock %p) decrementing spinlock from %d\n",
     83 		thread, thread->pt_spinlocks));
     84 		--thread->pt_spinlocks;
     85 
     86 		/*
     87 		 * We may be preempted while spinning. If so, we will
     88 		 * be restarted here if thread->pt_spinlocks is
     89 		 * nonzero, which can happen if:
     90 		 * a) we just got the lock
     91 		 * b) we haven't yet decremented the lock count.
     92 		 * If we're at this point, (b) applies. Therefore,
     93 		 * check if we're being continued, and if so, bail.
     94 		 * (in case (a), we should let the code finish and
     95 		 * we will bail out in pthread_spinunlock()).
     96 		 */
     97 		if (thread->pt_next != NULL) {
     98 			PTHREADD_ADD(PTHREADD_SPINPREEMPT);
     99 			pthread__switch(thread, thread->pt_next);
    100 		}
    101 		/* try again */
    102 		count = nspins;
    103 	SDPRINTF(("(pthread_spinlock %p) incrementing spinlock from %d\n",
    104 		thread, thread->pt_spinlocks));
    105 		++thread->pt_spinlocks;
    106 	} while (/*CONSTCOND*/1);
    107 
    108 	PTHREADD_ADD(PTHREADD_SPINLOCKS);
    109 	/* Got it! We're out of here. */
    110 }
    111 
    112 
    113 int
    114 pthread_spintrylock(pthread_t thread, pthread_spin_t *lock)
    115 {
    116 	int ret;
    117 
    118 	SDPRINTF(("(pthread_spinlock %p) incrementing spinlock from %d\n",
    119 		thread, thread->pt_spinlocks));
    120 	++thread->pt_spinlocks;
    121 
    122 	ret = __cpu_simple_lock_try(lock);
    123 
    124 	if (ret == 0) {
    125 	SDPRINTF(("(pthread_spintrylock %p) decrementing spinlock from %d\n",
    126 		thread, thread->pt_spinlocks));
    127 		--thread->pt_spinlocks;
    128 		/* See above. */
    129 		if (thread->pt_next != NULL) {
    130 			PTHREADD_ADD(PTHREADD_SPINPREEMPT);
    131 			pthread__switch(thread, thread->pt_next);
    132 		}
    133 	}
    134 
    135 	return ret;
    136 }
    137 
    138 
    139 void
    140 pthread_spinunlock(pthread_t thread, pthread_spin_t *lock)
    141 {
    142 
    143 	__cpu_simple_unlock(lock);
    144 	SDPRINTF(("(pthread_spinunlock %p) decrementing spinlock from %d\n",
    145 		thread, thread->pt_spinlocks));
    146 	--thread->pt_spinlocks;
    147 
    148 	PTHREADD_ADD(PTHREADD_SPINUNLOCKS);
    149 
    150 	/*
    151 	 * If we were preempted while holding a spinlock, the
    152 	 * scheduler will notice this and continue us. To be good
    153 	 * citzens, we must now get out of here if that was our
    154 	 * last spinlock.
    155 	 * XXX when will we ever have more than one?
    156 	 */
    157 
    158 	if ((thread->pt_spinlocks == 0) && (thread->pt_next != NULL)) {
    159 		PTHREADD_ADD(PTHREADD_SPINPREEMPT);
    160 		pthread__switch(thread, thread->pt_next);
    161 	}
    162 }
    163 
    164 
    165 /*
    166  * Public (POSIX-specified) spinlocks.
    167  * These don't interact with the spin-preemption code, nor do they
    168  * perform any adaptive sleeping.
    169  */
    170 
    171 int
    172 pthread_spin_init(pthread_spinlock_t *lock, int pshared)
    173 {
    174 
    175 #ifdef ERRORCHECK
    176 	if ((lock == NULL) ||
    177 	    ((pshared != PTHREAD_PROCESS_PRIVATE) &&
    178 		(pshared != PTHREAD_PROCESS_SHARED)))
    179 		return EINVAL;
    180 #endif
    181 	lock->pts_magic = _PT_SPINLOCK_MAGIC;
    182 	/*
    183 	 * We don't actually use the pshared flag for anything;
    184 	 * cpu simple locks have all the process-shared properties
    185 	 * that we want anyway.
    186 	 */
    187 	lock->pts_flags = pshared;
    188 	pthread_lockinit(&lock->pts_spin);
    189 
    190 	return 0;
    191 }
    192 
    193 int
    194 pthread_spin_destroy(pthread_spinlock_t *lock)
    195 {
    196 
    197 #ifdef ERRORCHECK
    198 	if ((lock == NULL) || (lock->pts_magic != _PT_SPINLOCK_MAGIC))
    199 		return EINVAL;
    200 
    201 	if (lock->pts_spin != __SIMPLELOCK_UNLOCKED)
    202 		return EBUSY;
    203 #endif
    204 
    205 	lock->pts_magic = _PT_SPINLOCK_DEAD;
    206 
    207 	return 0;
    208 }
    209 
    210 int
    211 pthread_spin_lock(pthread_spinlock_t *lock)
    212 {
    213 
    214 #ifdef ERRORCHECK
    215 	if ((lock == NULL) || (lock->pts_magic != _PT_SPINLOCK_MAGIC))
    216 		return EINVAL;
    217 #endif
    218 
    219 	__cpu_simple_lock(&lock->pts_spin);
    220 
    221 	return 0;
    222 }
    223 
    224 int
    225 pthread_spin_trylock(pthread_spinlock_t *lock)
    226 {
    227 
    228 #ifdef ERRORCHECK
    229 	if ((lock == NULL) || (lock->pts_magic != _PT_SPINLOCK_MAGIC))
    230 		return EINVAL;
    231 #endif
    232 
    233 	if (__cpu_simple_lock_try(&lock->pts_spin) == 0)
    234 		return EBUSY;
    235 
    236 	return 0;
    237 }
    238 
    239 int
    240 pthread_spin_unlock(pthread_spinlock_t *lock)
    241 {
    242 
    243 #ifdef ERRORCHECK
    244 	if ((lock == NULL) || (lock->pts_magic != _PT_SPINLOCK_MAGIC))
    245 		return EINVAL;
    246 #endif
    247 
    248 	__cpu_simple_unlock(&lock->pts_spin);
    249 
    250 	return 0;
    251 }
    252