Fri Jun 15 13:51:41 2012 UTC ()
comments and assertions.
no functional changes.


(yamt)
diff -r1.31 -r1.32 src/sys/kern/kern_turnstile.c

cvs diff -r1.31 -r1.32 src/sys/kern/kern_turnstile.c (expand / switch to unified diff)

--- src/sys/kern/kern_turnstile.c 2011/12/02 12:31:53 1.31
+++ src/sys/kern/kern_turnstile.c 2012/06/15 13:51:40 1.32
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: kern_turnstile.c,v 1.31 2011/12/02 12:31:53 yamt Exp $ */ 1/* $NetBSD: kern_turnstile.c,v 1.32 2012/06/15 13:51:40 yamt Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2002, 2006, 2007, 2009 The NetBSD Foundation, Inc. 4 * Copyright (c) 2002, 2006, 2007, 2009 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe and Andrew Doran. 8 * by Jason R. Thorpe and Andrew Doran.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
@@ -50,27 +50,27 @@ @@ -50,27 +50,27 @@
50 * queue. If a thread decides it doesn't need to block after all, then this 50 * queue. If a thread decides it doesn't need to block after all, then this
51 * interlock must be released by explicitly aborting the turnstile 51 * interlock must be released by explicitly aborting the turnstile
52 * operation. 52 * operation.
53 * 53 *
54 * When a thread is awakened, it needs to get its turnstile back. If there 54 * When a thread is awakened, it needs to get its turnstile back. If there
55 * are still other threads waiting in the active turnstile, the thread 55 * are still other threads waiting in the active turnstile, the thread
56 * grabs a free turnstile off the free list. Otherwise, it can take back 56 * grabs a free turnstile off the free list. Otherwise, it can take back
57 * the active turnstile from the lock (thus deactivating the turnstile). 57 * the active turnstile from the lock (thus deactivating the turnstile).
58 * 58 *
59 * Turnstiles are the place to do priority inheritence. 59 * Turnstiles are the place to do priority inheritence.
60 */ 60 */
61 61
62#include <sys/cdefs.h> 62#include <sys/cdefs.h>
63__KERNEL_RCSID(0, "$NetBSD: kern_turnstile.c,v 1.31 2011/12/02 12:31:53 yamt Exp $"); 63__KERNEL_RCSID(0, "$NetBSD: kern_turnstile.c,v 1.32 2012/06/15 13:51:40 yamt Exp $");
64 64
65#include <sys/param.h> 65#include <sys/param.h>
66#include <sys/lockdebug.h> 66#include <sys/lockdebug.h>
67#include <sys/pool.h> 67#include <sys/pool.h>
68#include <sys/proc.h>  68#include <sys/proc.h>
69#include <sys/sleepq.h> 69#include <sys/sleepq.h>
70#include <sys/systm.h> 70#include <sys/systm.h>
71 71
72#define TS_HASH_SIZE 64 72#define TS_HASH_SIZE 64
73#define TS_HASH_MASK (TS_HASH_SIZE - 1) 73#define TS_HASH_MASK (TS_HASH_SIZE - 1)
74#define TS_HASH(obj) (((uintptr_t)(obj) >> 3) & TS_HASH_MASK) 74#define TS_HASH(obj) (((uintptr_t)(obj) >> 3) & TS_HASH_MASK)
75 75
76static tschain_t turnstile_tab[TS_HASH_SIZE] __cacheline_aligned; 76static tschain_t turnstile_tab[TS_HASH_SIZE] __cacheline_aligned;
@@ -189,100 +189,120 @@ void @@ -189,100 +189,120 @@ void
189turnstile_exit(wchan_t obj) 189turnstile_exit(wchan_t obj)
190{ 190{
191 tschain_t *tc; 191 tschain_t *tc;
192 192
193 tc = &turnstile_tab[TS_HASH(obj)]; 193 tc = &turnstile_tab[TS_HASH(obj)];
194 mutex_spin_exit(tc->tc_mutex); 194 mutex_spin_exit(tc->tc_mutex);
195} 195}
196 196
197/* 197/*
198 * turnstile_lendpri: 198 * turnstile_lendpri:
199 * 199 *
200 * Lend our priority to lwps on the blocking chain. 200 * Lend our priority to lwps on the blocking chain.
201 * 201 *
202 * 202 * If the current owner of the lock (l->l_wchan, set by sleepq_enqueue)
 203 * has a priority lower than ours (lwp_eprio(l)), lend our priority to
 204 * him to avoid priority inversions.
203 */ 205 */
204 206
205static void 207static void
206turnstile_lendpri(lwp_t *cur) 208turnstile_lendpri(lwp_t *cur)
207{ 209{
208 lwp_t * l = cur; 210 lwp_t * l = cur;
209 pri_t prio; 211 pri_t prio;
210 212
211 /* 213 /*
212 * NOTE: if you get a panic in this code block, it is likely that 214 * NOTE: if you get a panic in this code block, it is likely that
213 * a lock has been destroyed or corrupted while still in use. Try 215 * a lock has been destroyed or corrupted while still in use. Try
214 * compiling a kernel with LOCKDEBUG to pinpoint the problem. 216 * compiling a kernel with LOCKDEBUG to pinpoint the problem.
215 */ 217 */
216 218
217 LOCKDEBUG_BARRIER(l->l_mutex, 1); 219 LOCKDEBUG_BARRIER(l->l_mutex, 1);
218 KASSERT(l == curlwp); 220 KASSERT(l == curlwp);
219 prio = lwp_eprio(l); 221 prio = lwp_eprio(l);
220 for (;;) { 222 for (;;) {
221 lwp_t *owner; 223 lwp_t *owner;
222 turnstile_t *ts; 224 turnstile_t *ts;
223 bool dolock; 225 bool dolock;
224 226
225 if (l->l_wchan == NULL) 227 if (l->l_wchan == NULL)
226 break; 228 break;
227 229
 230 /*
 231 * Ask syncobj the owner of the lock.
 232 */
228 owner = (*l->l_syncobj->sobj_owner)(l->l_wchan); 233 owner = (*l->l_syncobj->sobj_owner)(l->l_wchan);
229 if (owner == NULL) 234 if (owner == NULL)
230 break; 235 break;
231 236
232 /* The owner may have changed as we have dropped the tc lock */ 237 /*
 238 * The owner may have changed as we have dropped the tc lock.
 239 */
233 if (cur == owner) { 240 if (cur == owner) {
234 /* 241 /*
235 * we own the lock: stop here, sleepq_block() 242 * We own the lock: stop here, sleepq_block()
236 * should wake up immediatly 243 * should wake up immediatly.
237 */ 244 */
238 break; 245 break;
239 } 246 }
240 if (l->l_mutex != owner->l_mutex) 247 /*
241 dolock = true; 248 * Acquire owner->l_mutex if we don't have it yet.
242 else 249 * Because we already have another LWP lock (l->l_mutex) held,
243 dolock = false; 250 * we need to play a try lock dance to avoid deadlock.
 251 */
 252 dolock = l->l_mutex != owner->l_mutex;
244 if (l == owner || (dolock && !lwp_trylock(owner))) { 253 if (l == owner || (dolock && !lwp_trylock(owner))) {
245 /* 254 /*
246 * restart from curlwp. 255 * The owner was changed behind us or trylock failed.
 256 * Restart from curlwp.
 257 *
247 * Note that there may be a livelock here: 258 * Note that there may be a livelock here:
248 * the owner may try grabing cur's lock (which is 259 * the owner may try grabing cur's lock (which is the
249 * the tc lock) while we're trying to grab 260 * tc lock) while we're trying to grab the owner's lock.
250 * the owner's lock. 
251 */ 261 */
252 lwp_unlock(l); 262 lwp_unlock(l);
253 l = cur; 263 l = cur;
254 lwp_lock(l); 264 lwp_lock(l);
255 prio = lwp_eprio(l); 265 prio = lwp_eprio(l);
256 continue; 266 continue;
257 } 267 }
 268 /*
 269 * If the owner's priority is already higher than ours,
 270 * there's nothing to do anymore.
 271 */
258 if (prio <= lwp_eprio(owner)) { 272 if (prio <= lwp_eprio(owner)) {
259 if (dolock) 273 if (dolock)
260 lwp_unlock(owner); 274 lwp_unlock(owner);
261 break; 275 break;
262 } 276 }
 277 /*
 278 * Lend our priority to the 'owner' LWP.
 279 *
 280 * Update lenders info for turnstile_unlendpri.
 281 */
263 ts = l->l_ts; 282 ts = l->l_ts;
264 KASSERT(ts->ts_inheritor == owner || ts->ts_inheritor == NULL); 283 KASSERT(ts->ts_inheritor == owner || ts->ts_inheritor == NULL);
265 if (ts->ts_inheritor == NULL) { 284 if (ts->ts_inheritor == NULL) {
266 ts->ts_inheritor = owner; 285 ts->ts_inheritor = owner;
267 ts->ts_eprio = prio; 286 ts->ts_eprio = prio;
268 SLIST_INSERT_HEAD(&owner->l_pi_lenders, ts, ts_pichain); 287 SLIST_INSERT_HEAD(&owner->l_pi_lenders, ts, ts_pichain);
269 lwp_lendpri(owner, prio); 288 lwp_lendpri(owner, prio);
270 } else if (prio > ts->ts_eprio) { 289 } else if (prio > ts->ts_eprio) {
271 ts->ts_eprio = prio; 290 ts->ts_eprio = prio;
272 lwp_lendpri(owner, prio); 291 lwp_lendpri(owner, prio);
273 } 292 }
274 if (dolock) 293 if (dolock)
275 lwp_unlock(l); 294 lwp_unlock(l);
 295 LOCKDEBUG_BARRIER(owner->l_mutex, 1);
276 l = owner; 296 l = owner;
277 } 297 }
278 LOCKDEBUG_BARRIER(l->l_mutex, 1); 298 LOCKDEBUG_BARRIER(l->l_mutex, 1);
279 if (cur->l_mutex != l->l_mutex) { 299 if (cur->l_mutex != l->l_mutex) {
280 lwp_unlock(l); 300 lwp_unlock(l);
281 lwp_lock(cur); 301 lwp_lock(cur);
282 } 302 }
283 LOCKDEBUG_BARRIER(cur->l_mutex, 1); 303 LOCKDEBUG_BARRIER(cur->l_mutex, 1);
284} 304}
285 305
286/* 306/*
287 * turnstile_unlendpri: undo turnstile_lendpri 307 * turnstile_unlendpri: undo turnstile_lendpri
288 */ 308 */