Home | History | Annotate | Download | only in iomgr
      1 /*
      2  *
      3  * Copyright 2016 gRPC authors.
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  *
     17  */
     18 
     19 #include "src/core/lib/iomgr/resource_quota.h"
     20 
     21 #include <grpc/support/alloc.h>
     22 #include <grpc/support/log.h>
     23 
     24 #include "src/core/lib/iomgr/exec_ctx.h"
     25 #include "src/core/lib/slice/slice_internal.h"
     26 #include "test/core/util/test_config.h"
     27 
     28 gpr_mu g_mu;
     29 gpr_cv g_cv;
     30 
     31 static void inc_int_cb(void* a, grpc_error* error) {
     32   gpr_mu_lock(&g_mu);
     33   ++*static_cast<int*>(a);
     34   gpr_cv_signal(&g_cv);
     35   gpr_mu_unlock(&g_mu);
     36 }
     37 
     38 static void assert_counter_becomes(int* ctr, int value) {
     39   gpr_mu_lock(&g_mu);
     40   gpr_timespec deadline = grpc_timeout_seconds_to_deadline(5);
     41   while (*ctr != value) {
     42     GPR_ASSERT(!gpr_cv_wait(&g_cv, &g_mu, deadline));
     43   }
     44   gpr_mu_unlock(&g_mu);
     45 }
     46 
     47 static void set_event_cb(void* a, grpc_error* error) {
     48   gpr_event_set(static_cast<gpr_event*>(a), (void*)1);
     49 }
     50 grpc_closure* set_event(gpr_event* ev) {
     51   return GRPC_CLOSURE_CREATE(set_event_cb, ev, grpc_schedule_on_exec_ctx);
     52 }
     53 
     54 typedef struct {
     55   size_t size;
     56   grpc_resource_user* resource_user;
     57   grpc_closure* then;
     58 } reclaimer_args;
     59 
     60 static void reclaimer_cb(void* args, grpc_error* error) {
     61   GPR_ASSERT(error == GRPC_ERROR_NONE);
     62   reclaimer_args* a = static_cast<reclaimer_args*>(args);
     63   grpc_resource_user_free(a->resource_user, a->size);
     64   grpc_resource_user_finish_reclamation(a->resource_user);
     65   GRPC_CLOSURE_RUN(a->then, GRPC_ERROR_NONE);
     66   gpr_free(a);
     67 }
     68 
     69 grpc_closure* make_reclaimer(grpc_resource_user* resource_user, size_t size,
     70                              grpc_closure* then) {
     71   reclaimer_args* a = static_cast<reclaimer_args*>(gpr_malloc(sizeof(*a)));
     72   a->size = size;
     73   a->resource_user = resource_user;
     74   a->then = then;
     75   return GRPC_CLOSURE_CREATE(reclaimer_cb, a, grpc_schedule_on_exec_ctx);
     76 }
     77 
     78 static void unused_reclaimer_cb(void* arg, grpc_error* error) {
     79   GPR_ASSERT(error == GRPC_ERROR_CANCELLED);
     80   GRPC_CLOSURE_RUN(static_cast<grpc_closure*>(arg), GRPC_ERROR_NONE);
     81 }
     82 grpc_closure* make_unused_reclaimer(grpc_closure* then) {
     83   return GRPC_CLOSURE_CREATE(unused_reclaimer_cb, then,
     84                              grpc_schedule_on_exec_ctx);
     85 }
     86 
     87 static void destroy_user(grpc_resource_user* usr) {
     88   grpc_core::ExecCtx exec_ctx;
     89   grpc_resource_user_unref(usr);
     90 }
     91 
     92 static void test_no_op(void) {
     93   gpr_log(GPR_INFO, "** test_no_op **");
     94   grpc_resource_quota_unref(grpc_resource_quota_create("test_no_op"));
     95 }
     96 
     97 static void test_resize_then_destroy(void) {
     98   gpr_log(GPR_INFO, "** test_resize_then_destroy **");
     99   grpc_resource_quota* q =
    100       grpc_resource_quota_create("test_resize_then_destroy");
    101   grpc_resource_quota_resize(q, 1024 * 1024);
    102   grpc_resource_quota_unref(q);
    103 }
    104 
    105 static void test_resource_user_no_op(void) {
    106   gpr_log(GPR_INFO, "** test_resource_user_no_op **");
    107   grpc_resource_quota* q =
    108       grpc_resource_quota_create("test_resource_user_no_op");
    109   grpc_resource_user* usr = grpc_resource_user_create(q, "usr");
    110   grpc_resource_quota_unref(q);
    111   destroy_user(usr);
    112 }
    113 
    114 static void test_instant_alloc_then_free(void) {
    115   gpr_log(GPR_INFO, "** test_instant_alloc_then_free **");
    116   grpc_resource_quota* q =
    117       grpc_resource_quota_create("test_instant_alloc_then_free");
    118   grpc_resource_quota_resize(q, 1024 * 1024);
    119   grpc_resource_user* usr = grpc_resource_user_create(q, "usr");
    120   {
    121     grpc_core::ExecCtx exec_ctx;
    122     grpc_resource_user_alloc(usr, 1024, nullptr);
    123   }
    124   {
    125     grpc_core::ExecCtx exec_ctx;
    126     grpc_resource_user_free(usr, 1024);
    127   }
    128   grpc_resource_quota_unref(q);
    129   destroy_user(usr);
    130 }
    131 
    132 static void test_instant_alloc_free_pair(void) {
    133   gpr_log(GPR_INFO, "** test_instant_alloc_free_pair **");
    134   grpc_resource_quota* q =
    135       grpc_resource_quota_create("test_instant_alloc_free_pair");
    136   grpc_resource_quota_resize(q, 1024 * 1024);
    137   grpc_resource_user* usr = grpc_resource_user_create(q, "usr");
    138   {
    139     grpc_core::ExecCtx exec_ctx;
    140     grpc_resource_user_alloc(usr, 1024, nullptr);
    141     grpc_resource_user_free(usr, 1024);
    142   }
    143   grpc_resource_quota_unref(q);
    144   destroy_user(usr);
    145 }
    146 
    147 static void test_simple_async_alloc(void) {
    148   gpr_log(GPR_INFO, "** test_simple_async_alloc **");
    149   grpc_resource_quota* q =
    150       grpc_resource_quota_create("test_simple_async_alloc");
    151   grpc_resource_quota_resize(q, 1024 * 1024);
    152   grpc_resource_user* usr = grpc_resource_user_create(q, "usr");
    153   {
    154     gpr_event ev;
    155     gpr_event_init(&ev);
    156     grpc_core::ExecCtx exec_ctx;
    157     grpc_resource_user_alloc(usr, 1024, set_event(&ev));
    158     grpc_core::ExecCtx::Get()->Flush();
    159     GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) !=
    160                nullptr);
    161   }
    162   {
    163     grpc_core::ExecCtx exec_ctx;
    164     grpc_resource_user_free(usr, 1024);
    165   }
    166   grpc_resource_quota_unref(q);
    167   destroy_user(usr);
    168 }
    169 
    170 static void test_async_alloc_blocked_by_size(void) {
    171   gpr_log(GPR_INFO, "** test_async_alloc_blocked_by_size **");
    172   grpc_resource_quota* q =
    173       grpc_resource_quota_create("test_async_alloc_blocked_by_size");
    174   grpc_resource_quota_resize(q, 1);
    175   grpc_resource_user* usr = grpc_resource_user_create(q, "usr");
    176   gpr_event ev;
    177   gpr_event_init(&ev);
    178   {
    179     grpc_core::ExecCtx exec_ctx;
    180     grpc_resource_user_alloc(usr, 1024, set_event(&ev));
    181     grpc_core::ExecCtx::Get()->Flush();
    182     GPR_ASSERT(gpr_event_wait(
    183                    &ev, grpc_timeout_milliseconds_to_deadline(100)) == nullptr);
    184   }
    185   grpc_resource_quota_resize(q, 1024);
    186   GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) !=
    187              nullptr);
    188   ;
    189   {
    190     grpc_core::ExecCtx exec_ctx;
    191     grpc_resource_user_free(usr, 1024);
    192   }
    193   grpc_resource_quota_unref(q);
    194   destroy_user(usr);
    195 }
    196 
    197 static void test_scavenge(void) {
    198   gpr_log(GPR_INFO, "** test_scavenge **");
    199   grpc_resource_quota* q = grpc_resource_quota_create("test_scavenge");
    200   grpc_resource_quota_resize(q, 1024);
    201   grpc_resource_user* usr1 = grpc_resource_user_create(q, "usr1");
    202   grpc_resource_user* usr2 = grpc_resource_user_create(q, "usr2");
    203   {
    204     gpr_event ev;
    205     gpr_event_init(&ev);
    206     grpc_core::ExecCtx exec_ctx;
    207     grpc_resource_user_alloc(usr1, 1024, set_event(&ev));
    208     grpc_core::ExecCtx::Get()->Flush();
    209     GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) !=
    210                nullptr);
    211     ;
    212   }
    213   {
    214     grpc_core::ExecCtx exec_ctx;
    215     grpc_resource_user_free(usr1, 1024);
    216   }
    217   {
    218     gpr_event ev;
    219     gpr_event_init(&ev);
    220     grpc_core::ExecCtx exec_ctx;
    221     grpc_resource_user_alloc(usr2, 1024, set_event(&ev));
    222     grpc_core::ExecCtx::Get()->Flush();
    223     GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) !=
    224                nullptr);
    225     ;
    226   }
    227   {
    228     grpc_core::ExecCtx exec_ctx;
    229     grpc_resource_user_free(usr2, 1024);
    230   }
    231   grpc_resource_quota_unref(q);
    232   destroy_user(usr1);
    233   destroy_user(usr2);
    234 }
    235 
    236 static void test_scavenge_blocked(void) {
    237   gpr_log(GPR_INFO, "** test_scavenge_blocked **");
    238   grpc_resource_quota* q = grpc_resource_quota_create("test_scavenge_blocked");
    239   grpc_resource_quota_resize(q, 1024);
    240   grpc_resource_user* usr1 = grpc_resource_user_create(q, "usr1");
    241   grpc_resource_user* usr2 = grpc_resource_user_create(q, "usr2");
    242   gpr_event ev;
    243   {
    244     gpr_event_init(&ev);
    245     grpc_core::ExecCtx exec_ctx;
    246     grpc_resource_user_alloc(usr1, 1024, set_event(&ev));
    247     grpc_core::ExecCtx::Get()->Flush();
    248     GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) !=
    249                nullptr);
    250     ;
    251   }
    252   {
    253     gpr_event_init(&ev);
    254     grpc_core::ExecCtx exec_ctx;
    255     grpc_resource_user_alloc(usr2, 1024, set_event(&ev));
    256     grpc_core::ExecCtx::Get()->Flush();
    257     GPR_ASSERT(gpr_event_wait(
    258                    &ev, grpc_timeout_milliseconds_to_deadline(100)) == nullptr);
    259   }
    260   {
    261     grpc_core::ExecCtx exec_ctx;
    262     grpc_resource_user_free(usr1, 1024);
    263     grpc_core::ExecCtx::Get()->Flush();
    264     GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) !=
    265                nullptr);
    266     ;
    267   }
    268   {
    269     grpc_core::ExecCtx exec_ctx;
    270     grpc_resource_user_free(usr2, 1024);
    271   }
    272   grpc_resource_quota_unref(q);
    273   destroy_user(usr1);
    274   destroy_user(usr2);
    275 }
    276 
    277 static void test_blocked_until_scheduled_reclaim(void) {
    278   gpr_log(GPR_INFO, "** test_blocked_until_scheduled_reclaim **");
    279   grpc_resource_quota* q =
    280       grpc_resource_quota_create("test_blocked_until_scheduled_reclaim");
    281   grpc_resource_quota_resize(q, 1024);
    282   grpc_resource_user* usr = grpc_resource_user_create(q, "usr");
    283   {
    284     gpr_event ev;
    285     gpr_event_init(&ev);
    286     grpc_core::ExecCtx exec_ctx;
    287     grpc_resource_user_alloc(usr, 1024, set_event(&ev));
    288     grpc_core::ExecCtx::Get()->Flush();
    289     GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) !=
    290                nullptr);
    291     ;
    292   }
    293   gpr_event reclaim_done;
    294   gpr_event_init(&reclaim_done);
    295   {
    296     grpc_core::ExecCtx exec_ctx;
    297     grpc_resource_user_post_reclaimer(
    298         usr, false, make_reclaimer(usr, 1024, set_event(&reclaim_done)));
    299   }
    300   {
    301     gpr_event ev;
    302     gpr_event_init(&ev);
    303     grpc_core::ExecCtx exec_ctx;
    304     grpc_resource_user_alloc(usr, 1024, set_event(&ev));
    305     grpc_core::ExecCtx::Get()->Flush();
    306     GPR_ASSERT(gpr_event_wait(&reclaim_done,
    307                               grpc_timeout_seconds_to_deadline(5)) != nullptr);
    308     GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) !=
    309                nullptr);
    310     ;
    311   }
    312   {
    313     grpc_core::ExecCtx exec_ctx;
    314     grpc_resource_user_free(usr, 1024);
    315   }
    316   grpc_resource_quota_unref(q);
    317   destroy_user(usr);
    318 }
    319 
    320 static void test_blocked_until_scheduled_reclaim_and_scavenge(void) {
    321   gpr_log(GPR_INFO, "** test_blocked_until_scheduled_reclaim_and_scavenge **");
    322   grpc_resource_quota* q = grpc_resource_quota_create(
    323       "test_blocked_until_scheduled_reclaim_and_scavenge");
    324   grpc_resource_quota_resize(q, 1024);
    325   grpc_resource_user* usr1 = grpc_resource_user_create(q, "usr1");
    326   grpc_resource_user* usr2 = grpc_resource_user_create(q, "usr2");
    327   {
    328     gpr_event ev;
    329     gpr_event_init(&ev);
    330     grpc_core::ExecCtx exec_ctx;
    331     grpc_resource_user_alloc(usr1, 1024, set_event(&ev));
    332     grpc_core::ExecCtx::Get()->Flush();
    333     GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) !=
    334                nullptr);
    335     ;
    336   }
    337   gpr_event reclaim_done;
    338   gpr_event_init(&reclaim_done);
    339   {
    340     grpc_core::ExecCtx exec_ctx;
    341     grpc_resource_user_post_reclaimer(
    342         usr1, false, make_reclaimer(usr1, 1024, set_event(&reclaim_done)));
    343   }
    344   {
    345     gpr_event ev;
    346     gpr_event_init(&ev);
    347     grpc_core::ExecCtx exec_ctx;
    348     grpc_resource_user_alloc(usr2, 1024, set_event(&ev));
    349     grpc_core::ExecCtx::Get()->Flush();
    350     GPR_ASSERT(gpr_event_wait(&reclaim_done,
    351                               grpc_timeout_seconds_to_deadline(5)) != nullptr);
    352     GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) !=
    353                nullptr);
    354     ;
    355   }
    356   {
    357     grpc_core::ExecCtx exec_ctx;
    358     grpc_resource_user_free(usr2, 1024);
    359   }
    360   grpc_resource_quota_unref(q);
    361   destroy_user(usr1);
    362   destroy_user(usr2);
    363 }
    364 
    365 static void test_blocked_until_scheduled_destructive_reclaim(void) {
    366   gpr_log(GPR_INFO, "** test_blocked_until_scheduled_destructive_reclaim **");
    367   grpc_resource_quota* q = grpc_resource_quota_create(
    368       "test_blocked_until_scheduled_destructive_reclaim");
    369   grpc_resource_quota_resize(q, 1024);
    370   grpc_resource_user* usr = grpc_resource_user_create(q, "usr");
    371   {
    372     gpr_event ev;
    373     gpr_event_init(&ev);
    374     grpc_core::ExecCtx exec_ctx;
    375     grpc_resource_user_alloc(usr, 1024, set_event(&ev));
    376     grpc_core::ExecCtx::Get()->Flush();
    377     GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) !=
    378                nullptr);
    379     ;
    380   }
    381   gpr_event reclaim_done;
    382   gpr_event_init(&reclaim_done);
    383   {
    384     grpc_core::ExecCtx exec_ctx;
    385     grpc_resource_user_post_reclaimer(
    386         usr, true, make_reclaimer(usr, 1024, set_event(&reclaim_done)));
    387   }
    388   {
    389     gpr_event ev;
    390     gpr_event_init(&ev);
    391     grpc_core::ExecCtx exec_ctx;
    392     grpc_resource_user_alloc(usr, 1024, set_event(&ev));
    393     grpc_core::ExecCtx::Get()->Flush();
    394     GPR_ASSERT(gpr_event_wait(&reclaim_done,
    395                               grpc_timeout_seconds_to_deadline(5)) != nullptr);
    396     GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) !=
    397                nullptr);
    398     ;
    399   }
    400   {
    401     grpc_core::ExecCtx exec_ctx;
    402     grpc_resource_user_free(usr, 1024);
    403   }
    404   grpc_resource_quota_unref(q);
    405   destroy_user(usr);
    406 }
    407 
    408 static void test_unused_reclaim_is_cancelled(void) {
    409   gpr_log(GPR_INFO, "** test_unused_reclaim_is_cancelled **");
    410   grpc_resource_quota* q =
    411       grpc_resource_quota_create("test_unused_reclaim_is_cancelled");
    412   grpc_resource_quota_resize(q, 1024);
    413   grpc_resource_user* usr = grpc_resource_user_create(q, "usr");
    414   gpr_event benign_done;
    415   gpr_event_init(&benign_done);
    416   gpr_event destructive_done;
    417   gpr_event_init(&destructive_done);
    418   {
    419     grpc_core::ExecCtx exec_ctx;
    420     grpc_resource_user_post_reclaimer(
    421         usr, false, make_unused_reclaimer(set_event(&benign_done)));
    422     grpc_resource_user_post_reclaimer(
    423         usr, true, make_unused_reclaimer(set_event(&destructive_done)));
    424     grpc_core::ExecCtx::Get()->Flush();
    425     GPR_ASSERT(gpr_event_wait(&benign_done,
    426                               grpc_timeout_milliseconds_to_deadline(100)) ==
    427                nullptr);
    428     GPR_ASSERT(gpr_event_wait(&destructive_done,
    429                               grpc_timeout_milliseconds_to_deadline(100)) ==
    430                nullptr);
    431   }
    432   grpc_resource_quota_unref(q);
    433   destroy_user(usr);
    434   GPR_ASSERT(gpr_event_wait(&benign_done,
    435                             grpc_timeout_seconds_to_deadline(5)) != nullptr);
    436   GPR_ASSERT(gpr_event_wait(&destructive_done,
    437                             grpc_timeout_seconds_to_deadline(5)) != nullptr);
    438 }
    439 
    440 static void test_benign_reclaim_is_preferred(void) {
    441   gpr_log(GPR_INFO, "** test_benign_reclaim_is_preferred **");
    442   grpc_resource_quota* q =
    443       grpc_resource_quota_create("test_benign_reclaim_is_preferred");
    444   grpc_resource_quota_resize(q, 1024);
    445   grpc_resource_user* usr = grpc_resource_user_create(q, "usr");
    446   gpr_event benign_done;
    447   gpr_event_init(&benign_done);
    448   gpr_event destructive_done;
    449   gpr_event_init(&destructive_done);
    450   {
    451     gpr_event ev;
    452     gpr_event_init(&ev);
    453     grpc_core::ExecCtx exec_ctx;
    454     grpc_resource_user_alloc(usr, 1024, set_event(&ev));
    455     grpc_core::ExecCtx::Get()->Flush();
    456     GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) !=
    457                nullptr);
    458     ;
    459   }
    460   {
    461     grpc_core::ExecCtx exec_ctx;
    462     grpc_resource_user_post_reclaimer(
    463         usr, false, make_reclaimer(usr, 1024, set_event(&benign_done)));
    464     grpc_resource_user_post_reclaimer(
    465         usr, true, make_unused_reclaimer(set_event(&destructive_done)));
    466     grpc_core::ExecCtx::Get()->Flush();
    467     GPR_ASSERT(gpr_event_wait(&benign_done,
    468                               grpc_timeout_milliseconds_to_deadline(100)) ==
    469                nullptr);
    470     GPR_ASSERT(gpr_event_wait(&destructive_done,
    471                               grpc_timeout_milliseconds_to_deadline(100)) ==
    472                nullptr);
    473   }
    474   {
    475     gpr_event ev;
    476     gpr_event_init(&ev);
    477     grpc_core::ExecCtx exec_ctx;
    478     grpc_resource_user_alloc(usr, 1024, set_event(&ev));
    479     grpc_core::ExecCtx::Get()->Flush();
    480     GPR_ASSERT(gpr_event_wait(&benign_done,
    481                               grpc_timeout_seconds_to_deadline(5)) != nullptr);
    482     GPR_ASSERT(gpr_event_wait(&destructive_done,
    483                               grpc_timeout_milliseconds_to_deadline(100)) ==
    484                nullptr);
    485     GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) !=
    486                nullptr);
    487   }
    488   {
    489     grpc_core::ExecCtx exec_ctx;
    490     grpc_resource_user_free(usr, 1024);
    491   }
    492   grpc_resource_quota_unref(q);
    493   destroy_user(usr);
    494   GPR_ASSERT(gpr_event_wait(&benign_done,
    495                             grpc_timeout_seconds_to_deadline(5)) != nullptr);
    496   GPR_ASSERT(gpr_event_wait(&destructive_done,
    497                             grpc_timeout_seconds_to_deadline(5)) != nullptr);
    498 }
    499 
    500 static void test_multiple_reclaims_can_be_triggered(void) {
    501   gpr_log(GPR_INFO, "** test_multiple_reclaims_can_be_triggered **");
    502   grpc_resource_quota* q =
    503       grpc_resource_quota_create("test_multiple_reclaims_can_be_triggered");
    504   grpc_resource_quota_resize(q, 1024);
    505   grpc_resource_user* usr = grpc_resource_user_create(q, "usr");
    506   gpr_event benign_done;
    507   gpr_event_init(&benign_done);
    508   gpr_event destructive_done;
    509   gpr_event_init(&destructive_done);
    510   {
    511     gpr_event ev;
    512     gpr_event_init(&ev);
    513     grpc_core::ExecCtx exec_ctx;
    514     grpc_resource_user_alloc(usr, 1024, set_event(&ev));
    515     grpc_core::ExecCtx::Get()->Flush();
    516     GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) !=
    517                nullptr);
    518     ;
    519   }
    520   {
    521     grpc_core::ExecCtx exec_ctx;
    522     grpc_resource_user_post_reclaimer(
    523         usr, false, make_reclaimer(usr, 512, set_event(&benign_done)));
    524     grpc_resource_user_post_reclaimer(
    525         usr, true, make_reclaimer(usr, 512, set_event(&destructive_done)));
    526     grpc_core::ExecCtx::Get()->Flush();
    527     GPR_ASSERT(gpr_event_wait(&benign_done,
    528                               grpc_timeout_milliseconds_to_deadline(100)) ==
    529                nullptr);
    530     GPR_ASSERT(gpr_event_wait(&destructive_done,
    531                               grpc_timeout_milliseconds_to_deadline(100)) ==
    532                nullptr);
    533   }
    534   {
    535     gpr_event ev;
    536     gpr_event_init(&ev);
    537     grpc_core::ExecCtx exec_ctx;
    538     grpc_resource_user_alloc(usr, 1024, set_event(&ev));
    539     grpc_core::ExecCtx::Get()->Flush();
    540     GPR_ASSERT(gpr_event_wait(&benign_done,
    541                               grpc_timeout_seconds_to_deadline(5)) != nullptr);
    542     GPR_ASSERT(gpr_event_wait(&destructive_done,
    543                               grpc_timeout_seconds_to_deadline(5)) != nullptr);
    544     GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) !=
    545                nullptr);
    546     ;
    547   }
    548   {
    549     grpc_core::ExecCtx exec_ctx;
    550     grpc_resource_user_free(usr, 1024);
    551   }
    552   grpc_resource_quota_unref(q);
    553   destroy_user(usr);
    554   GPR_ASSERT(gpr_event_wait(&benign_done,
    555                             grpc_timeout_seconds_to_deadline(5)) != nullptr);
    556   GPR_ASSERT(gpr_event_wait(&destructive_done,
    557                             grpc_timeout_seconds_to_deadline(5)) != nullptr);
    558 }
    559 
    560 static void test_resource_user_stays_allocated_until_memory_released(void) {
    561   gpr_log(GPR_INFO,
    562           "** test_resource_user_stays_allocated_until_memory_released **");
    563   grpc_resource_quota* q = grpc_resource_quota_create(
    564       "test_resource_user_stays_allocated_until_memory_released");
    565   grpc_resource_quota_resize(q, 1024 * 1024);
    566   grpc_resource_user* usr = grpc_resource_user_create(q, "usr");
    567   {
    568     grpc_core::ExecCtx exec_ctx;
    569     grpc_resource_user_alloc(usr, 1024, nullptr);
    570   }
    571   {
    572     grpc_core::ExecCtx exec_ctx;
    573     grpc_resource_quota_unref(q);
    574     grpc_resource_user_unref(usr);
    575   }
    576   {
    577     grpc_core::ExecCtx exec_ctx;
    578     grpc_resource_user_free(usr, 1024);
    579   }
    580 }
    581 
    582 static void
    583 test_resource_user_stays_allocated_and_reclaimers_unrun_until_memory_released(
    584     void) {
    585   gpr_log(GPR_INFO,
    586           "** "
    587           "test_resource_user_stays_allocated_and_reclaimers_unrun_until_"
    588           "memory_released **");
    589   grpc_resource_quota* q = grpc_resource_quota_create(
    590       "test_resource_user_stays_allocated_and_reclaimers_unrun_until_memory_"
    591       "released");
    592   grpc_resource_quota_resize(q, 1024);
    593   for (int i = 0; i < 10; i++) {
    594     grpc_resource_user* usr = grpc_resource_user_create(q, "usr");
    595     gpr_event reclaimer_cancelled;
    596     gpr_event_init(&reclaimer_cancelled);
    597     {
    598       grpc_core::ExecCtx exec_ctx;
    599       grpc_resource_user_post_reclaimer(
    600           usr, false, make_unused_reclaimer(set_event(&reclaimer_cancelled)));
    601       grpc_core::ExecCtx::Get()->Flush();
    602       GPR_ASSERT(gpr_event_wait(&reclaimer_cancelled,
    603                                 grpc_timeout_milliseconds_to_deadline(100)) ==
    604                  nullptr);
    605     }
    606     {
    607       gpr_event allocated;
    608       gpr_event_init(&allocated);
    609       grpc_core::ExecCtx exec_ctx;
    610       grpc_resource_user_alloc(usr, 1024, set_event(&allocated));
    611       grpc_core::ExecCtx::Get()->Flush();
    612       GPR_ASSERT(gpr_event_wait(&allocated, grpc_timeout_seconds_to_deadline(
    613                                                 5)) != nullptr);
    614       GPR_ASSERT(gpr_event_wait(&reclaimer_cancelled,
    615                                 grpc_timeout_milliseconds_to_deadline(100)) ==
    616                  nullptr);
    617     }
    618     {
    619       grpc_core::ExecCtx exec_ctx;
    620       grpc_resource_user_unref(usr);
    621       grpc_core::ExecCtx::Get()->Flush();
    622       GPR_ASSERT(gpr_event_wait(&reclaimer_cancelled,
    623                                 grpc_timeout_milliseconds_to_deadline(100)) ==
    624                  nullptr);
    625     }
    626     {
    627       grpc_core::ExecCtx exec_ctx;
    628       grpc_resource_user_free(usr, 1024);
    629       grpc_core::ExecCtx::Get()->Flush();
    630       GPR_ASSERT(gpr_event_wait(&reclaimer_cancelled,
    631                                 grpc_timeout_seconds_to_deadline(5)) !=
    632                  nullptr);
    633     }
    634   }
    635   grpc_resource_quota_unref(q);
    636 }
    637 
    638 static void test_reclaimers_can_be_posted_repeatedly(void) {
    639   gpr_log(GPR_INFO, "** test_reclaimers_can_be_posted_repeatedly **");
    640   grpc_resource_quota* q =
    641       grpc_resource_quota_create("test_reclaimers_can_be_posted_repeatedly");
    642   grpc_resource_quota_resize(q, 1024);
    643   grpc_resource_user* usr = grpc_resource_user_create(q, "usr");
    644   {
    645     gpr_event allocated;
    646     gpr_event_init(&allocated);
    647     grpc_core::ExecCtx exec_ctx;
    648     grpc_resource_user_alloc(usr, 1024, set_event(&allocated));
    649     grpc_core::ExecCtx::Get()->Flush();
    650     GPR_ASSERT(gpr_event_wait(&allocated,
    651                               grpc_timeout_seconds_to_deadline(5)) != nullptr);
    652   }
    653   for (int i = 0; i < 10; i++) {
    654     gpr_event reclaimer_done;
    655     gpr_event_init(&reclaimer_done);
    656     {
    657       grpc_core::ExecCtx exec_ctx;
    658       grpc_resource_user_post_reclaimer(
    659           usr, false, make_reclaimer(usr, 1024, set_event(&reclaimer_done)));
    660       grpc_core::ExecCtx::Get()->Flush();
    661       GPR_ASSERT(gpr_event_wait(&reclaimer_done,
    662                                 grpc_timeout_milliseconds_to_deadline(100)) ==
    663                  nullptr);
    664     }
    665     {
    666       gpr_event allocated;
    667       gpr_event_init(&allocated);
    668       grpc_core::ExecCtx exec_ctx;
    669       grpc_resource_user_alloc(usr, 1024, set_event(&allocated));
    670       grpc_core::ExecCtx::Get()->Flush();
    671       GPR_ASSERT(gpr_event_wait(&allocated, grpc_timeout_seconds_to_deadline(
    672                                                 5)) != nullptr);
    673       GPR_ASSERT(gpr_event_wait(&reclaimer_done,
    674                                 grpc_timeout_seconds_to_deadline(5)) !=
    675                  nullptr);
    676     }
    677   }
    678   {
    679     grpc_core::ExecCtx exec_ctx;
    680     grpc_resource_user_free(usr, 1024);
    681   }
    682   destroy_user(usr);
    683   grpc_resource_quota_unref(q);
    684 }
    685 
    686 static void test_one_slice(void) {
    687   gpr_log(GPR_INFO, "** test_one_slice **");
    688 
    689   grpc_resource_quota* q = grpc_resource_quota_create("test_one_slice");
    690   grpc_resource_quota_resize(q, 1024);
    691 
    692   grpc_resource_user* usr = grpc_resource_user_create(q, "usr");
    693 
    694   grpc_resource_user_slice_allocator alloc;
    695   int num_allocs = 0;
    696   grpc_resource_user_slice_allocator_init(&alloc, usr, inc_int_cb, &num_allocs);
    697 
    698   grpc_slice_buffer buffer;
    699   grpc_slice_buffer_init(&buffer);
    700 
    701   {
    702     const int start_allocs = num_allocs;
    703     grpc_core::ExecCtx exec_ctx;
    704     grpc_resource_user_alloc_slices(&alloc, 1024, 1, &buffer);
    705     grpc_core::ExecCtx::Get()->Flush();
    706     assert_counter_becomes(&num_allocs, start_allocs + 1);
    707   }
    708 
    709   {
    710     grpc_core::ExecCtx exec_ctx;
    711     grpc_slice_buffer_destroy_internal(&buffer);
    712   }
    713   destroy_user(usr);
    714   grpc_resource_quota_unref(q);
    715 }
    716 
    717 static void test_one_slice_deleted_late(void) {
    718   gpr_log(GPR_INFO, "** test_one_slice_deleted_late **");
    719 
    720   grpc_resource_quota* q =
    721       grpc_resource_quota_create("test_one_slice_deleted_late");
    722   grpc_resource_quota_resize(q, 1024);
    723 
    724   grpc_resource_user* usr = grpc_resource_user_create(q, "usr");
    725 
    726   grpc_resource_user_slice_allocator alloc;
    727   int num_allocs = 0;
    728   grpc_resource_user_slice_allocator_init(&alloc, usr, inc_int_cb, &num_allocs);
    729 
    730   grpc_slice_buffer buffer;
    731   grpc_slice_buffer_init(&buffer);
    732 
    733   {
    734     const int start_allocs = num_allocs;
    735     grpc_core::ExecCtx exec_ctx;
    736     grpc_resource_user_alloc_slices(&alloc, 1024, 1, &buffer);
    737     grpc_core::ExecCtx::Get()->Flush();
    738     assert_counter_becomes(&num_allocs, start_allocs + 1);
    739   }
    740 
    741   {
    742     grpc_core::ExecCtx exec_ctx;
    743     grpc_resource_user_unref(usr);
    744   }
    745 
    746   grpc_resource_quota_unref(q);
    747   {
    748     grpc_core::ExecCtx exec_ctx;
    749     grpc_slice_buffer_destroy_internal(&buffer);
    750   }
    751 }
    752 
    753 static void test_resize_to_zero(void) {
    754   gpr_log(GPR_INFO, "** test_resize_to_zero **");
    755   grpc_resource_quota* q = grpc_resource_quota_create("test_resize_to_zero");
    756   grpc_resource_quota_resize(q, 0);
    757   grpc_resource_quota_unref(q);
    758 }
    759 
    760 static void test_negative_rq_free_pool(void) {
    761   gpr_log(GPR_INFO, "** test_negative_rq_free_pool **");
    762   grpc_resource_quota* q =
    763       grpc_resource_quota_create("test_negative_rq_free_pool");
    764   grpc_resource_quota_resize(q, 1024);
    765 
    766   grpc_resource_user* usr = grpc_resource_user_create(q, "usr");
    767 
    768   grpc_resource_user_slice_allocator alloc;
    769   int num_allocs = 0;
    770   grpc_resource_user_slice_allocator_init(&alloc, usr, inc_int_cb, &num_allocs);
    771 
    772   grpc_slice_buffer buffer;
    773   grpc_slice_buffer_init(&buffer);
    774 
    775   {
    776     const int start_allocs = num_allocs;
    777     grpc_core::ExecCtx exec_ctx;
    778     grpc_resource_user_alloc_slices(&alloc, 1024, 1, &buffer);
    779     grpc_core::ExecCtx::Get()->Flush();
    780     assert_counter_becomes(&num_allocs, start_allocs + 1);
    781   }
    782 
    783   grpc_resource_quota_resize(q, 512);
    784 
    785   double eps = 0.0001;
    786   GPR_ASSERT(grpc_resource_quota_get_memory_pressure(q) < 1 + eps);
    787   GPR_ASSERT(grpc_resource_quota_get_memory_pressure(q) > 1 - eps);
    788 
    789   {
    790     grpc_core::ExecCtx exec_ctx;
    791     grpc_resource_user_unref(usr);
    792   }
    793 
    794   grpc_resource_quota_unref(q);
    795   {
    796     grpc_core::ExecCtx exec_ctx;
    797     grpc_slice_buffer_destroy_internal(&buffer);
    798   }
    799 }
    800 
    801 // Simple test to check resource quota thread limits
    802 static void test_thread_limit() {
    803   grpc_core::ExecCtx exec_ctx;
    804 
    805   grpc_resource_quota* rq = grpc_resource_quota_create("test_thread_limit");
    806   grpc_resource_user* ru1 = grpc_resource_user_create(rq, "ru1");
    807   grpc_resource_user* ru2 = grpc_resource_user_create(rq, "ru2");
    808 
    809   // Max threads = 100
    810   grpc_resource_quota_set_max_threads(rq, 100);
    811 
    812   // Request quota for 100 threads (50 for ru1, 50 for ru2)
    813   GPR_ASSERT(grpc_resource_user_allocate_threads(ru1, 10));
    814   GPR_ASSERT(grpc_resource_user_allocate_threads(ru2, 10));
    815   GPR_ASSERT(grpc_resource_user_allocate_threads(ru1, 40));
    816   GPR_ASSERT(grpc_resource_user_allocate_threads(ru2, 40));
    817 
    818   // Threads exhausted. Next request must fail
    819   GPR_ASSERT(!grpc_resource_user_allocate_threads(ru2, 20));
    820 
    821   // Free 20 threads from two different users
    822   grpc_resource_user_free_threads(ru1, 10);
    823   grpc_resource_user_free_threads(ru2, 10);
    824 
    825   // Next request to 20 threads must succeed
    826   GPR_ASSERT(grpc_resource_user_allocate_threads(ru2, 20));
    827 
    828   // No more thread quota again
    829   GPR_ASSERT(!grpc_resource_user_allocate_threads(ru1, 20));
    830 
    831   // Free 10 more
    832   grpc_resource_user_free_threads(ru1, 10);
    833 
    834   GPR_ASSERT(grpc_resource_user_allocate_threads(ru1, 5));
    835   GPR_ASSERT(
    836       !grpc_resource_user_allocate_threads(ru2, 10));  // Only 5 available
    837   GPR_ASSERT(grpc_resource_user_allocate_threads(ru2, 5));
    838 
    839   // Teardown (ru1 and ru2 release all the quota back to rq)
    840   grpc_resource_user_unref(ru1);
    841   grpc_resource_user_unref(ru2);
    842   grpc_resource_quota_unref(rq);
    843 }
    844 
    845 // Change max quota in either direction dynamically
    846 static void test_thread_maxquota_change() {
    847   grpc_core::ExecCtx exec_ctx;
    848 
    849   grpc_resource_quota* rq =
    850       grpc_resource_quota_create("test_thread_maxquota_change");
    851   grpc_resource_user* ru1 = grpc_resource_user_create(rq, "ru1");
    852   grpc_resource_user* ru2 = grpc_resource_user_create(rq, "ru2");
    853 
    854   // Max threads = 100
    855   grpc_resource_quota_set_max_threads(rq, 100);
    856 
    857   // Request quota for 100 threads (50 for ru1, 50 for ru2)
    858   GPR_ASSERT(grpc_resource_user_allocate_threads(ru1, 50));
    859   GPR_ASSERT(grpc_resource_user_allocate_threads(ru2, 50));
    860 
    861   // Threads exhausted. Next request must fail
    862   GPR_ASSERT(!grpc_resource_user_allocate_threads(ru2, 20));
    863 
    864   // Increase maxquota and retry
    865   // Max threads = 150;
    866   grpc_resource_quota_set_max_threads(rq, 150);
    867   GPR_ASSERT(grpc_resource_user_allocate_threads(ru2, 20));  // ru2=70, ru1=50
    868 
    869   // Decrease maxquota (Note: Quota already given to ru1 and ru2 is unaffected)
    870   // Max threads = 10;
    871   grpc_resource_quota_set_max_threads(rq, 10);
    872 
    873   // New requests will fail until quota is available
    874   GPR_ASSERT(!grpc_resource_user_allocate_threads(ru1, 10));
    875 
    876   // Make quota available
    877   grpc_resource_user_free_threads(ru1, 50);                   // ru1 now has 0
    878   GPR_ASSERT(!grpc_resource_user_allocate_threads(ru1, 10));  // not enough
    879 
    880   grpc_resource_user_free_threads(ru2, 70);  // ru2 now has 0
    881 
    882   // Now we can get quota up-to 10, the current max
    883   GPR_ASSERT(grpc_resource_user_allocate_threads(ru2, 10));
    884   // No more thread quota again
    885   GPR_ASSERT(!grpc_resource_user_allocate_threads(ru1, 10));
    886 
    887   // Teardown (ru1 and ru2 release all the quota back to rq)
    888   grpc_resource_user_unref(ru1);
    889   grpc_resource_user_unref(ru2);
    890   grpc_resource_quota_unref(rq);
    891 }
    892 
    893 int main(int argc, char** argv) {
    894   grpc_test_init(argc, argv);
    895   grpc_init();
    896   gpr_mu_init(&g_mu);
    897   gpr_cv_init(&g_cv);
    898   test_no_op();
    899   test_resize_then_destroy();
    900   test_resource_user_no_op();
    901   test_instant_alloc_then_free();
    902   test_instant_alloc_free_pair();
    903   test_simple_async_alloc();
    904   test_async_alloc_blocked_by_size();
    905   test_scavenge();
    906   test_scavenge_blocked();
    907   test_blocked_until_scheduled_reclaim();
    908   test_blocked_until_scheduled_reclaim_and_scavenge();
    909   test_blocked_until_scheduled_destructive_reclaim();
    910   test_unused_reclaim_is_cancelled();
    911   test_benign_reclaim_is_preferred();
    912   test_multiple_reclaims_can_be_triggered();
    913   test_resource_user_stays_allocated_until_memory_released();
    914   test_resource_user_stays_allocated_and_reclaimers_unrun_until_memory_released();
    915   test_reclaimers_can_be_posted_repeatedly();
    916   test_one_slice();
    917   test_one_slice_deleted_late();
    918   test_resize_to_zero();
    919   test_negative_rq_free_pool();
    920   gpr_mu_destroy(&g_mu);
    921   gpr_cv_destroy(&g_cv);
    922 
    923   // Resource quota thread related
    924   test_thread_limit();
    925   test_thread_maxquota_change();
    926 
    927   grpc_shutdown();
    928   return 0;
    929 }
    930