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