1 /*- 2 * Copyright (c) 2001 Matthew Dillon. All Rights Reserved. Copyright 3 * terms are as specified in the COPYRIGHT file at the base of the source 4 * tree. 5 * 6 * Mutex pool routines. These routines are designed to be used as short 7 * term leaf mutexes (e.g. the last mutex you might aquire other then 8 * calling msleep()). They operate using a shared pool. A mutex is chosen 9 * from the pool based on the supplied pointer (which may or may not be 10 * valid). 11 * 12 * Advantages: 13 * - no structural overhead. Mutexes can be associated with structures 14 * without adding bloat to the structures. 15 * - mutexes can be obtained for invalid pointers, useful when uses 16 * mutexes to interlock destructor ops. 17 * - no initialization/destructor overhead 18 * - can be used with msleep. 19 * 20 * Disadvantages: 21 * - should generally only be used as leaf mutexes 22 * - pool/pool dependancy ordering cannot be depended on. 23 * - possible L1 cache mastersip contention between cpus 24 * 25 * $FreeBSD$ 26 */ 27 28 #include <sys/param.h> 29 #include <sys/proc.h> 30 #include <sys/kernel.h> 31 #include <sys/ktr.h> 32 #include <sys/lock.h> 33 #include <sys/malloc.h> 34 #include <sys/mutex.h> 35 #include <sys/systm.h> 36 37 #ifndef MTX_POOL_SIZE 38 #define MTX_POOL_SIZE 128 39 #endif 40 #define MTX_POOL_MASK (MTX_POOL_SIZE-1) 41 42 static struct mtx mtx_pool_ary[MTX_POOL_SIZE]; 43 44 int mtx_pool_valid = 0; 45 46 /* 47 * Inline version of mtx_pool_find(), used to streamline our main API 48 * function calls. 49 */ 50 static __inline 51 struct mtx * 52 _mtx_pool_find(void *ptr) 53 { 54 int p; 55 56 p = (int)(uintptr_t)ptr; 57 return(&mtx_pool_ary[(p ^ (p >> 6)) & MTX_POOL_MASK]); 58 } 59 60 static void 61 mtx_pool_setup(void *dummy __unused) 62 { 63 int i; 64 65 for (i = 0; i < MTX_POOL_SIZE; ++i) 66 mtx_init(&mtx_pool_ary[i], "pool mutex", MTX_DEF | MTX_NOWITNESS | MTX_QUIET); 67 mtx_pool_valid = 1; 68 } 69 70 /* 71 * Obtain a (shared) mutex from the pool. The returned mutex is a leaf 72 * level mutex, meaning that if you obtain it you cannot obtain any other 73 * mutexes until you release it. You can legally msleep() on the mutex. 74 */ 75 struct mtx * 76 mtx_pool_alloc(void) 77 { 78 static int si; 79 return(&mtx_pool_ary[si++ & MTX_POOL_MASK]); 80 } 81 82 /* 83 * Return the (shared) pool mutex associated with the specified address. 84 * The returned mutex is a leaf level mutex, meaning that if you obtain it 85 * you cannot obtain any other mutexes until you release it. You can 86 * legally msleep() on the mutex. 87 */ 88 struct mtx * 89 mtx_pool_find(void *ptr) 90 { 91 return(_mtx_pool_find(ptr)); 92 } 93 94 /* 95 * Combined find/lock operation. Lock the pool mutex associated with 96 * the specified address. 97 */ 98 void 99 mtx_pool_lock(void *ptr) 100 { 101 mtx_lock(_mtx_pool_find(ptr)); 102 } 103 104 /* 105 * Combined find/unlock operation. Unlock the pool mutex associated with 106 * the specified address. 107 */ 108 void 109 mtx_pool_unlock(void *ptr) 110 { 111 mtx_unlock(_mtx_pool_find(ptr)); 112 } 113 114 SYSINIT(mtxpooli, SI_SUB_MTX_POOL, SI_ORDER_FIRST, mtx_pool_setup, NULL) 115 116