kern_mtxpool.c revision 116182
1140668Sgnn/*- 2140668Sgnn * Copyright (c) 2001 Matthew Dillon. All Rights Reserved. Copyright 3140668Sgnn * terms are as specified in the COPYRIGHT file at the base of the source 4140668Sgnn * tree. 5140668Sgnn * 6140668Sgnn * Mutex pool routines. These routines are designed to be used as short 7140668Sgnn * term leaf mutexes (e.g. the last mutex you might aquire other then 8140668Sgnn * calling msleep()). They operate using a shared pool. A mutex is chosen 9140668Sgnn * from the pool based on the supplied pointer (which may or may not be 10140668Sgnn * valid). 11140668Sgnn * 12140668Sgnn * Advantages: 13140668Sgnn * - no structural overhead. Mutexes can be associated with structures 14140668Sgnn * without adding bloat to the structures. 15140668Sgnn * - mutexes can be obtained for invalid pointers, useful when uses 16140668Sgnn * mutexes to interlock destructor ops. 17140668Sgnn * - no initialization/destructor overhead 18140668Sgnn * - can be used with msleep. 19140668Sgnn * 20140668Sgnn * Disadvantages: 21140668Sgnn * - should generally only be used as leaf mutexes 22140668Sgnn * - pool/pool dependancy ordering cannot be depended on. 23140668Sgnn * - possible L1 cache mastersip contention between cpus 24140668Sgnn */ 25140668Sgnn 26140668Sgnn#include <sys/cdefs.h> 27140668Sgnn__FBSDID("$FreeBSD: head/sys/kern/kern_mtxpool.c 116182 2003-06-11 00:56:59Z obrien $"); 28140668Sgnn 29140668Sgnn#include <sys/param.h> 30141580Sru#include <sys/proc.h> 31141580Sru#include <sys/kernel.h> 32140668Sgnn#include <sys/ktr.h> 33140668Sgnn#include <sys/lock.h> 34140668Sgnn#include <sys/malloc.h> 35140668Sgnn#include <sys/mutex.h> 36140668Sgnn#include <sys/systm.h> 37140668Sgnn 38140668Sgnn#ifndef MTX_POOL_SIZE 39140668Sgnn#define MTX_POOL_SIZE 128 40140668Sgnn#endif 41140668Sgnn#define MTX_POOL_MASK (MTX_POOL_SIZE-1) 42140668Sgnn 43140668Sgnnstatic struct mtx mtx_pool_ary[MTX_POOL_SIZE]; 44140668Sgnn 45140668Sgnnint mtx_pool_valid = 0; 46140668Sgnn 47140668Sgnn/* 48140668Sgnn * Inline version of mtx_pool_find(), used to streamline our main API 49140668Sgnn * function calls. 50140668Sgnn */ 51140668Sgnnstatic __inline 52140668Sgnnstruct mtx * 53140668Sgnn_mtx_pool_find(void *ptr) 54140668Sgnn{ 55140668Sgnn int p; 56140668Sgnn 57140668Sgnn p = (int)(uintptr_t)ptr; 58140668Sgnn return(&mtx_pool_ary[(p ^ (p >> 6)) & MTX_POOL_MASK]); 59140668Sgnn} 60140668Sgnn 61140668Sgnnstatic void 62140668Sgnnmtx_pool_setup(void *dummy __unused) 63140668Sgnn{ 64147402Sru int i; 65140668Sgnn 66140668Sgnn for (i = 0; i < MTX_POOL_SIZE; ++i) 67140668Sgnn mtx_init(&mtx_pool_ary[i], "pool mutex", NULL, MTX_DEF | MTX_NOWITNESS | MTX_QUIET); 68140668Sgnn mtx_pool_valid = 1; 69140668Sgnn} 70140668Sgnn 71140668Sgnn/* 72140668Sgnn * Obtain a (shared) mutex from the pool. The returned mutex is a leaf 73140668Sgnn * level mutex, meaning that if you obtain it you cannot obtain any other 74140668Sgnn * mutexes until you release it. You can legally msleep() on the mutex. 75140668Sgnn */ 76140668Sgnnstruct mtx * 77140668Sgnnmtx_pool_alloc(void) 78140668Sgnn{ 79140668Sgnn static int si; 80140668Sgnn return(&mtx_pool_ary[si++ & MTX_POOL_MASK]); 81140668Sgnn} 82140668Sgnn 83140668Sgnn/* 84140668Sgnn * Return the (shared) pool mutex associated with the specified address. 85147402Sru * The returned mutex is a leaf level mutex, meaning that if you obtain it 86140668Sgnn * you cannot obtain any other mutexes until you release it. You can 87140668Sgnn * legally msleep() on the mutex. 88148580Skeramida */ 89147402Srustruct mtx * 90140668Sgnnmtx_pool_find(void *ptr) 91140668Sgnn{ 92147402Sru return(_mtx_pool_find(ptr)); 93140668Sgnn} 94140668Sgnn 95140668Sgnn/* 96140668Sgnn * Combined find/lock operation. Lock the pool mutex associated with 97140668Sgnn * the specified address. 98140668Sgnn */ 99140668Sgnnvoid 100140668Sgnnmtx_pool_lock(void *ptr) 101140668Sgnn{ 102140668Sgnn mtx_lock(_mtx_pool_find(ptr)); 103140668Sgnn} 104211397Sjoel 105211397Sjoel/* 106140668Sgnn * Combined find/unlock operation. Unlock the pool mutex associated with 107140668Sgnn * the specified address. 108140668Sgnn */ 109140668Sgnnvoid 110140668Sgnnmtx_pool_unlock(void *ptr) 111140668Sgnn{ 112140668Sgnn mtx_unlock(_mtx_pool_find(ptr)); 113140668Sgnn} 114140668Sgnn 115140668SgnnSYSINIT(mtxpooli, SI_SUB_MTX_POOL, SI_ORDER_FIRST, mtx_pool_setup, NULL) 116140668Sgnn 117140668Sgnn