"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.17.5/lib/isc/quota.c" (4 Sep 2020, 4186 Bytes) of package /linux/misc/dns/bind9/9.17.5/bind-9.17.5.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "quota.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
    3  *
    4  * This Source Code Form is subject to the terms of the Mozilla Public
    5  * License, v. 2.0. If a copy of the MPL was not distributed with this
    6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
    7  *
    8  * See the COPYRIGHT file distributed with this work for additional
    9  * information regarding copyright ownership.
   10  */
   11 
   12 /*! \file */
   13 
   14 #include <stddef.h>
   15 
   16 #include <isc/atomic.h>
   17 #include <isc/quota.h>
   18 #include <isc/util.h>
   19 
   20 void
   21 isc_quota_init(isc_quota_t *quota, unsigned int max) {
   22     atomic_init(&quota->max, max);
   23     atomic_init(&quota->used, 0);
   24     atomic_init(&quota->soft, 0);
   25     atomic_init(&quota->waiting, 0);
   26     ISC_LIST_INIT(quota->cbs);
   27     isc_mutex_init(&quota->cblock);
   28 }
   29 
   30 void
   31 isc_quota_destroy(isc_quota_t *quota) {
   32     INSIST(atomic_load(&quota->used) == 0);
   33     INSIST(atomic_load(&quota->waiting) == 0);
   34     INSIST(ISC_LIST_EMPTY(quota->cbs));
   35     atomic_store_release(&quota->max, 0);
   36     atomic_store_release(&quota->used, 0);
   37     atomic_store_release(&quota->soft, 0);
   38     isc_mutex_destroy(&quota->cblock);
   39 }
   40 
   41 void
   42 isc_quota_soft(isc_quota_t *quota, unsigned int soft) {
   43     atomic_store_release(&quota->soft, soft);
   44 }
   45 
   46 void
   47 isc_quota_max(isc_quota_t *quota, unsigned int max) {
   48     atomic_store_release(&quota->max, max);
   49 }
   50 
   51 unsigned int
   52 isc_quota_getmax(isc_quota_t *quota) {
   53     return (atomic_load_relaxed(&quota->max));
   54 }
   55 
   56 unsigned int
   57 isc_quota_getsoft(isc_quota_t *quota) {
   58     return (atomic_load_relaxed(&quota->soft));
   59 }
   60 
   61 unsigned int
   62 isc_quota_getused(isc_quota_t *quota) {
   63     return (atomic_load_relaxed(&quota->used));
   64 }
   65 
   66 static isc_result_t
   67 quota_reserve(isc_quota_t *quota) {
   68     isc_result_t result;
   69     uint_fast32_t max = atomic_load_acquire(&quota->max);
   70     uint_fast32_t soft = atomic_load_acquire(&quota->soft);
   71     uint_fast32_t used = atomic_load_acquire(&quota->used);
   72     do {
   73         if (max != 0 && used >= max) {
   74             return (ISC_R_QUOTA);
   75         }
   76         if (soft != 0 && used >= soft) {
   77             result = ISC_R_SOFTQUOTA;
   78         } else {
   79             result = ISC_R_SUCCESS;
   80         }
   81     } while (!atomic_compare_exchange_weak_acq_rel(&quota->used, &used,
   82                                used + 1));
   83     return (result);
   84 }
   85 
   86 /* Must be quota->cbslock locked */
   87 static void
   88 enqueue(isc_quota_t *quota, isc_quota_cb_t *cb) {
   89     REQUIRE(cb != NULL);
   90     ISC_LIST_ENQUEUE(quota->cbs, cb, link);
   91     atomic_fetch_add_release(&quota->waiting, 1);
   92 }
   93 
   94 /* Must be quota->cbslock locked */
   95 static isc_quota_cb_t *
   96 dequeue(isc_quota_t *quota) {
   97     isc_quota_cb_t *cb = ISC_LIST_HEAD(quota->cbs);
   98     INSIST(cb != NULL);
   99     ISC_LIST_DEQUEUE(quota->cbs, cb, link);
  100     atomic_fetch_sub_relaxed(&quota->waiting, 1);
  101     return (cb);
  102 }
  103 
  104 static void
  105 quota_release(isc_quota_t *quota) {
  106     /*
  107      * This is opportunistic - we might race with a failing quota_attach_cb
  108      * and not detect that something is waiting, but eventually someone will
  109      * be releasing quota and will detect it, so we don't need to worry -
  110      * and we're saving a lot by not locking cblock every time.
  111      */
  112 
  113     if (atomic_load_acquire(&quota->waiting) > 0) {
  114         isc_quota_cb_t *cb = NULL;
  115         LOCK(&quota->cblock);
  116         if (atomic_load_relaxed(&quota->waiting) > 0) {
  117             cb = dequeue(quota);
  118         }
  119         UNLOCK(&quota->cblock);
  120         if (cb != NULL) {
  121             cb->cb_func(quota, cb->data);
  122             return;
  123         }
  124     }
  125 
  126     INSIST(atomic_fetch_sub_release(&quota->used, 1) > 0);
  127 }
  128 
  129 static isc_result_t
  130 doattach(isc_quota_t *quota, isc_quota_t **p) {
  131     isc_result_t result;
  132     REQUIRE(p != NULL && *p == NULL);
  133 
  134     result = quota_reserve(quota);
  135     if (result == ISC_R_SUCCESS || result == ISC_R_SOFTQUOTA) {
  136         *p = quota;
  137     }
  138 
  139     return (result);
  140 }
  141 
  142 isc_result_t
  143 isc_quota_attach(isc_quota_t *quota, isc_quota_t **p) {
  144     return (isc_quota_attach_cb(quota, p, NULL));
  145 }
  146 
  147 isc_result_t
  148 isc_quota_attach_cb(isc_quota_t *quota, isc_quota_t **p, isc_quota_cb_t *cb) {
  149     isc_result_t result = doattach(quota, p);
  150     if (result == ISC_R_QUOTA && cb != NULL) {
  151         LOCK(&quota->cblock);
  152         enqueue(quota, cb);
  153         UNLOCK(&quota->cblock);
  154     }
  155     return (result);
  156 }
  157 
  158 void
  159 isc_quota_cb_init(isc_quota_cb_t *cb, isc_quota_cb_func_t cb_func, void *data) {
  160     ISC_LINK_INIT(cb, link);
  161     cb->cb_func = cb_func;
  162     cb->data = data;
  163 }
  164 
  165 void
  166 isc_quota_detach(isc_quota_t **p) {
  167     INSIST(p != NULL && *p != NULL);
  168     quota_release(*p);
  169     *p = NULL;
  170 }