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