kern_mtxpool.c revision 116305
116234Smichaelm/*-
216234Smichaelm * Copyright (c) 2001 Matthew Dillon.  All Rights Reserved.  Copyright
316234Smichaelm * terms are as specified in the COPYRIGHT file at the base of the source
416234Smichaelm * tree.
516234Smichaelm *
616234Smichaelm * Mutex pool routines.  These routines are designed to be used as short
716234Smichaelm * term leaf mutexes (e.g. the last mutex you might aquire other then
816234Smichaelm * calling msleep()).  They operate using a shared pool.  A mutex is chosen
916234Smichaelm * from the pool based on the supplied pointer (which may or may not be
1016234Smichaelm * valid).
1116234Smichaelm *
1216234Smichaelm * Advantages:
1316234Smichaelm *	- no structural overhead.  Mutexes can be associated with structures
1416234Smichaelm *	  without adding bloat to the structures.
1516234Smichaelm *	- mutexes can be obtained for invalid pointers, useful when uses
1616234Smichaelm *	  mutexes to interlock destructor ops.
1716234Smichaelm *	- no initialization/destructor overhead.
1816234Smichaelm *	- can be used with msleep.
1916234Smichaelm *
2016234Smichaelm * Disadvantages:
2116234Smichaelm *	- should generally only be used as leaf mutexes.
2216234Smichaelm *	- pool/pool dependancy ordering cannot be depended on.
2316234Smichaelm *	- possible L1 cache mastersip contention between cpus.
2416234Smichaelm */
2516234Smichaelm
2616234Smichaelm#include <sys/cdefs.h>
2716234Smichaelm__FBSDID("$FreeBSD: head/sys/kern/kern_mtxpool.c 116305 2003-06-13 19:39:21Z mux $");
2816234Smichaelm
2916234Smichaelm#include <sys/param.h>
3016234Smichaelm#include <sys/proc.h>
3116234Smichaelm#include <sys/kernel.h>
3216234Smichaelm#include <sys/ktr.h>
3316234Smichaelm#include <sys/lock.h>
3416234Smichaelm#include <sys/malloc.h>
3516234Smichaelm#include <sys/mutex.h>
3616234Smichaelm#include <sys/systm.h>
3716234Smichaelm
3816234Smichaelm#ifndef MTX_POOL_SIZE
3916234Smichaelm#define MTX_POOL_SIZE	128
4016234Smichaelm#endif
4116234Smichaelm#define MTX_POOL_MASK	(MTX_POOL_SIZE - 1)
4216234Smichaelm
4316234Smichaelmstatic struct mtx mtx_pool_ary[MTX_POOL_SIZE];
4416234Smichaelm
4516234Smichaelmint mtx_pool_valid = 0;
4616234Smichaelm
4716234Smichaelm/*
4816234Smichaelm * Inline version of mtx_pool_find(), used to streamline our main API
4916234Smichaelm * function calls.
5016234Smichaelm */
5116234Smichaelmstatic __inline struct mtx *
5216234Smichaelm_mtx_pool_find(void *ptr)
5316234Smichaelm{
5416234Smichaelm    int p;
5516234Smichaelm
5616234Smichaelm    p = (int)(uintptr_t)ptr;
5716234Smichaelm    return (&mtx_pool_ary[(p ^ (p >> 6)) & MTX_POOL_MASK]);
5816234Smichaelm}
5916234Smichaelm
6016234Smichaelmstatic void
6116234Smichaelmmtx_pool_setup(void *dummy __unused)
6216234Smichaelm{
6316234Smichaelm    int i;
6416234Smichaelm
6516234Smichaelm    for (i = 0; i < MTX_POOL_SIZE; ++i)
6616234Smichaelm	mtx_init(&mtx_pool_ary[i], "pool mutex", NULL,
6716234Smichaelm	    MTX_DEF | MTX_NOWITNESS | MTX_QUIET);
6816234Smichaelm    mtx_pool_valid = 1;
6916234Smichaelm}
7016234Smichaelm
7116234Smichaelm/*
7216234Smichaelm * Obtain a (shared) mutex from the pool.  The returned mutex is a leaf
7316234Smichaelm * level mutex, meaning that if you obtain it you cannot obtain any other
7416234Smichaelm * mutexes until you release it.  You can legally msleep() on the mutex.
7516234Smichaelm */
7616234Smichaelmstruct mtx *
7716234Smichaelmmtx_pool_alloc(void)
7816234Smichaelm{
7916234Smichaelm    static int si;
8016234Smichaelm
8116234Smichaelm    return (&mtx_pool_ary[si++ & MTX_POOL_MASK]);
8216234Smichaelm}
8316234Smichaelm
8416234Smichaelm/*
8516234Smichaelm * Return the (shared) pool mutex associated with the specified address.
8616234Smichaelm * The returned mutex is a leaf level mutex, meaning that if you obtain it
8716234Smichaelm * you cannot obtain any other mutexes until you release it.  You can
8816234Smichaelm * legally msleep() on the mutex.
8916234Smichaelm */
9016234Smichaelmstruct mtx *
9116234Smichaelmmtx_pool_find(void *ptr)
9216234Smichaelm{
9316234Smichaelm
9416234Smichaelm    return (_mtx_pool_find(ptr));
9516234Smichaelm}
9616234Smichaelm
9716234Smichaelm/*
9816234Smichaelm * Combined find/lock operation.  Lock the pool mutex associated with
9916234Smichaelm * the specified address.
10016234Smichaelm */
10116234Smichaelmvoid
10216234Smichaelmmtx_pool_lock(void *ptr)
10316234Smichaelm{
10416234Smichaelm
10516234Smichaelm    mtx_lock(_mtx_pool_find(ptr));
10616234Smichaelm}
10716234Smichaelm
10816234Smichaelm/*
10916234Smichaelm * Combined find/unlock operation.  Unlock the pool mutex associated with
11016234Smichaelm * the specified address.
11116234Smichaelm */
11216234Smichaelmvoid
11316234Smichaelmmtx_pool_unlock(void *ptr)
11416234Smichaelm{
11516234Smichaelm
11616234Smichaelm    mtx_unlock(_mtx_pool_find(ptr));
11716234Smichaelm}
11816234Smichaelm
11916234SmichaelmSYSINIT(mtxpooli, SI_SUB_MTX_POOL, SI_ORDER_FIRST, mtx_pool_setup, NULL);
12016234Smichaelm