pthread_lock.c revision 1.1.2.12 1 /* $NetBSD: pthread_lock.c,v 1.1.2.12 2002/11/14 04:10:08 nathanw 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 #include <unistd.h>
42
43 #include "pthread.h"
44 #include "pthread_int.h"
45
46 #undef PTHREAD_SPIN_DEBUG
47
48 #ifdef PTHREAD_SPIN_DEBUG
49 #define SDPRINTF(x) DPRINTF(x)
50 #else
51 #define SDPRINTF(x)
52 #endif
53
54 /* How many times to try before checking whether we've been continued. */
55 #define NSPINS 1 /* no point in actually spinning until MP works */
56
57 static int nspins = NSPINS;
58
59 void
60 pthread_lockinit(pthread_spin_t *lock)
61 {
62
63 __cpu_simple_lock_init(lock);
64 }
65
66 void
67 pthread_spinlock(pthread_t thread, pthread_spin_t *lock)
68 {
69 int count, ret;
70
71 count = nspins;
72 SDPRINTF(("(pthread_spinlock %p) incrementing spinlock from %d\n",
73 thread, thread->pt_spinlocks));
74 #ifdef PTHREAD_SPIN_DEBUG
75 if(!(thread->pt_spinlocks >= 0)) {
76 (void)kill(getpid(), SIGABRT);
77 _exit(1);
78 }
79 #endif
80 ++thread->pt_spinlocks;
81
82 do {
83 while (((ret = __cpu_simple_lock_try(lock)) == 0) && --count)
84 ;
85
86 if (ret == 1)
87 break;
88
89 SDPRINTF(("(pthread_spinlock %p) decrementing spinlock from %d\n",
90 thread, thread->pt_spinlocks));
91 --thread->pt_spinlocks;
92
93 /*
94 * We may be preempted while spinning. If so, we will
95 * be restarted here if thread->pt_spinlocks is
96 * nonzero, which can happen if:
97 * a) we just got the lock
98 * b) we haven't yet decremented the lock count.
99 * If we're at this point, (b) applies. Therefore,
100 * check if we're being continued, and if so, bail.
101 * (in case (a), we should let the code finish and
102 * we will bail out in pthread_spinunlock()).
103 */
104 if (thread->pt_next != NULL) {
105 PTHREADD_ADD(PTHREADD_SPINPREEMPT);
106 pthread__switch(thread, thread->pt_next);
107 }
108 /* try again */
109 count = nspins;
110 SDPRINTF(("(pthread_spinlock %p) incrementing spinlock from %d\n",
111 thread, thread->pt_spinlocks));
112 ++thread->pt_spinlocks;
113 } while (/*CONSTCOND*/1);
114
115 PTHREADD_ADD(PTHREADD_SPINLOCKS);
116 /* Got it! We're out of here. */
117 }
118
119
120 int
121 pthread_spintrylock(pthread_t thread, pthread_spin_t *lock)
122 {
123 int ret;
124
125 SDPRINTF(("(pthread_spinlock %p) incrementing spinlock from %d\n",
126 thread, thread->pt_spinlocks));
127 ++thread->pt_spinlocks;
128
129 ret = __cpu_simple_lock_try(lock);
130
131 if (ret == 0) {
132 SDPRINTF(("(pthread_spintrylock %p) decrementing spinlock from %d\n",
133 thread, thread->pt_spinlocks));
134 --thread->pt_spinlocks;
135 /* See above. */
136 if (thread->pt_next != NULL) {
137 PTHREADD_ADD(PTHREADD_SPINPREEMPT);
138 pthread__switch(thread, thread->pt_next);
139 }
140 }
141
142 return ret;
143 }
144
145
146 void
147 pthread_spinunlock(pthread_t thread, pthread_spin_t *lock)
148 {
149
150 __cpu_simple_unlock(lock);
151 SDPRINTF(("(pthread_spinunlock %p) decrementing spinlock from %d\n",
152 thread, thread->pt_spinlocks));
153 --thread->pt_spinlocks;
154 #ifdef PTHREAD_SPIN_DEBUG
155 if (!(thread->pt_spinlocks >= 0)) {
156 (void)kill(getpid(), SIGABRT);
157 _exit(1);
158 }
159 #endif
160 PTHREADD_ADD(PTHREADD_SPINUNLOCKS);
161
162 /*
163 * If we were preempted while holding a spinlock, the
164 * scheduler will notice this and continue us. To be good
165 * citzens, we must now get out of here if that was our
166 * last spinlock.
167 * XXX when will we ever have more than one?
168 */
169
170 if ((thread->pt_spinlocks == 0) && (thread->pt_next != NULL)) {
171 PTHREADD_ADD(PTHREADD_SPINPREEMPT);
172 pthread__switch(thread, thread->pt_next);
173 }
174 }
175
176
177 /*
178 * Public (POSIX-specified) spinlocks.
179 * These don't interact with the spin-preemption code, nor do they
180 * perform any adaptive sleeping.
181 */
182
183 int
184 pthread_spin_init(pthread_spinlock_t *lock, int pshared)
185 {
186
187 #ifdef ERRORCHECK
188 if ((lock == NULL) ||
189 ((pshared != PTHREAD_PROCESS_PRIVATE) &&
190 (pshared != PTHREAD_PROCESS_SHARED)))
191 return EINVAL;
192 #endif
193 lock->pts_magic = _PT_SPINLOCK_MAGIC;
194 /*
195 * We don't actually use the pshared flag for anything;
196 * cpu simple locks have all the process-shared properties
197 * that we want anyway.
198 */
199 lock->pts_flags = pshared;
200 pthread_lockinit(&lock->pts_spin);
201
202 return 0;
203 }
204
205 int
206 pthread_spin_destroy(pthread_spinlock_t *lock)
207 {
208
209 #ifdef ERRORCHECK
210 if ((lock == NULL) || (lock->pts_magic != _PT_SPINLOCK_MAGIC))
211 return EINVAL;
212
213 if (lock->pts_spin != __SIMPLELOCK_UNLOCKED)
214 return EBUSY;
215 #endif
216
217 lock->pts_magic = _PT_SPINLOCK_DEAD;
218
219 return 0;
220 }
221
222 int
223 pthread_spin_lock(pthread_spinlock_t *lock)
224 {
225
226 #ifdef ERRORCHECK
227 if ((lock == NULL) || (lock->pts_magic != _PT_SPINLOCK_MAGIC))
228 return EINVAL;
229 #endif
230
231 __cpu_simple_lock(&lock->pts_spin);
232
233 return 0;
234 }
235
236 int
237 pthread_spin_trylock(pthread_spinlock_t *lock)
238 {
239
240 #ifdef ERRORCHECK
241 if ((lock == NULL) || (lock->pts_magic != _PT_SPINLOCK_MAGIC))
242 return EINVAL;
243 #endif
244
245 if (__cpu_simple_lock_try(&lock->pts_spin) == 0)
246 return EBUSY;
247
248 return 0;
249 }
250
251 int
252 pthread_spin_unlock(pthread_spinlock_t *lock)
253 {
254
255 #ifdef ERRORCHECK
256 if ((lock == NULL) || (lock->pts_magic != _PT_SPINLOCK_MAGIC))
257 return EINVAL;
258 #endif
259
260 __cpu_simple_unlock(&lock->pts_spin);
261
262 return 0;
263 }
264