1*2c2f96dcSApple OSS Distributions /* 2*2c2f96dcSApple OSS Distributions * Copyright (c) 2022 Apple Inc. All rights reserved. 3*2c2f96dcSApple OSS Distributions * 4*2c2f96dcSApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5*2c2f96dcSApple OSS Distributions * 6*2c2f96dcSApple OSS Distributions * This file contains Original Code and/or Modifications of Original Code 7*2c2f96dcSApple OSS Distributions * as defined in and that are subject to the Apple Public Source License 8*2c2f96dcSApple OSS Distributions * Version 2.0 (the 'License'). You may not use this file except in 9*2c2f96dcSApple OSS Distributions * compliance with the License. The rights granted to you under the License 10*2c2f96dcSApple OSS Distributions * may not be used to create, or enable the creation or redistribution of, 11*2c2f96dcSApple OSS Distributions * unlawful or unlicensed copies of an Apple operating system, or to 12*2c2f96dcSApple OSS Distributions * circumvent, violate, or enable the circumvention or violation of, any 13*2c2f96dcSApple OSS Distributions * terms of an Apple operating system software license agreement. 14*2c2f96dcSApple OSS Distributions * 15*2c2f96dcSApple OSS Distributions * Please obtain a copy of the License at 16*2c2f96dcSApple OSS Distributions * http://www.opensource.apple.com/apsl/ and read it before using this file. 17*2c2f96dcSApple OSS Distributions * 18*2c2f96dcSApple OSS Distributions * The Original Code and all software distributed under the License are 19*2c2f96dcSApple OSS Distributions * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20*2c2f96dcSApple OSS Distributions * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21*2c2f96dcSApple OSS Distributions * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22*2c2f96dcSApple OSS Distributions * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23*2c2f96dcSApple OSS Distributions * Please see the License for the specific language governing rights and 24*2c2f96dcSApple OSS Distributions * limitations under the License. 25*2c2f96dcSApple OSS Distributions * 26*2c2f96dcSApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27*2c2f96dcSApple OSS Distributions */ 28*2c2f96dcSApple OSS Distributions 29*2c2f96dcSApple OSS Distributions #ifndef _KERN_COMPACT_ID_H_ 30*2c2f96dcSApple OSS Distributions #define _KERN_COMPACT_ID_H_ 31*2c2f96dcSApple OSS Distributions 32*2c2f96dcSApple OSS Distributions #include <stdbool.h> 33*2c2f96dcSApple OSS Distributions #include <stdint.h> 34*2c2f96dcSApple OSS Distributions #include <kern/bits.h> 35*2c2f96dcSApple OSS Distributions #include <kern/startup.h> 36*2c2f96dcSApple OSS Distributions #include <kern/locks.h> 37*2c2f96dcSApple OSS Distributions 38*2c2f96dcSApple OSS Distributions __BEGIN_DECLS 39*2c2f96dcSApple OSS Distributions #pragma GCC visibility push(hidden) 40*2c2f96dcSApple OSS Distributions 41*2c2f96dcSApple OSS Distributions #define COMPACT_ID_SHIFT_BASE (10) 42*2c2f96dcSApple OSS Distributions #define COMPACT_ID_COUNT_BASE (1u << COMPACT_ID_SHIFT_BASE) 43*2c2f96dcSApple OSS Distributions #define COMPACT_ID_SLAB_COUNT (12) 44*2c2f96dcSApple OSS Distributions #define COMPACT_ID_MAX ((COMPACT_ID_COUNT_BASE << (COMPACT_ID_SLAB_COUNT - 1)) - 1u) 45*2c2f96dcSApple OSS Distributions 46*2c2f96dcSApple OSS Distributions typedef uint32_t compact_id_t; 47*2c2f96dcSApple OSS Distributions typedef struct compact_id_table *compact_id_table_t; 48*2c2f96dcSApple OSS Distributions 49*2c2f96dcSApple OSS Distributions /* 50*2c2f96dcSApple OSS Distributions * @struct compact_id_table 51*2c2f96dcSApple OSS Distributions * 52*2c2f96dcSApple OSS Distributions * @discussion 53*2c2f96dcSApple OSS Distributions * A compact ID table contains an array of COMPACT_ID_SLAB_COUNT 54*2c2f96dcSApple OSS Distributions * compact_id_slab slabs. 55*2c2f96dcSApple OSS Distributions * 56*2c2f96dcSApple OSS Distributions * Each slab contains a different number of values, depending on its position 57*2c2f96dcSApple OSS Distributions * within the cidt_slabs. 58*2c2f96dcSApple OSS Distributions * 59*2c2f96dcSApple OSS Distributions * The entries in the table are never deallocated once created, 60*2c2f96dcSApple OSS Distributions * which allows to access the table without holding a lock. 61*2c2f96dcSApple OSS Distributions * 62*2c2f96dcSApple OSS Distributions * Slots within each slab can be re-used once an association 63*2c2f96dcSApple OSS Distributions * with a prior value has been released. 64*2c2f96dcSApple OSS Distributions * 65*2c2f96dcSApple OSS Distributions * The first 2 entries will have COMPACT_ID_COUNT_BASE entries, 66*2c2f96dcSApple OSS Distributions * all others will have size COMPACT_ID_COUNT_BASE * 2^(index - 1). 67*2c2f96dcSApple OSS Distributions * 68*2c2f96dcSApple OSS Distributions * |BASE|BASE|2BASE|4BASE|...|2^(MAX-2)BASE| 69*2c2f96dcSApple OSS Distributions * 0 1 2 3 MAX-1 70*2c2f96dcSApple OSS Distributions * 71*2c2f96dcSApple OSS Distributions * This can allow a maximum capacity of BASE(2^(MAX-1)) values 72*2c2f96dcSApple OSS Distributions * 73*2c2f96dcSApple OSS Distributions * Because COMPACT_ID_COUNT_BASE is a power of 2, it lets us 74*2c2f96dcSApple OSS Distributions * lookup into the tables very efficiently: each table slab 75*2c2f96dcSApple OSS Distributions * contains all the compact IDs between subsequent power of 2 76*2c2f96dcSApple OSS Distributions * of COMPACT_ID_COUNT_BASE. 77*2c2f96dcSApple OSS Distributions * 78*2c2f96dcSApple OSS Distributions * |0 -> (B-1)|B -> (2B-1)|2B -> (4B-1)|...|2^(MAX-2)B -> ((2^(MAX-1)B)-1)| 79*2c2f96dcSApple OSS Distributions * 0 1 2 MAX-1 80*2c2f96dcSApple OSS Distributions * 81*2c2f96dcSApple OSS Distributions * By observing the most significant bit of a given compact ID, 82*2c2f96dcSApple OSS Distributions * we can compute its slab index very efficiently: 83*2c2f96dcSApple OSS Distributions * 84*2c2f96dcSApple OSS Distributions * slab_index = clz(COMPACT_ID_COUNT_BASE) - clz(ctid | (COMPACT_ID_COUNT_BASE - 1)) + 1 85*2c2f96dcSApple OSS Distributions * 86*2c2f96dcSApple OSS Distributions * Note: because we expect lookups to be common, 87*2c2f96dcSApple OSS Distributions * cidt_array isn't the real array but shifted 88*2c2f96dcSApple OSS Distributions * so that dereferencing it with the compact ID 89*2c2f96dcSApple OSS Distributions * works for any slab. 90*2c2f96dcSApple OSS Distributions */ 91*2c2f96dcSApple OSS Distributions struct compact_id_table { 92*2c2f96dcSApple OSS Distributions /* 93*2c2f96dcSApple OSS Distributions * slabs first saves one instruction per compact_id_resolve() 94*2c2f96dcSApple OSS Distributions */ 95*2c2f96dcSApple OSS Distributions void **cidt_array[COMPACT_ID_SLAB_COUNT]; 96*2c2f96dcSApple OSS Distributions bitmap_t *cidt_bitmap[COMPACT_ID_SLAB_COUNT]; 97*2c2f96dcSApple OSS Distributions lck_mtx_t cidt_lock; 98*2c2f96dcSApple OSS Distributions struct thread *cidt_allocator; 99*2c2f96dcSApple OSS Distributions bool cidt_waiters; 100*2c2f96dcSApple OSS Distributions uint32_t cidt_count; 101*2c2f96dcSApple OSS Distributions compact_id_t cidt_first_free; 102*2c2f96dcSApple OSS Distributions }; 103*2c2f96dcSApple OSS Distributions 104*2c2f96dcSApple OSS Distributions extern void compact_id_table_init( 105*2c2f96dcSApple OSS Distributions compact_id_table_t table); 106*2c2f96dcSApple OSS Distributions 107*2c2f96dcSApple OSS Distributions extern void **compact_id_resolve( 108*2c2f96dcSApple OSS Distributions compact_id_table_t table, 109*2c2f96dcSApple OSS Distributions compact_id_t compact_id) __pure2; 110*2c2f96dcSApple OSS Distributions 111*2c2f96dcSApple OSS Distributions extern compact_id_t compact_id_get_locked( 112*2c2f96dcSApple OSS Distributions compact_id_table_t table, 113*2c2f96dcSApple OSS Distributions compact_id_t limit, 114*2c2f96dcSApple OSS Distributions void *value); 115*2c2f96dcSApple OSS Distributions 116*2c2f96dcSApple OSS Distributions extern compact_id_t compact_id_get( 117*2c2f96dcSApple OSS Distributions compact_id_table_t table, 118*2c2f96dcSApple OSS Distributions compact_id_t limit, 119*2c2f96dcSApple OSS Distributions void *value); 120*2c2f96dcSApple OSS Distributions 121*2c2f96dcSApple OSS Distributions extern void *compact_id_put( 122*2c2f96dcSApple OSS Distributions compact_id_table_t table, 123*2c2f96dcSApple OSS Distributions compact_id_t compact_id); 124*2c2f96dcSApple OSS Distributions 125*2c2f96dcSApple OSS Distributions extern void compact_id_for_each( 126*2c2f96dcSApple OSS Distributions compact_id_table_t table, 127*2c2f96dcSApple OSS Distributions uint32_t stride, 128*2c2f96dcSApple OSS Distributions bool (^cb)(void *v)); 129*2c2f96dcSApple OSS Distributions 130*2c2f96dcSApple OSS Distributions extern void compact_id_table_lock( 131*2c2f96dcSApple OSS Distributions compact_id_table_t table); 132*2c2f96dcSApple OSS Distributions 133*2c2f96dcSApple OSS Distributions extern void compact_id_table_unlock( 134*2c2f96dcSApple OSS Distributions compact_id_table_t table); 135*2c2f96dcSApple OSS Distributions 136*2c2f96dcSApple OSS Distributions #define COMPACT_ID_TABLE_DEFINE(class, var) \ 137*2c2f96dcSApple OSS Distributions static void *var##_array0[COMPACT_ID_COUNT_BASE]; \ 138*2c2f96dcSApple OSS Distributions static bitmap_t var##_bits0[BITMAP_LEN(COMPACT_ID_COUNT_BASE)] = { \ 139*2c2f96dcSApple OSS Distributions [0 ... BITMAP_LEN(COMPACT_ID_COUNT_BASE) - 1] = ~0ull, \ 140*2c2f96dcSApple OSS Distributions }; \ 141*2c2f96dcSApple OSS Distributions class struct compact_id_table var = { \ 142*2c2f96dcSApple OSS Distributions .cidt_bitmap[0] = var##_bits0, \ 143*2c2f96dcSApple OSS Distributions .cidt_array[0] = var##_array0, \ 144*2c2f96dcSApple OSS Distributions }; \ 145*2c2f96dcSApple OSS Distributions STARTUP_ARG(LOCKS, STARTUP_RANK_THIRD, compact_id_table_init, &var) 146*2c2f96dcSApple OSS Distributions 147*2c2f96dcSApple OSS Distributions #pragma GCC visibility pop 148*2c2f96dcSApple OSS Distributions __END_DECLS 149*2c2f96dcSApple OSS Distributions 150*2c2f96dcSApple OSS Distributions #endif /* _KERN_COMPACT_ID_H_ */ 151