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