1*2c2f96dcSApple OSS Distributions /* 2*2c2f96dcSApple OSS Distributions * Copyright (c) 2020 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 #ifdef XNU_KERNEL_PRIVATE 29*2c2f96dcSApple OSS Distributions 30*2c2f96dcSApple OSS Distributions #ifndef _KERN_COUNTER_H 31*2c2f96dcSApple OSS Distributions #define _KERN_COUNTER_H 32*2c2f96dcSApple OSS Distributions 33*2c2f96dcSApple OSS Distributions /*! 34*2c2f96dcSApple OSS Distributions * @file <kern/counter.h> 35*2c2f96dcSApple OSS Distributions * 36*2c2f96dcSApple OSS Distributions * @brief 37*2c2f96dcSApple OSS Distributions * Module for working with 64bit relaxed atomic counters. 38*2c2f96dcSApple OSS Distributions * 39*2c2f96dcSApple OSS Distributions * @discussion 40*2c2f96dcSApple OSS Distributions * Different counter types have different speed-memory tradeoffs, but 41*2c2f96dcSApple OSS Distributions * they all share a common interface. 42*2c2f96dcSApple OSS Distributions * 43*2c2f96dcSApple OSS Distributions * Counters can be statically allocated or dynamically allocated. 44*2c2f96dcSApple OSS Distributions * 45*2c2f96dcSApple OSS Distributions * Statically allocated counters are always backed by per-cpu storage which means 46*2c2f96dcSApple OSS Distributions * writes take place on the current CPUs value and reads sum all of the per-cpu values. 47*2c2f96dcSApple OSS Distributions * 48*2c2f96dcSApple OSS Distributions * Dynamically allocated counters can be either per-cpu or use a single 64bit value. 49*2c2f96dcSApple OSS Distributions * To create a per-cpu counter, use the scalable_counter_t type. Note that this 50*2c2f96dcSApple OSS Distributions * trades of additional memory for better scalability. 51*2c2f96dcSApple OSS Distributions * To create a single 64bit counter, use the atomic_counter_t type. 52*2c2f96dcSApple OSS Distributions * 53*2c2f96dcSApple OSS Distributions * For most counters you can just use the counter_t type and the choice of 54*2c2f96dcSApple OSS Distributions * scalable or atomic will be made at compile time based on the target. 55*2c2f96dcSApple OSS Distributions * 56*2c2f96dcSApple OSS Distributions * The counter types are opaque handles. They ARE NOT COPYABLE. If you need 57*2c2f96dcSApple OSS Distributions * to make a copy of a counter, you should do so like this: 58*2c2f96dcSApple OSS Distributions * <code> 59*2c2f96dcSApple OSS Distributions * counter_t original; 60*2c2f96dcSApple OSS Distributions * ... 61*2c2f96dcSApple OSS Distributions * counter_t copy; 62*2c2f96dcSApple OSS Distributions * counter_alloc(©); 63*2c2f96dcSApple OSS Distributions * counter_add(©, counter_load(&original)); 64*2c2f96dcSApple OSS Distributions * ... 65*2c2f96dcSApple OSS Distributions * // Make sure to free them at some point. 66*2c2f96dcSApple OSS Distributions * counter_free(&original); 67*2c2f96dcSApple OSS Distributions * counter_free(©); 68*2c2f96dcSApple OSS Distributions * </code> 69*2c2f96dcSApple OSS Distributions * 70*2c2f96dcSApple OSS Distributions * Static counter example: 71*2c2f96dcSApple OSS Distributions * <code> 72*2c2f96dcSApple OSS Distributions * SCALABLE_COUNTER_DEFINE(my_counter); 73*2c2f96dcSApple OSS Distributions * ... 74*2c2f96dcSApple OSS Distributions * counter_inc(&my_counter); 75*2c2f96dcSApple OSS Distributions * assert(counter_load(&my_counter) == 1); 76*2c2f96dcSApple OSS Distributions * </code> 77*2c2f96dcSApple OSS Distributions * 78*2c2f96dcSApple OSS Distributions * Dynamic Counter Example: 79*2c2f96dcSApple OSS Distributions * <code> 80*2c2f96dcSApple OSS Distributions * scalable_counter_t my_percpu_counter; 81*2c2f96dcSApple OSS Distributions * atomic_counter_t my_atomic_counter; 82*2c2f96dcSApple OSS Distributions * counter_t my_counter; 83*2c2f96dcSApple OSS Distributions * 84*2c2f96dcSApple OSS Distributions * // All three counters share the same interface. So to change the speed-memory 85*2c2f96dcSApple OSS Distributions * // tradeoff just change the type. 86*2c2f96dcSApple OSS Distributions * counter_init(&my_scalable_counter); 87*2c2f96dcSApple OSS Distributions * counter_init(&my_atomic_counter); 88*2c2f96dcSApple OSS Distributions * counter_init(&my_counter); 89*2c2f96dcSApple OSS Distributions * 90*2c2f96dcSApple OSS Distributions * counter_inc(&my_scalable_counter); 91*2c2f96dcSApple OSS Distributions * counter_inc(&my_atomic_counter); 92*2c2f96dcSApple OSS Distributions * counter_inc(&my_counter); 93*2c2f96dcSApple OSS Distributions * 94*2c2f96dcSApple OSS Distributions * assert(counter_load(&my_scalable_counter) == 1); 95*2c2f96dcSApple OSS Distributions * assert(counter_load(&my_atomic_counter) == 1); 96*2c2f96dcSApple OSS Distributions * assert(counter_load(&my_counter) == 1); 97*2c2f96dcSApple OSS Distributions * </code> 98*2c2f96dcSApple OSS Distributions */ 99*2c2f96dcSApple OSS Distributions 100*2c2f96dcSApple OSS Distributions #include <mach/mach_types.h> 101*2c2f96dcSApple OSS Distributions #include <kern/macro_help.h> 102*2c2f96dcSApple OSS Distributions #include <kern/startup.h> 103*2c2f96dcSApple OSS Distributions #include <kern/zalloc.h> 104*2c2f96dcSApple OSS Distributions 105*2c2f96dcSApple OSS Distributions typedef uint64_t *__zpercpu scalable_counter_t; 106*2c2f96dcSApple OSS Distributions typedef uint64_t atomic_counter_t; 107*2c2f96dcSApple OSS Distributions /* Generic counter base type. Does not have an implementation. */ 108*2c2f96dcSApple OSS Distributions struct generic_counter_t; 109*2c2f96dcSApple OSS Distributions 110*2c2f96dcSApple OSS Distributions /*! 111*2c2f96dcSApple OSS Distributions * @macro SCALABLE_COUNTER_DECLARE 112*2c2f96dcSApple OSS Distributions * 113*2c2f96dcSApple OSS Distributions * @abstract 114*2c2f96dcSApple OSS Distributions * (optionally) declares a static per-cpu counter (in a header). 115*2c2f96dcSApple OSS Distributions * 116*2c2f96dcSApple OSS Distributions * @param var the name of the counter. 117*2c2f96dcSApple OSS Distributions */ 118*2c2f96dcSApple OSS Distributions #define SCALABLE_COUNTER_DECLARE(name) \ 119*2c2f96dcSApple OSS Distributions extern scalable_counter_t name; 120*2c2f96dcSApple OSS Distributions 121*2c2f96dcSApple OSS Distributions /*! 122*2c2f96dcSApple OSS Distributions * @macro SCALABLE_COUNTER_DEFINE 123*2c2f96dcSApple OSS Distributions * 124*2c2f96dcSApple OSS Distributions * @abstract 125*2c2f96dcSApple OSS Distributions * Defines a static per-cpu counter. 126*2c2f96dcSApple OSS Distributions * Counter can only be accessed after the TUNABLES phase of startup. 127*2c2f96dcSApple OSS Distributions * 128*2c2f96dcSApple OSS Distributions * @param var the name of the counter. 129*2c2f96dcSApple OSS Distributions */ 130*2c2f96dcSApple OSS Distributions #define SCALABLE_COUNTER_DEFINE(name) \ 131*2c2f96dcSApple OSS Distributions __startup_data uint64_t __ ##name##_early_storage = 0; \ 132*2c2f96dcSApple OSS Distributions scalable_counter_t name = {&__##name##_early_storage}; \ 133*2c2f96dcSApple OSS Distributions STARTUP_ARG(TUNABLES, STARTUP_RANK_MIDDLE, scalable_counter_static_boot_mangle, &name); \ 134*2c2f96dcSApple OSS Distributions STARTUP_ARG(PERCPU, STARTUP_RANK_SECOND, scalable_counter_static_init, &name); 135*2c2f96dcSApple OSS Distributions 136*2c2f96dcSApple OSS Distributions /* 137*2c2f96dcSApple OSS Distributions * Initialize a per-cpu counter. 138*2c2f96dcSApple OSS Distributions * May block and will never fail. 139*2c2f96dcSApple OSS Distributions * This counter must be freed with counter_free. 140*2c2f96dcSApple OSS Distributions */ 141*2c2f96dcSApple OSS Distributions OS_OVERLOADABLE 142*2c2f96dcSApple OSS Distributions extern void counter_alloc(struct generic_counter_t *); 143*2c2f96dcSApple OSS Distributions 144*2c2f96dcSApple OSS Distributions OS_OVERLOADABLE 145*2c2f96dcSApple OSS Distributions extern void counter_free(struct generic_counter_t *); 146*2c2f96dcSApple OSS Distributions /* 147*2c2f96dcSApple OSS Distributions * Add amount to counter. 148*2c2f96dcSApple OSS Distributions * @param amount The amount to add. 149*2c2f96dcSApple OSS Distributions */ 150*2c2f96dcSApple OSS Distributions OS_OVERLOADABLE 151*2c2f96dcSApple OSS Distributions extern void counter_add(struct generic_counter_t *, uint64_t amount); 152*2c2f96dcSApple OSS Distributions 153*2c2f96dcSApple OSS Distributions /* 154*2c2f96dcSApple OSS Distributions * Add 1 to this counter. 155*2c2f96dcSApple OSS Distributions */ 156*2c2f96dcSApple OSS Distributions OS_OVERLOADABLE 157*2c2f96dcSApple OSS Distributions extern void counter_inc(struct generic_counter_t *); 158*2c2f96dcSApple OSS Distributions 159*2c2f96dcSApple OSS Distributions /* 160*2c2f96dcSApple OSS Distributions * Subtract 1 from this counter. 161*2c2f96dcSApple OSS Distributions */ 162*2c2f96dcSApple OSS Distributions OS_OVERLOADABLE 163*2c2f96dcSApple OSS Distributions extern void counter_dec(struct generic_counter_t *); 164*2c2f96dcSApple OSS Distributions 165*2c2f96dcSApple OSS Distributions /* Variants of the above operations where the caller takes responsibility for disabling preemption. */ 166*2c2f96dcSApple OSS Distributions OS_OVERLOADABLE 167*2c2f96dcSApple OSS Distributions extern void counter_add_preemption_disabled(struct generic_counter_t *, uint64_t amount); 168*2c2f96dcSApple OSS Distributions OS_OVERLOADABLE 169*2c2f96dcSApple OSS Distributions extern void counter_inc_preemption_disabled(struct generic_counter_t *); 170*2c2f96dcSApple OSS Distributions OS_OVERLOADABLE 171*2c2f96dcSApple OSS Distributions extern void counter_dec_preemption_disabled(struct generic_counter_t *); 172*2c2f96dcSApple OSS Distributions 173*2c2f96dcSApple OSS Distributions /* 174*2c2f96dcSApple OSS Distributions * Read the value of the percpu counter. 175*2c2f96dcSApple OSS Distributions * Note that this will cause synchronization of all the sharded values. 176*2c2f96dcSApple OSS Distributions */ 177*2c2f96dcSApple OSS Distributions OS_OVERLOADABLE 178*2c2f96dcSApple OSS Distributions extern uint64_t counter_load(struct generic_counter_t *); 179*2c2f96dcSApple OSS Distributions 180*2c2f96dcSApple OSS Distributions #pragma mark implementation details 181*2c2f96dcSApple OSS Distributions /* NB: Nothing below here should be used directly. */ 182*2c2f96dcSApple OSS Distributions 183*2c2f96dcSApple OSS Distributions __startup_func void scalable_counter_static_boot_mangle(scalable_counter_t *counter); 184*2c2f96dcSApple OSS Distributions __startup_func void scalable_counter_static_init(scalable_counter_t *counter); 185*2c2f96dcSApple OSS Distributions 186*2c2f96dcSApple OSS Distributions #if XNU_TARGET_OS_WATCH || XNU_TARGET_OS_TV 187*2c2f96dcSApple OSS Distributions #define ATOMIC_COUNTER_USE_PERCPU 0 188*2c2f96dcSApple OSS Distributions #else 189*2c2f96dcSApple OSS Distributions #define ATOMIC_COUNTER_USE_PERCPU 1 190*2c2f96dcSApple OSS Distributions #endif /* XNU_TARGET_OS_OSX */ 191*2c2f96dcSApple OSS Distributions 192*2c2f96dcSApple OSS Distributions #if ATOMIC_COUNTER_USE_PERCPU 193*2c2f96dcSApple OSS Distributions typedef scalable_counter_t counter_t; 194*2c2f96dcSApple OSS Distributions #else 195*2c2f96dcSApple OSS Distributions typedef atomic_counter_t counter_t; 196*2c2f96dcSApple OSS Distributions #endif /* ATOMIC_COUNTER_USE_PERCPU */ 197*2c2f96dcSApple OSS Distributions 198*2c2f96dcSApple OSS Distributions #define COUNTER_MAKE_PROTOTYPES(counter_t) \ 199*2c2f96dcSApple OSS Distributions OS_OVERLOADABLE \ 200*2c2f96dcSApple OSS Distributions extern void counter_alloc(counter_t *); \ 201*2c2f96dcSApple OSS Distributions \ 202*2c2f96dcSApple OSS Distributions OS_OVERLOADABLE \ 203*2c2f96dcSApple OSS Distributions extern void counter_free(counter_t *); \ 204*2c2f96dcSApple OSS Distributions \ 205*2c2f96dcSApple OSS Distributions OS_OVERLOADABLE \ 206*2c2f96dcSApple OSS Distributions extern void counter_add(counter_t *, uint64_t amount); \ 207*2c2f96dcSApple OSS Distributions \ 208*2c2f96dcSApple OSS Distributions OS_OVERLOADABLE \ 209*2c2f96dcSApple OSS Distributions extern void counter_inc(counter_t *); \ 210*2c2f96dcSApple OSS Distributions \ 211*2c2f96dcSApple OSS Distributions OS_OVERLOADABLE \ 212*2c2f96dcSApple OSS Distributions extern void counter_dec(counter_t *); \ 213*2c2f96dcSApple OSS Distributions \ 214*2c2f96dcSApple OSS Distributions OS_OVERLOADABLE \ 215*2c2f96dcSApple OSS Distributions extern void counter_add_preemption_disabled(counter_t *, uint64_t amount); \ 216*2c2f96dcSApple OSS Distributions \ 217*2c2f96dcSApple OSS Distributions OS_OVERLOADABLE \ 218*2c2f96dcSApple OSS Distributions extern void counter_inc_preemption_disabled(counter_t *); \ 219*2c2f96dcSApple OSS Distributions \ 220*2c2f96dcSApple OSS Distributions OS_OVERLOADABLE \ 221*2c2f96dcSApple OSS Distributions extern void counter_dec_preemption_disabled(counter_t *); \ 222*2c2f96dcSApple OSS Distributions \ 223*2c2f96dcSApple OSS Distributions OS_OVERLOADABLE \ 224*2c2f96dcSApple OSS Distributions extern uint64_t counter_load(counter_t *); 225*2c2f96dcSApple OSS Distributions 226*2c2f96dcSApple OSS Distributions COUNTER_MAKE_PROTOTYPES(scalable_counter_t); 227*2c2f96dcSApple OSS Distributions COUNTER_MAKE_PROTOTYPES(atomic_counter_t); 228*2c2f96dcSApple OSS Distributions 229*2c2f96dcSApple OSS Distributions #endif /* _KERN_COUNTER_H */ 230*2c2f96dcSApple OSS Distributions 231*2c2f96dcSApple OSS Distributions #endif /* XNU_KERNEL_PRIVATE */ 232