Home | History | Annotate | Line # | Download | only in isc
counter.c revision 1.1
      1 /*	$NetBSD: counter.c,v 1.1 2024/02/18 20:57:48 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * SPDX-License-Identifier: MPL-2.0
      7  *
      8  * This Source Code Form is subject to the terms of the Mozilla Public
      9  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11  *
     12  * See the COPYRIGHT file distributed with this work for additional
     13  * information regarding copyright ownership.
     14  */
     15 
     16 /*! \file */
     17 
     18 #include <stdbool.h>
     19 #include <stddef.h>
     20 
     21 #include <isc/atomic.h>
     22 #include <isc/counter.h>
     23 #include <isc/magic.h>
     24 #include <isc/mem.h>
     25 #include <isc/refcount.h>
     26 #include <isc/util.h>
     27 
     28 #define COUNTER_MAGIC	 ISC_MAGIC('C', 'n', 't', 'r')
     29 #define VALID_COUNTER(r) ISC_MAGIC_VALID(r, COUNTER_MAGIC)
     30 
     31 struct isc_counter {
     32 	unsigned int magic;
     33 	isc_mem_t *mctx;
     34 	isc_refcount_t references;
     35 	atomic_uint_fast32_t limit;
     36 	atomic_uint_fast32_t used;
     37 };
     38 
     39 isc_result_t
     40 isc_counter_create(isc_mem_t *mctx, int limit, isc_counter_t **counterp) {
     41 	isc_counter_t *counter;
     42 
     43 	REQUIRE(counterp != NULL && *counterp == NULL);
     44 
     45 	counter = isc_mem_get(mctx, sizeof(*counter));
     46 
     47 	counter->mctx = NULL;
     48 	isc_mem_attach(mctx, &counter->mctx);
     49 
     50 	isc_refcount_init(&counter->references, 1);
     51 	atomic_init(&counter->limit, limit);
     52 	atomic_init(&counter->used, 0);
     53 
     54 	counter->magic = COUNTER_MAGIC;
     55 	*counterp = counter;
     56 	return (ISC_R_SUCCESS);
     57 }
     58 
     59 isc_result_t
     60 isc_counter_increment(isc_counter_t *counter) {
     61 	uint32_t used = atomic_fetch_add_relaxed(&counter->used, 1) + 1;
     62 	uint32_t limit = atomic_load_acquire(&counter->limit);
     63 
     64 	if (limit != 0 && used >= limit) {
     65 		return (ISC_R_QUOTA);
     66 	}
     67 
     68 	return (ISC_R_SUCCESS);
     69 }
     70 
     71 unsigned int
     72 isc_counter_used(isc_counter_t *counter) {
     73 	REQUIRE(VALID_COUNTER(counter));
     74 
     75 	return (atomic_load_acquire(&counter->used));
     76 }
     77 
     78 void
     79 isc_counter_setlimit(isc_counter_t *counter, int limit) {
     80 	REQUIRE(VALID_COUNTER(counter));
     81 
     82 	atomic_store(&counter->limit, limit);
     83 }
     84 
     85 void
     86 isc_counter_attach(isc_counter_t *source, isc_counter_t **targetp) {
     87 	REQUIRE(VALID_COUNTER(source));
     88 	REQUIRE(targetp != NULL && *targetp == NULL);
     89 
     90 	isc_refcount_increment(&source->references);
     91 
     92 	*targetp = source;
     93 }
     94 
     95 static void
     96 destroy(isc_counter_t *counter) {
     97 	isc_refcount_destroy(&counter->references);
     98 	counter->magic = 0;
     99 	isc_mem_putanddetach(&counter->mctx, counter, sizeof(*counter));
    100 }
    101 
    102 void
    103 isc_counter_detach(isc_counter_t **counterp) {
    104 	isc_counter_t *counter;
    105 
    106 	REQUIRE(counterp != NULL && *counterp != NULL);
    107 	counter = *counterp;
    108 	*counterp = NULL;
    109 	REQUIRE(VALID_COUNTER(counter));
    110 
    111 	if (isc_refcount_decrement(&counter->references) == 1) {
    112 		destroy(counter);
    113 	}
    114 }
    115