1 /* $NetBSD: counter.c,v 1.1.1.2 2014/12/10 03:34:43 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /*! \file */ 20 21 #include <config.h> 22 23 #include <stddef.h> 24 25 #include <isc/counter.h> 26 #include <isc/magic.h> 27 #include <isc/mem.h> 28 #include <isc/util.h> 29 30 #define COUNTER_MAGIC ISC_MAGIC('C', 'n', 't', 'r') 31 #define VALID_COUNTER(r) ISC_MAGIC_VALID(r, COUNTER_MAGIC) 32 33 struct isc_counter { 34 unsigned int magic; 35 isc_mem_t *mctx; 36 isc_mutex_t lock; 37 unsigned int references; 38 unsigned int limit; 39 unsigned int used; 40 }; 41 42 isc_result_t 43 isc_counter_create(isc_mem_t *mctx, int limit, isc_counter_t **counterp) { 44 isc_result_t result; 45 isc_counter_t *counter; 46 47 REQUIRE(counterp != NULL && *counterp == NULL); 48 49 counter = isc_mem_get(mctx, sizeof(*counter)); 50 if (counter == NULL) 51 return (ISC_R_NOMEMORY); 52 53 result = isc_mutex_init(&counter->lock); 54 if (result != ISC_R_SUCCESS) { 55 isc_mem_put(mctx, counter, sizeof(*counter)); 56 return (result); 57 } 58 59 counter->mctx = NULL; 60 isc_mem_attach(mctx, &counter->mctx); 61 62 counter->references = 1; 63 counter->limit = limit; 64 counter->used = 0; 65 66 counter->magic = COUNTER_MAGIC; 67 *counterp = counter; 68 return (ISC_R_SUCCESS); 69 } 70 71 isc_result_t 72 isc_counter_increment(isc_counter_t *counter) { 73 isc_result_t result = ISC_R_SUCCESS; 74 75 LOCK(&counter->lock); 76 counter->used++; 77 if (counter->limit != 0 && counter->used >= counter->limit) 78 result = ISC_R_QUOTA; 79 UNLOCK(&counter->lock); 80 81 return (result); 82 } 83 84 unsigned int 85 isc_counter_used(isc_counter_t *counter) { 86 REQUIRE(VALID_COUNTER(counter)); 87 88 return (counter->used); 89 } 90 91 void 92 isc_counter_setlimit(isc_counter_t *counter, int limit) { 93 REQUIRE(VALID_COUNTER(counter)); 94 95 LOCK(&counter->lock); 96 counter->limit = limit; 97 UNLOCK(&counter->lock); 98 } 99 100 void 101 isc_counter_attach(isc_counter_t *source, isc_counter_t **targetp) { 102 REQUIRE(VALID_COUNTER(source)); 103 REQUIRE(targetp != NULL && *targetp == NULL); 104 105 LOCK(&source->lock); 106 source->references++; 107 INSIST(source->references > 0); 108 UNLOCK(&source->lock); 109 110 *targetp = source; 111 } 112 113 static void 114 destroy(isc_counter_t *counter) { 115 counter->magic = 0; 116 isc_mutex_destroy(&counter->lock); 117 isc_mem_putanddetach(&counter->mctx, counter, sizeof(*counter)); 118 } 119 120 void 121 isc_counter_detach(isc_counter_t **counterp) { 122 isc_counter_t *counter; 123 isc_boolean_t want_destroy = ISC_FALSE; 124 125 REQUIRE(counterp != NULL && *counterp != NULL); 126 counter = *counterp; 127 REQUIRE(VALID_COUNTER(counter)); 128 129 *counterp = NULL; 130 131 LOCK(&counter->lock); 132 INSIST(counter->references > 0); 133 counter->references--; 134 if (counter->references == 0) 135 want_destroy = ISC_TRUE; 136 UNLOCK(&counter->lock); 137 138 if (want_destroy) 139 destroy(counter); 140 } 141