tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

test_scheduler.c (41286B)


      1 /* Copyright (c) 2014-2021, The Tor Project, Inc. */
      2 /* See LICENSE for licensing information */
      3 
      4 #include "orconfig.h"
      5 
      6 #include <math.h>
      7 
      8 #define SCHEDULER_KIST_PRIVATE
      9 #define CHANNEL_OBJECT_PRIVATE
     10 #define CHANNEL_FILE_PRIVATE
     11 #include "core/or/or.h"
     12 #include "app/config/config.h"
     13 #include "lib/evloop/compat_libevent.h"
     14 #include "core/or/channel.h"
     15 #include "core/or/channeltls.h"
     16 #include "core/mainloop/connection.h"
     17 #include "feature/nodelist/networkstatus.h"
     18 #define SCHEDULER_PRIVATE
     19 #include "core/or/scheduler.h"
     20 
     21 /* Test suite stuff */
     22 #include "test/test.h"
     23 #include "test/fakechans.h"
     24 
     25 /* Shamelessly stolen from compat_libevent.c */
     26 #define V(major, minor, patch) \
     27  (((major) << 24) | ((minor) << 16) | ((patch) << 8))
     28 
     29 /******************************************************************************
     30 * Statistical info
     31 *****************************************************************************/
     32 static int scheduler_compare_channels_mock_ctr = 0;
     33 static int scheduler_run_mock_ctr = 0;
     34 
     35 /******************************************************************************
     36 * Utility functions and things we need to mock
     37 *****************************************************************************/
     38 static or_options_t mocked_options;
     39 static const or_options_t *
     40 mock_get_options(void)
     41 {
     42  return &mocked_options;
     43 }
     44 
     45 static void
     46 cleanup_scheduler_options(void)
     47 {
     48  if (mocked_options.SchedulerTypes_) {
     49    SMARTLIST_FOREACH(mocked_options.SchedulerTypes_, int *, i, tor_free(i));
     50    smartlist_free(mocked_options.SchedulerTypes_);
     51    mocked_options.SchedulerTypes_ = NULL;
     52  }
     53 }
     54 
     55 static void
     56 set_scheduler_options(int val)
     57 {
     58  int *type;
     59 
     60  if (mocked_options.SchedulerTypes_ == NULL) {
     61    mocked_options.SchedulerTypes_ = smartlist_new();
     62  }
     63  type = tor_malloc_zero(sizeof(int));
     64  *type = val;
     65  smartlist_add(mocked_options.SchedulerTypes_, type);
     66 }
     67 
     68 static void
     69 clear_options(void)
     70 {
     71  cleanup_scheduler_options();
     72  memset(&mocked_options, 0, sizeof(mocked_options));
     73 }
     74 
     75 static int32_t
     76 mock_vanilla_networkstatus_get_param(
     77    const networkstatus_t *ns, const char *param_name, int32_t default_val,
     78    int32_t min_val, int32_t max_val)
     79 {
     80  (void)ns;
     81  (void)default_val;
     82  (void)min_val;
     83  (void)max_val;
     84  (void)param_name;
     85  return 0;
     86 }
     87 
     88 static int32_t
     89 mock_kist_networkstatus_get_param(
     90    const networkstatus_t *ns, const char *param_name, int32_t default_val,
     91    int32_t min_val, int32_t max_val)
     92 {
     93  (void)ns;
     94  (void)default_val;
     95  (void)min_val;
     96  (void)max_val;
     97  (void)param_name;
     98  return 12;
     99 }
    100 
    101 static int
    102 scheduler_compare_channels_mock(const void *c1_v,
    103                                const void *c2_v)
    104 {
    105  uintptr_t p1, p2;
    106 
    107  p1 = (uintptr_t)(c1_v);
    108  p2 = (uintptr_t)(c2_v);
    109 
    110  ++scheduler_compare_channels_mock_ctr;
    111 
    112  if (p1 == p2) return 0;
    113  else if (p1 < p2) return 1;
    114  else return -1;
    115 }
    116 
    117 static void
    118 scheduler_run_noop_mock(void)
    119 {
    120  ++scheduler_run_mock_ctr;
    121 }
    122 
    123 static circuitmux_t *mock_ccm_tgt_1 = NULL;
    124 static circuitmux_t *mock_ccm_tgt_2 = NULL;
    125 static circuitmux_t *mock_cgp_tgt_1 = NULL;
    126 static circuitmux_policy_t *mock_cgp_val_1 = NULL;
    127 static circuitmux_t *mock_cgp_tgt_2 = NULL;
    128 static circuitmux_policy_t *mock_cgp_val_2 = NULL;
    129 
    130 static const circuitmux_policy_t *
    131 circuitmux_get_policy_mock(circuitmux_t *cmux)
    132 {
    133  const circuitmux_policy_t *result = NULL;
    134 
    135  tt_assert(cmux != NULL);
    136  if (cmux) {
    137    if (cmux == mock_cgp_tgt_1) result = mock_cgp_val_1;
    138    else if (cmux == mock_cgp_tgt_2) result = mock_cgp_val_2;
    139    else result = circuitmux_get_policy__real(cmux);
    140  }
    141 
    142 done:
    143  return result;
    144 }
    145 
    146 static int
    147 circuitmux_compare_muxes_mock(circuitmux_t *cmux_1,
    148                              circuitmux_t *cmux_2)
    149 {
    150  int result = 0;
    151 
    152  tt_assert(cmux_1 != NULL);
    153  tt_assert(cmux_2 != NULL);
    154 
    155  if (cmux_1 != cmux_2) {
    156    if (cmux_1 == mock_ccm_tgt_1 && cmux_2 == mock_ccm_tgt_2) result = -1;
    157    else if (cmux_1 == mock_ccm_tgt_2 && cmux_2 == mock_ccm_tgt_1) {
    158      result = 1;
    159    } else {
    160      if (cmux_1 == mock_ccm_tgt_1 || cmux_1 == mock_ccm_tgt_2) result = -1;
    161      else if (cmux_2 == mock_ccm_tgt_1 || cmux_2 == mock_ccm_tgt_2) {
    162        result = 1;
    163      } else {
    164        result = circuitmux_compare_muxes__real(cmux_1, cmux_2);
    165      }
    166    }
    167  }
    168  /* else result = 0 always */
    169 
    170 done:
    171  return result;
    172 }
    173 
    174 typedef struct {
    175  const channel_t *chan;
    176  ssize_t cells;
    177 } flush_mock_channel_t;
    178 
    179 static smartlist_t *chans_for_flush_mock = NULL;
    180 
    181 static void
    182 channel_flush_some_cells_mock_free_all(void)
    183 {
    184  if (chans_for_flush_mock) {
    185    SMARTLIST_FOREACH_BEGIN(chans_for_flush_mock,
    186                            flush_mock_channel_t *,
    187                            flush_mock_ch) {
    188      SMARTLIST_DEL_CURRENT(chans_for_flush_mock, flush_mock_ch);
    189      tor_free(flush_mock_ch);
    190    } SMARTLIST_FOREACH_END(flush_mock_ch);
    191 
    192    smartlist_free(chans_for_flush_mock);
    193    chans_for_flush_mock = NULL;
    194  }
    195 }
    196 
    197 static void
    198 channel_flush_some_cells_mock_set(channel_t *chan, ssize_t num_cells)
    199 {
    200  int found = 0;
    201 
    202  if (!chan) return;
    203  if (num_cells <= 0) return;
    204 
    205  if (!chans_for_flush_mock) {
    206    chans_for_flush_mock = smartlist_new();
    207  }
    208 
    209  SMARTLIST_FOREACH_BEGIN(chans_for_flush_mock,
    210                          flush_mock_channel_t *,
    211                          flush_mock_ch) {
    212    if (flush_mock_ch != NULL && flush_mock_ch->chan != NULL) {
    213      if (flush_mock_ch->chan == chan) {
    214        /* Found it */
    215        flush_mock_ch->cells = num_cells;
    216        found = 1;
    217        break;
    218      }
    219    } else {
    220      /* That shouldn't be there... */
    221      SMARTLIST_DEL_CURRENT(chans_for_flush_mock, flush_mock_ch);
    222      tor_free(flush_mock_ch);
    223    }
    224  } SMARTLIST_FOREACH_END(flush_mock_ch);
    225 
    226  if (! found) {
    227    /* The loop didn't find it */
    228    flush_mock_channel_t *flush_mock_ch;
    229    flush_mock_ch = tor_malloc_zero(sizeof(*flush_mock_ch));
    230    flush_mock_ch->chan = chan;
    231    flush_mock_ch->cells = num_cells;
    232    smartlist_add(chans_for_flush_mock, flush_mock_ch);
    233  }
    234 }
    235 
    236 static int
    237 channel_more_to_flush_mock(channel_t *chan)
    238 {
    239  tor_assert(chan);
    240 
    241  flush_mock_channel_t *found_mock_ch = NULL;
    242 
    243  SMARTLIST_FOREACH_BEGIN(chans_for_flush_mock,
    244                          flush_mock_channel_t *,
    245                          flush_mock_ch) {
    246    if (flush_mock_ch != NULL && flush_mock_ch->chan != NULL) {
    247      if (flush_mock_ch->chan == chan) {
    248        /* Found it */
    249        found_mock_ch = flush_mock_ch;
    250        break;
    251      }
    252    } else {
    253      /* That shouldn't be there... */
    254      SMARTLIST_DEL_CURRENT(chans_for_flush_mock, flush_mock_ch);
    255      tor_free(flush_mock_ch);
    256    }
    257  } SMARTLIST_FOREACH_END(flush_mock_ch);
    258 
    259  tor_assert(found_mock_ch);
    260 
    261  /* Check if any circuits would like to queue some */
    262  /* special for the mock: return the number of cells (instead of 1), or zero
    263   * if nothing to flush */
    264  return (found_mock_ch->cells > 0 ? (int)found_mock_ch->cells : 0 );
    265 }
    266 
    267 static void
    268 channel_write_to_kernel_mock(channel_t *chan)
    269 {
    270  (void)chan;
    271  //log_debug(LD_SCHED, "chan=%d writing to kernel",
    272  //    (int)chan->global_identifier);
    273 }
    274 
    275 static int
    276 channel_should_write_to_kernel_mock(outbuf_table_t *ot, channel_t *chan)
    277 {
    278  (void)ot;
    279  (void)chan;
    280  return 1;
    281  /* We could make this more complicated if we wanted. But I don't think doing
    282   * so tests much of anything */
    283  //static int called_counter = 0;
    284  //if (++called_counter >= 3) {
    285  //  called_counter -= 3;
    286  //  log_debug(LD_SCHED, "chan=%d should write to kernel",
    287  //      (int)chan->global_identifier);
    288  //  return 1;
    289  //}
    290  //return 0;
    291 }
    292 
    293 static ssize_t
    294 channel_flush_some_cells_mock(channel_t *chan, ssize_t num_cells)
    295 {
    296  ssize_t flushed = 0, max;
    297  char unlimited = 0;
    298  flush_mock_channel_t *found = NULL;
    299 
    300  tt_ptr_op(chan, OP_NE, NULL);
    301  if (chan) {
    302    if (num_cells < 0) {
    303      num_cells = 0;
    304      unlimited = 1;
    305    }
    306 
    307    /* Check if we have it */
    308    if (chans_for_flush_mock != NULL) {
    309      SMARTLIST_FOREACH_BEGIN(chans_for_flush_mock,
    310                              flush_mock_channel_t *,
    311                              flush_mock_ch) {
    312        if (flush_mock_ch != NULL && flush_mock_ch->chan != NULL) {
    313          if (flush_mock_ch->chan == chan) {
    314            /* Found it */
    315            found = flush_mock_ch;
    316            break;
    317          }
    318        } else {
    319          /* That shouldn't be there... */
    320          SMARTLIST_DEL_CURRENT(chans_for_flush_mock, flush_mock_ch);
    321          tor_free(flush_mock_ch);
    322        }
    323      } SMARTLIST_FOREACH_END(flush_mock_ch);
    324 
    325      if (found) {
    326        /* We found one */
    327        if (found->cells < 0) found->cells = 0;
    328 
    329        if (unlimited) max = found->cells;
    330        else max = MIN(found->cells, num_cells);
    331 
    332        flushed += max;
    333        found->cells -= max;
    334      }
    335    }
    336  }
    337 
    338 done:
    339  return flushed;
    340 }
    341 
    342 static void
    343 update_socket_info_impl_mock(socket_table_ent_t *ent)
    344 {
    345  ent->cwnd = ent->unacked = ent->mss = ent->notsent = 0;
    346  ent->limit = INT_MAX;
    347 }
    348 
    349 static void
    350 perform_channel_state_tests(int KISTSchedRunInterval, int sched_type)
    351 {
    352  channel_t *ch1 = NULL, *ch2 = NULL;
    353  int old_count;
    354 
    355  /* setup options so we're sure about what sched we are running */
    356  MOCK(get_options, mock_get_options);
    357  clear_options();
    358  mocked_options.KISTSchedRunInterval = KISTSchedRunInterval;
    359  set_scheduler_options(sched_type);
    360 
    361  /* Set up scheduler */
    362  scheduler_init();
    363  /*
    364   * Install the compare channels mock so we can test
    365   * scheduler_touch_channel().
    366   */
    367  MOCK(scheduler_compare_channels, scheduler_compare_channels_mock);
    368  /*
    369   * Disable scheduler_run so we can just check the state transitions
    370   * without having to make everything it might call work too.
    371   */
    372  ((scheduler_t *) the_scheduler)->run = scheduler_run_noop_mock;
    373 
    374  tt_int_op(smartlist_len(channels_pending), OP_EQ, 0);
    375 
    376  /* Set up a fake channel */
    377  ch1 = new_fake_channel();
    378  tt_assert(ch1);
    379 
    380  /* Start it off in OPENING */
    381  ch1->state = CHANNEL_STATE_OPENING;
    382  /* Try to register it */
    383  channel_register(ch1);
    384  tt_assert(ch1->registered);
    385 
    386  /* It should start off in SCHED_CHAN_IDLE */
    387  tt_int_op(ch1->scheduler_state, OP_EQ, SCHED_CHAN_IDLE);
    388 
    389  /* Now get another one */
    390  ch2 = new_fake_channel();
    391  tt_assert(ch2);
    392  ch2->state = CHANNEL_STATE_OPENING;
    393  channel_register(ch2);
    394  tt_assert(ch2->registered);
    395 
    396  /* Send ch1 to SCHED_CHAN_WAITING_TO_WRITE */
    397  scheduler_channel_has_waiting_cells(ch1);
    398  tt_int_op(ch1->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_TO_WRITE);
    399 
    400  /* This should send it to SCHED_CHAN_PENDING */
    401  scheduler_channel_wants_writes(ch1);
    402  tt_int_op(ch1->scheduler_state, OP_EQ, SCHED_CHAN_PENDING);
    403  tt_int_op(smartlist_len(channels_pending), OP_EQ, 1);
    404 
    405  /* Now send ch2 to SCHED_CHAN_WAITING_FOR_CELLS */
    406  scheduler_channel_wants_writes(ch2);
    407  tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_FOR_CELLS);
    408 
    409  /* Drop ch2 back to idle */
    410  scheduler_channel_doesnt_want_writes(ch2);
    411  tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_IDLE);
    412 
    413  /* ...and back to SCHED_CHAN_WAITING_FOR_CELLS */
    414  scheduler_channel_wants_writes(ch2);
    415  tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_FOR_CELLS);
    416 
    417  /* ...and this should kick ch2 into SCHED_CHAN_PENDING */
    418  scheduler_channel_has_waiting_cells(ch2);
    419  tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_PENDING);
    420  tt_int_op(smartlist_len(channels_pending), OP_EQ, 2);
    421 
    422  /* This should send ch2 to SCHED_CHAN_WAITING_TO_WRITE */
    423  scheduler_channel_doesnt_want_writes(ch2);
    424  tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_TO_WRITE);
    425  tt_int_op(smartlist_len(channels_pending), OP_EQ, 1);
    426 
    427  /* ...and back to SCHED_CHAN_PENDING */
    428  scheduler_channel_wants_writes(ch2);
    429  tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_PENDING);
    430  tt_int_op(smartlist_len(channels_pending), OP_EQ, 2);
    431 
    432  /* Now we exercise scheduler_touch_channel */
    433  old_count = scheduler_compare_channels_mock_ctr;
    434  scheduler_touch_channel(ch1);
    435  tt_assert(scheduler_compare_channels_mock_ctr > old_count);
    436 
    437  /* Release the ch2 and then do it another time to make sure it doesn't blow
    438   * up and we are still in a quiescent state. */
    439  scheduler_release_channel(ch2);
    440  tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_IDLE);
    441  tt_int_op(smartlist_len(channels_pending), OP_EQ, 1);
    442  /* Cheat a bit so make the release more confused but also will tells us if
    443   * the release did put the channel in the right state. */
    444  ch2->scheduler_state = SCHED_CHAN_PENDING;
    445  scheduler_release_channel(ch2);
    446  tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_IDLE);
    447  tt_int_op(smartlist_len(channels_pending), OP_EQ, 1);
    448 
    449  /* Close */
    450  channel_mark_for_close(ch1);
    451  tt_int_op(ch1->state, OP_EQ, CHANNEL_STATE_CLOSING);
    452  channel_mark_for_close(ch2);
    453  tt_int_op(ch2->state, OP_EQ, CHANNEL_STATE_CLOSING);
    454  channel_closed(ch1);
    455  tt_int_op(ch1->state, OP_EQ, CHANNEL_STATE_CLOSED);
    456  ch1 = NULL;
    457  channel_closed(ch2);
    458  tt_int_op(ch2->state, OP_EQ, CHANNEL_STATE_CLOSED);
    459  ch2 = NULL;
    460 
    461  /* Shut things down */
    462 
    463  channel_free_all();
    464  scheduler_free_all();
    465 
    466 done:
    467  tor_free(ch1);
    468  tor_free(ch2);
    469 
    470  UNMOCK(scheduler_compare_channels);
    471  UNMOCK(get_options);
    472  cleanup_scheduler_options();
    473 
    474  return;
    475 }
    476 
    477 static void
    478 test_scheduler_compare_channels(void *arg)
    479 {
    480  /* We don't actually need whole fake channels... */
    481  channel_t c1, c2;
    482  /* ...and some dummy circuitmuxes too */
    483  circuitmux_t *cm1 = NULL, *cm2 = NULL;
    484  int result;
    485 
    486  (void)arg;
    487 
    488  /* We can't actually see sizeof(circuitmux_t) from here */
    489  cm1 = tor_malloc_zero(sizeof(void *));
    490  cm2 = tor_malloc_zero(sizeof(void *));
    491 
    492  c1.cmux = cm1;
    493  c2.cmux = cm2;
    494 
    495  /* Configure circuitmux_get_policy() mock */
    496  mock_cgp_tgt_1 = cm1;
    497  mock_cgp_tgt_2 = cm2;
    498 
    499  /*
    500   * This is to test the different-policies case, which uses the policy
    501   * cast to an uintptr_t as an arbitrary but definite thing to compare.
    502   */
    503  mock_cgp_val_1 = tor_malloc_zero(16);
    504  mock_cgp_val_2 = tor_malloc_zero(16);
    505  if ( ((uintptr_t) mock_cgp_val_1) > ((uintptr_t) mock_cgp_val_2) ) {
    506    void *tmp = mock_cgp_val_1;
    507    mock_cgp_val_1 = mock_cgp_val_2;
    508    mock_cgp_val_2 = tmp;
    509  }
    510 
    511  MOCK(circuitmux_get_policy, circuitmux_get_policy_mock);
    512 
    513  /* Now set up circuitmux_compare_muxes() mock using cm1/cm2 */
    514  mock_ccm_tgt_1 = cm1;
    515  mock_ccm_tgt_2 = cm2;
    516  MOCK(circuitmux_compare_muxes, circuitmux_compare_muxes_mock);
    517 
    518  /* Equal-channel case */
    519  result = scheduler_compare_channels(&c1, &c1);
    520  tt_int_op(result, OP_EQ, 0);
    521 
    522  /* Distinct channels, distinct policies */
    523  result = scheduler_compare_channels(&c1, &c2);
    524  tt_int_op(result, OP_EQ, -1);
    525  result = scheduler_compare_channels(&c2, &c1);
    526  tt_int_op(result, OP_EQ, 1);
    527 
    528  /* Distinct channels, same policy */
    529  tor_free(mock_cgp_val_2);
    530  mock_cgp_val_2 = mock_cgp_val_1;
    531  result = scheduler_compare_channels(&c1, &c2);
    532  tt_int_op(result, OP_EQ, -1);
    533  result = scheduler_compare_channels(&c2, &c1);
    534  tt_int_op(result, OP_EQ, 1);
    535 
    536 done:
    537 
    538  UNMOCK(circuitmux_compare_muxes);
    539  mock_ccm_tgt_1 = NULL;
    540  mock_ccm_tgt_2 = NULL;
    541 
    542  UNMOCK(circuitmux_get_policy);
    543  mock_cgp_tgt_1 = NULL;
    544  mock_cgp_tgt_2 = NULL;
    545 
    546  tor_free(cm1);
    547  tor_free(cm2);
    548 
    549  if (mock_cgp_val_1 != mock_cgp_val_2)
    550    tor_free(mock_cgp_val_1);
    551  tor_free(mock_cgp_val_2);
    552  mock_cgp_val_1 = NULL;
    553  mock_cgp_val_2 = NULL;
    554 
    555  return;
    556 }
    557 
    558 /******************************************************************************
    559 * The actual tests!
    560 *****************************************************************************/
    561 
    562 static void
    563 test_scheduler_loop_vanilla(void *arg)
    564 {
    565  (void)arg;
    566  channel_t *ch1 = NULL, *ch2 = NULL;
    567  void (*run_func_ptr)(void);
    568 
    569  /* setup options so we're sure about what sched we are running */
    570  MOCK(get_options, mock_get_options);
    571  clear_options();
    572  set_scheduler_options(SCHEDULER_VANILLA);
    573  mocked_options.KISTSchedRunInterval = 0;
    574 
    575  /* Set up scheduler */
    576  scheduler_init();
    577  /*
    578   * Install the compare channels mock so we can test
    579   * scheduler_touch_channel().
    580   */
    581  MOCK(scheduler_compare_channels, scheduler_compare_channels_mock);
    582  /*
    583   * Disable scheduler_run so we can just check the state transitions
    584   * without having to make everything it might call work too.
    585   */
    586  run_func_ptr = the_scheduler->run;
    587  ((scheduler_t *) the_scheduler)->run = scheduler_run_noop_mock;
    588 
    589  tt_int_op(smartlist_len(channels_pending), OP_EQ, 0);
    590 
    591  /* Set up a fake channel */
    592  ch1 = new_fake_channel();
    593  ch1->magic = TLS_CHAN_MAGIC;
    594  tt_assert(ch1);
    595 
    596  /* Start it off in OPENING */
    597  ch1->state = CHANNEL_STATE_OPENING;
    598  /* Try to register it */
    599  channel_register(ch1);
    600  tt_assert(ch1->registered);
    601  /* Finish opening it */
    602  channel_change_state_open(ch1);
    603 
    604  /* It should start off in SCHED_CHAN_IDLE */
    605  tt_int_op(ch1->scheduler_state, OP_EQ, SCHED_CHAN_IDLE);
    606 
    607  /* Now get another one */
    608  ch2 = new_fake_channel();
    609  ch2->magic = TLS_CHAN_MAGIC;
    610  tt_assert(ch2);
    611  ch2->state = CHANNEL_STATE_OPENING;
    612  channel_register(ch2);
    613  tt_assert(ch2->registered);
    614  /*
    615   * Don't open ch2; then channel_num_cells_writeable() will return
    616   * zero and we'll get coverage of that exception case in scheduler_run()
    617   */
    618 
    619  tt_int_op(ch1->state, OP_EQ, CHANNEL_STATE_OPEN);
    620  tt_int_op(ch2->state, OP_EQ, CHANNEL_STATE_OPENING);
    621 
    622  /* Send it to SCHED_CHAN_WAITING_TO_WRITE */
    623  scheduler_channel_has_waiting_cells(ch1);
    624  tt_int_op(ch1->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_TO_WRITE);
    625 
    626  /* This should send it to SCHED_CHAN_PENDING */
    627  scheduler_channel_wants_writes(ch1);
    628  tt_int_op(ch1->scheduler_state, OP_EQ, SCHED_CHAN_PENDING);
    629  tt_int_op(smartlist_len(channels_pending), OP_EQ, 1);
    630 
    631  /* Now send ch2 to SCHED_CHAN_WAITING_FOR_CELLS */
    632  scheduler_channel_wants_writes(ch2);
    633  tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_FOR_CELLS);
    634 
    635  /* Drop ch2 back to idle */
    636  scheduler_channel_doesnt_want_writes(ch2);
    637  tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_IDLE);
    638 
    639  /* ...and back to SCHED_CHAN_WAITING_FOR_CELLS */
    640  scheduler_channel_wants_writes(ch2);
    641  tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_FOR_CELLS);
    642 
    643  /* ...and this should kick ch2 into SCHED_CHAN_PENDING */
    644  scheduler_channel_has_waiting_cells(ch2);
    645  tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_PENDING);
    646  tt_int_op(smartlist_len(channels_pending), OP_EQ, 2);
    647 
    648  /*
    649   * Now we've got two pending channels and need to fire off
    650   * the scheduler run() that we kept.
    651   */
    652  run_func_ptr();
    653 
    654  /*
    655   * Assert that they're still in the states we left and aren't still
    656   * pending
    657   */
    658  tt_int_op(ch1->state, OP_EQ, CHANNEL_STATE_OPEN);
    659  tt_int_op(ch2->state, OP_EQ, CHANNEL_STATE_OPENING);
    660  tt_assert(ch1->scheduler_state != SCHED_CHAN_PENDING);
    661  tt_assert(ch2->scheduler_state != SCHED_CHAN_PENDING);
    662  tt_int_op(smartlist_len(channels_pending), OP_EQ, 0);
    663 
    664  /* Now, finish opening ch2, and get both back to pending */
    665  channel_change_state_open(ch2);
    666  scheduler_channel_wants_writes(ch1);
    667  scheduler_channel_wants_writes(ch2);
    668  scheduler_channel_has_waiting_cells(ch1);
    669  scheduler_channel_has_waiting_cells(ch2);
    670  tt_int_op(ch1->state, OP_EQ, CHANNEL_STATE_OPEN);
    671  tt_int_op(ch2->state, OP_EQ, CHANNEL_STATE_OPEN);
    672  tt_int_op(ch1->scheduler_state, OP_EQ, SCHED_CHAN_PENDING);
    673  tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_PENDING);
    674  tt_int_op(smartlist_len(channels_pending), OP_EQ, 2);
    675 
    676  /* Now, set up the channel_flush_some_cells() mock */
    677  MOCK(channel_flush_some_cells, channel_flush_some_cells_mock);
    678  /*
    679   * 16 cells on ch1 means it'll completely drain into the 32 cells
    680   * fakechan's num_cells_writeable() returns.
    681   */
    682  channel_flush_some_cells_mock_set(ch1, 16);
    683  /*
    684   * This one should get sent back to pending, since num_cells_writeable()
    685   * will still return non-zero.
    686   */
    687  channel_flush_some_cells_mock_set(ch2, 48);
    688 
    689  /*
    690   * And re-run the scheduler run() loop with non-zero returns from
    691   * channel_flush_some_cells() this time.
    692   */
    693  run_func_ptr();
    694 
    695  /*
    696   * ch1 should have gone to SCHED_CHAN_WAITING_FOR_CELLS, with 16 flushed
    697   * and 32 writeable.
    698   */
    699  tt_int_op(ch1->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_FOR_CELLS);
    700  /*
    701   * ...ch2 should also have gone to SCHED_CHAN_WAITING_FOR_CELLS, with
    702   * channel_more_to_flush() returning false and channel_num_cells_writeable()
    703   * > 0/
    704   */
    705  tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_FOR_CELLS);
    706 
    707  /* Close */
    708  channel_mark_for_close(ch1);
    709  tt_int_op(ch1->state, OP_EQ, CHANNEL_STATE_CLOSING);
    710  channel_mark_for_close(ch2);
    711  tt_int_op(ch2->state, OP_EQ, CHANNEL_STATE_CLOSING);
    712  channel_closed(ch1);
    713  tt_int_op(ch1->state, OP_EQ, CHANNEL_STATE_CLOSED);
    714  ch1 = NULL;
    715  channel_closed(ch2);
    716  tt_int_op(ch2->state, OP_EQ, CHANNEL_STATE_CLOSED);
    717  ch2 = NULL;
    718 
    719  /* Shut things down */
    720  channel_flush_some_cells_mock_free_all();
    721  channel_free_all();
    722  scheduler_free_all();
    723 
    724 done:
    725  tor_free(ch1);
    726  tor_free(ch2);
    727  cleanup_scheduler_options();
    728 
    729  UNMOCK(channel_flush_some_cells);
    730  UNMOCK(scheduler_compare_channels);
    731  UNMOCK(get_options);
    732 }
    733 
    734 static void
    735 test_scheduler_loop_kist(void *arg)
    736 {
    737  (void) arg;
    738 
    739 #ifndef HAVE_KIST_SUPPORT
    740  return;
    741 #endif
    742 
    743  channel_t *ch1 = new_fake_channel(), *ch2 = new_fake_channel();
    744  channel_t *ch3 = new_fake_channel();
    745 
    746  /* setup options so we're sure about what sched we are running */
    747  MOCK(get_options, mock_get_options);
    748  MOCK(channel_flush_some_cells, channel_flush_some_cells_mock);
    749  MOCK(channel_more_to_flush, channel_more_to_flush_mock);
    750  MOCK(channel_write_to_kernel, channel_write_to_kernel_mock);
    751  MOCK(channel_should_write_to_kernel, channel_should_write_to_kernel_mock);
    752  MOCK(update_socket_info_impl, update_socket_info_impl_mock);
    753  clear_options();
    754  mocked_options.KISTSchedRunInterval = 11;
    755  set_scheduler_options(SCHEDULER_KIST);
    756  scheduler_init();
    757 
    758  tt_assert(ch1);
    759  ch1->magic = TLS_CHAN_MAGIC;
    760  ch1->state = CHANNEL_STATE_OPENING;
    761  channel_register(ch1);
    762  tt_assert(ch1->registered);
    763  channel_change_state_open(ch1);
    764  scheduler_channel_has_waiting_cells(ch1);
    765  scheduler_channel_wants_writes(ch1);
    766  channel_flush_some_cells_mock_set(ch1, 5);
    767 
    768  tt_assert(ch2);
    769  ch2->magic = TLS_CHAN_MAGIC;
    770  ch2->state = CHANNEL_STATE_OPENING;
    771  channel_register(ch2);
    772  tt_assert(ch2->registered);
    773  channel_change_state_open(ch2);
    774  scheduler_channel_has_waiting_cells(ch2);
    775  scheduler_channel_wants_writes(ch2);
    776  channel_flush_some_cells_mock_set(ch2, 5);
    777 
    778  the_scheduler->run();
    779 
    780  scheduler_channel_has_waiting_cells(ch1);
    781  channel_flush_some_cells_mock_set(ch1, 5);
    782 
    783  the_scheduler->run();
    784 
    785  scheduler_channel_has_waiting_cells(ch1);
    786  channel_flush_some_cells_mock_set(ch1, 5);
    787  scheduler_channel_has_waiting_cells(ch2);
    788  channel_flush_some_cells_mock_set(ch2, 5);
    789 
    790  the_scheduler->run();
    791 
    792  channel_flush_some_cells_mock_free_all();
    793 
    794  /* We'll try to run this closed channel threw the scheduler loop and make
    795   * sure it ends up in the right state. */
    796  tt_assert(ch3);
    797  ch3->magic = TLS_CHAN_MAGIC;
    798  ch3->state = CHANNEL_STATE_OPEN;
    799  circuitmux_free(ch3->cmux);
    800  ch3->cmux = circuitmux_alloc();
    801  channel_register(ch3);
    802  tt_assert(ch3->registered);
    803 
    804  ch3->scheduler_state = SCHED_CHAN_WAITING_FOR_CELLS;
    805  scheduler_channel_has_waiting_cells(ch3);
    806  /* Should be in the pending list now waiting to be handled. */
    807  tt_int_op(ch3->scheduler_state, OP_EQ, SCHED_CHAN_PENDING);
    808  tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 1);
    809  /* By running the scheduler on a closed channel, it should end up in the
    810   * IDLE state and not in the pending channel list. */
    811  ch3->state = CHANNEL_STATE_CLOSED;
    812  the_scheduler->run();
    813  tt_int_op(ch3->scheduler_state, OP_EQ, SCHED_CHAN_IDLE);
    814  tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 0);
    815 
    816 done:
    817  /* Prep the channel so the free() function doesn't explode. */
    818  ch1->state = ch2->state = ch3->state = CHANNEL_STATE_CLOSED;
    819  ch1->registered = ch2->registered = ch3->registered = 0;
    820  channel_free(ch1);
    821  channel_free(ch2);
    822  channel_free(ch3);
    823  UNMOCK(update_socket_info_impl);
    824  UNMOCK(channel_should_write_to_kernel);
    825  UNMOCK(channel_write_to_kernel);
    826  UNMOCK(channel_more_to_flush);
    827  UNMOCK(channel_flush_some_cells);
    828  UNMOCK(get_options);
    829  scheduler_free_all();
    830  return;
    831 }
    832 
    833 static void
    834 test_scheduler_channel_states(void *arg)
    835 {
    836  (void)arg;
    837  perform_channel_state_tests(-1, SCHEDULER_VANILLA);
    838  perform_channel_state_tests(11, SCHEDULER_KIST_LITE);
    839 #ifdef HAVE_KIST_SUPPORT
    840  perform_channel_state_tests(11, SCHEDULER_KIST);
    841 #endif
    842 }
    843 
    844 static void
    845 test_scheduler_initfree(void *arg)
    846 {
    847  (void)arg;
    848 
    849  tt_ptr_op(channels_pending, OP_EQ, NULL);
    850  tt_ptr_op(run_sched_ev, OP_EQ, NULL);
    851 
    852  MOCK(get_options, mock_get_options);
    853  set_scheduler_options(SCHEDULER_KIST);
    854  set_scheduler_options(SCHEDULER_KIST_LITE);
    855  set_scheduler_options(SCHEDULER_VANILLA);
    856 
    857  scheduler_init();
    858 
    859  tt_ptr_op(channels_pending, OP_NE, NULL);
    860  tt_ptr_op(run_sched_ev, OP_NE, NULL);
    861  /* We have specified nothing in the torrc and there's no consensus so the
    862   * KIST scheduler is what should be in use */
    863  tt_ptr_op(the_scheduler, OP_EQ, get_kist_scheduler());
    864  tt_int_op(sched_run_interval, OP_EQ, KIST_SCHED_RUN_INTERVAL_DEFAULT);
    865 
    866  scheduler_free_all();
    867 
    868  tt_ptr_op(channels_pending, OP_EQ, NULL);
    869  tt_ptr_op(run_sched_ev, OP_EQ, NULL);
    870 
    871 done:
    872  UNMOCK(get_options);
    873  cleanup_scheduler_options();
    874  return;
    875 }
    876 
    877 static void
    878 test_scheduler_can_use_kist(void *arg)
    879 {
    880  (void)arg;
    881 
    882  int res_should, res_freq;
    883  MOCK(get_options, mock_get_options);
    884 
    885  /* Test force enabling of KIST */
    886  clear_options();
    887  mocked_options.KISTSchedRunInterval = 1234;
    888  res_should = scheduler_can_use_kist();
    889  res_freq = kist_scheduler_run_interval();
    890 #ifdef HAVE_KIST_SUPPORT
    891  tt_int_op(res_should, OP_EQ, 1);
    892 #else /* HAVE_KIST_SUPPORT */
    893  tt_int_op(res_should, OP_EQ, 0);
    894 #endif /* HAVE_KIST_SUPPORT */
    895  tt_int_op(res_freq, OP_EQ, 1234);
    896 
    897  /* Test defer to consensus, but no consensus available */
    898  clear_options();
    899  mocked_options.KISTSchedRunInterval = 0;
    900  res_should = scheduler_can_use_kist();
    901  res_freq = kist_scheduler_run_interval();
    902 #ifdef HAVE_KIST_SUPPORT
    903  tt_int_op(res_should, OP_EQ, 1);
    904 #else /* HAVE_KIST_SUPPORT */
    905  tt_int_op(res_should, OP_EQ, 0);
    906 #endif /* HAVE_KIST_SUPPORT */
    907  tt_int_op(res_freq, OP_EQ, KIST_SCHED_RUN_INTERVAL_DEFAULT);
    908 
    909  /* Test defer to consensus, and kist consensus available */
    910  MOCK(networkstatus_get_param, mock_kist_networkstatus_get_param);
    911  clear_options();
    912  mocked_options.KISTSchedRunInterval = 0;
    913  res_should = scheduler_can_use_kist();
    914  res_freq = kist_scheduler_run_interval();
    915 #ifdef HAVE_KIST_SUPPORT
    916  tt_int_op(res_should, OP_EQ, 1);
    917 #else /* HAVE_KIST_SUPPORT */
    918  tt_int_op(res_should, OP_EQ, 0);
    919 #endif /* HAVE_KIST_SUPPORT */
    920  tt_int_op(res_freq, OP_EQ, 12);
    921  UNMOCK(networkstatus_get_param);
    922 
    923  /* Test defer to consensus, and vanilla consensus available */
    924  MOCK(networkstatus_get_param, mock_vanilla_networkstatus_get_param);
    925  clear_options();
    926  mocked_options.KISTSchedRunInterval = 0;
    927  res_should = scheduler_can_use_kist();
    928  res_freq = kist_scheduler_run_interval();
    929  tt_int_op(res_should, OP_EQ, 0);
    930  tt_int_op(res_freq, OP_EQ, 0);
    931  UNMOCK(networkstatus_get_param);
    932 
    933 done:
    934  UNMOCK(get_options);
    935  return;
    936 }
    937 
    938 static void
    939 test_scheduler_ns_changed(void *arg)
    940 {
    941  (void) arg;
    942 
    943  /*
    944   * Currently no scheduler implementations use the old/new consensuses passed
    945   * in scheduler_notify_networkstatus_changed, so it is okay to pass NULL.
    946   *
    947   * "But then what does test actually exercise???" It tests that
    948   * scheduler_notify_networkstatus_changed fetches the correct value from the
    949   * consensus, and then switches the scheduler if necessasry.
    950   */
    951 
    952  MOCK(get_options, mock_get_options);
    953  clear_options();
    954  set_scheduler_options(SCHEDULER_KIST);
    955  set_scheduler_options(SCHEDULER_VANILLA);
    956 
    957  tt_ptr_op(the_scheduler, OP_EQ, NULL);
    958 
    959  /* Change from vanilla to kist via consensus */
    960  the_scheduler = get_vanilla_scheduler();
    961  MOCK(networkstatus_get_param, mock_kist_networkstatus_get_param);
    962  scheduler_notify_networkstatus_changed();
    963  UNMOCK(networkstatus_get_param);
    964 #ifdef HAVE_KIST_SUPPORT
    965  tt_ptr_op(the_scheduler, OP_EQ, get_kist_scheduler());
    966 #else
    967  tt_ptr_op(the_scheduler, OP_EQ, get_vanilla_scheduler());
    968 #endif
    969 
    970  /* Change from kist to vanilla via consensus */
    971  the_scheduler = get_kist_scheduler();
    972  MOCK(networkstatus_get_param, mock_vanilla_networkstatus_get_param);
    973  scheduler_notify_networkstatus_changed();
    974  UNMOCK(networkstatus_get_param);
    975  tt_ptr_op(the_scheduler, OP_EQ, get_vanilla_scheduler());
    976 
    977  /* Doesn't change when using KIST */
    978  the_scheduler = get_kist_scheduler();
    979  MOCK(networkstatus_get_param, mock_kist_networkstatus_get_param);
    980  scheduler_notify_networkstatus_changed();
    981  UNMOCK(networkstatus_get_param);
    982 #ifdef HAVE_KIST_SUPPORT
    983  tt_ptr_op(the_scheduler, OP_EQ, get_kist_scheduler());
    984 #else
    985  tt_ptr_op(the_scheduler, OP_EQ, get_vanilla_scheduler());
    986 #endif
    987 
    988  /* Doesn't change when using vanilla */
    989  the_scheduler = get_vanilla_scheduler();
    990  MOCK(networkstatus_get_param, mock_vanilla_networkstatus_get_param);
    991  scheduler_notify_networkstatus_changed();
    992  UNMOCK(networkstatus_get_param);
    993  tt_ptr_op(the_scheduler, OP_EQ, get_vanilla_scheduler());
    994 
    995 done:
    996  UNMOCK(get_options);
    997  cleanup_scheduler_options();
    998  return;
    999 }
   1000 
   1001 /*
   1002 * Mocked functions for the kist_pending_list test.
   1003 */
   1004 
   1005 static int mock_flush_some_cells_num = 1;
   1006 static int mock_more_to_flush = 0;
   1007 static int mock_update_socket_info_limit = 0;
   1008 
   1009 static ssize_t
   1010 channel_flush_some_cells_mock_var(channel_t *chan, ssize_t num_cells)
   1011 {
   1012  (void) chan;
   1013  (void) num_cells;
   1014  return mock_flush_some_cells_num;
   1015 }
   1016 
   1017 /* Because when we flush cells, it is possible that the connection outbuf gets
   1018 * fully drained, the wants to write scheduler event is fired back while we
   1019 * are in the scheduler loop so this mock function does it for us.
   1020 * Furthermore, the socket limit is set to 0 so once this is triggered, it
   1021 * informs the scheduler that it can't write on the socket anymore. */
   1022 static void
   1023 channel_write_to_kernel_mock_trigger_24700(channel_t *chan)
   1024 {
   1025  static int chan_id_seen[2] = {0};
   1026  if (++chan_id_seen[chan->global_identifier - 1] > 1) {
   1027    tt_assert(0);
   1028  }
   1029 
   1030  scheduler_channel_wants_writes(chan);
   1031 
   1032 done:
   1033  return;
   1034 }
   1035 
   1036 static int
   1037 channel_more_to_flush_mock_var(channel_t *chan)
   1038 {
   1039  (void) chan;
   1040  return mock_more_to_flush;
   1041 }
   1042 
   1043 static void
   1044 update_socket_info_impl_mock_var(socket_table_ent_t *ent)
   1045 {
   1046  ent->cwnd = ent->unacked = ent->mss = ent->notsent = 0;
   1047  ent->limit = mock_update_socket_info_limit;
   1048 }
   1049 
   1050 static void
   1051 test_scheduler_kist_pending_list(void *arg)
   1052 {
   1053  (void) arg;
   1054 
   1055 #ifndef HAVE_KIST_SUPPORT
   1056  return;
   1057 #endif
   1058 
   1059  /* This is for testing the channel flow with the pending list that is
   1060   * depending on the channel state, what will be the expected behavior of the
   1061   * scheduler with that list.
   1062   *
   1063   * For instance, we want to catch double channel add or removing a channel
   1064   * that doesn't exists, or putting a channel in the list in a wrong state.
   1065   * Essentially, this will articifically test cases of the KIST main loop and
   1066   * entry point in the channel subsystem.
   1067   *
   1068   * In part, this is to also catch things like #24700 and provide a test bed
   1069   * for more testing in the future like so. */
   1070 
   1071  /* Mocking a series of scheduler function to control the flow of the
   1072   * scheduler loop to test every use cases and assess the pending list. */
   1073  MOCK(get_options, mock_get_options);
   1074  MOCK(channel_flush_some_cells, channel_flush_some_cells_mock_var);
   1075  MOCK(channel_more_to_flush, channel_more_to_flush_mock_var);
   1076  MOCK(update_socket_info_impl, update_socket_info_impl_mock_var);
   1077  MOCK(channel_write_to_kernel, channel_write_to_kernel_mock);
   1078  MOCK(channel_should_write_to_kernel, channel_should_write_to_kernel_mock);
   1079 
   1080  /* Setup options so we're sure about what sched we are running */
   1081  mocked_options.KISTSchedRunInterval = 10;
   1082  set_scheduler_options(SCHEDULER_KIST);
   1083 
   1084  /* Init scheduler. */
   1085  scheduler_init();
   1086 
   1087  /* Initialize a channel. We'll need a second channel for the #24700 bug
   1088   * test. */
   1089  channel_t *chan1 = new_fake_channel();
   1090  channel_t *chan2 = new_fake_channel();
   1091  tt_assert(chan1);
   1092  tt_assert(chan2);
   1093  chan1->magic = chan2->magic = TLS_CHAN_MAGIC;
   1094  channel_register(chan1);
   1095  channel_register(chan2);
   1096  tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_IDLE);
   1097  tt_int_op(chan1->sched_heap_idx, OP_EQ, -1);
   1098  tt_int_op(chan2->scheduler_state, OP_EQ, SCHED_CHAN_IDLE);
   1099  tt_int_op(chan2->sched_heap_idx, OP_EQ, -1);
   1100 
   1101  /* Once a channel becomes OPEN, it always have at least one cell in it so
   1102   * the scheduler is notified that the channel wants to write so this is the
   1103   * first step. Might not make sense to you but it is the way it is. */
   1104  scheduler_channel_wants_writes(chan1);
   1105  tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_FOR_CELLS);
   1106  tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 0);
   1107 
   1108  /* Signal the scheduler that it has waiting cells which means the channel
   1109   * will get scheduled. */
   1110  scheduler_channel_has_waiting_cells(chan1);
   1111  tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_PENDING);
   1112  tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 1);
   1113  /* Subsequent call should not add it more times. It is possible we add many
   1114   * cells in rapid succession before the channel is scheduled. */
   1115  scheduler_channel_has_waiting_cells(chan1);
   1116  tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_PENDING);
   1117  tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 1);
   1118  scheduler_channel_has_waiting_cells(chan1);
   1119  tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_PENDING);
   1120  tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 1);
   1121 
   1122  /* We'll flush one cell and make it that the socket can write but no more to
   1123   * flush else we end up in an infinite loop. We expect the channel to be put
   1124   * in waiting for cells state and the pending list empty. */
   1125  mock_update_socket_info_limit = INT_MAX;
   1126  mock_more_to_flush = 0;
   1127  the_scheduler->run();
   1128  tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 0);
   1129  tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_FOR_CELLS);
   1130 
   1131  /* Lets make believe that a cell is now in the channel but this time the
   1132   * channel can't write so obviously it has more to flush. We expect the
   1133   * channel to be back in the pending list. */
   1134  scheduler_channel_has_waiting_cells(chan1);
   1135  mock_update_socket_info_limit = 0;
   1136  mock_more_to_flush = 1;
   1137  the_scheduler->run();
   1138  tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 1);
   1139  tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_PENDING);
   1140 
   1141  /* Channel is in the pending list now, during that time, we'll trigger a
   1142   * wants to write event because maybe the channel buffers were emptied in
   1143   * the meantime. This is possible because once the connection outbuf is
   1144   * flushed down the low watermark, the scheduler is notified.
   1145   *
   1146   * We expect the channel to NOT be added in the pending list again and stay
   1147   * in PENDING state. */
   1148  scheduler_channel_wants_writes(chan1);
   1149  tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 1);
   1150  tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_PENDING);
   1151 
   1152  /* Make it that the channel can write now but has nothing else to flush. We
   1153   * expect that it is removed from the pending list and waiting for cells. */
   1154  mock_update_socket_info_limit = INT_MAX;
   1155  mock_more_to_flush = 0;
   1156  the_scheduler->run();
   1157  tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 0);
   1158  tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_FOR_CELLS);
   1159 
   1160  /* While waiting for cells, lets say we were able to write more things on
   1161   * the connection outbuf (unlikely that this can happen but let say it
   1162   * does). We expect the channel to stay in waiting for cells. */
   1163  scheduler_channel_wants_writes(chan1);
   1164  tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 0);
   1165  tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_FOR_CELLS);
   1166 
   1167  /* We'll not put it in the pending list and make the flush cell fail with 0
   1168   * cell flushed. We expect that it is put back in waiting for cells. */
   1169  scheduler_channel_has_waiting_cells(chan1);
   1170  tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 1);
   1171  tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_PENDING);
   1172  mock_flush_some_cells_num = 0;
   1173  the_scheduler->run();
   1174  tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 0);
   1175  tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_FOR_CELLS);
   1176 
   1177  /* Set the channel to a state where it doesn't want to write more. We expect
   1178   * that the channel becomes idle. */
   1179  scheduler_channel_doesnt_want_writes(chan1);
   1180  tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 0);
   1181  tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_IDLE);
   1182 
   1183  /* Some cells arrive on the channel now. We expect it to go back in waiting
   1184   * to write. You might wonder why it is not put in the pending list? Because
   1185   * once the channel becomes OPEN again (the doesn't want to write event only
   1186   * occurs if the channel goes in MAINT mode), if there are cells in the
   1187   * channel, the wants to write event is triggered thus putting the channel
   1188   * in pending mode.
   1189   *
   1190   * Else, if no cells, it stays IDLE and then once a cell comes in, it should
   1191   * go in waiting to write which is a BUG itself because the channel can't be
   1192   * scheduled until a second cell comes in. Hopefully, #24554 will fix that
   1193   * for KIST. */
   1194  scheduler_channel_has_waiting_cells(chan1);
   1195  tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 0);
   1196  tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_TO_WRITE);
   1197 
   1198  /* Second cell comes in, unfortunately, it won't get scheduled until a wants
   1199   * to write event occurs like described above. */
   1200  scheduler_channel_has_waiting_cells(chan1);
   1201  tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 0);
   1202  tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_TO_WRITE);
   1203 
   1204  /* Unblock everything putting the channel in the pending list. */
   1205  scheduler_channel_wants_writes(chan1);
   1206  tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 1);
   1207  tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_PENDING);
   1208 
   1209  /* Testing bug #24700 which is the situation where we have at least two
   1210   * different channels in the pending list. The first one gets flushed and
   1211   * bytes are written on the wire which triggers a wants to write event
   1212   * because the outbuf is below the low watermark. The bug was that this
   1213   * exact channel was added back in the pending list because its state wasn't
   1214   * PENDING.
   1215   *
   1216   * The following does some ninja-tsu to try to make it happen. We need two
   1217   * different channels so we create a second one and add it to the pending
   1218   * list. Then, we have a custom function when we write to kernel that does
   1219   * two important things:
   1220   *
   1221   *  1) Calls scheduler_channel_wants_writes(chan) on the channel.
   1222   *  2) Keeps track of how many times it sees the channel going through. If
   1223   *     that limit goes > 1, it means we've added the channel twice in the
   1224   *     pending list.
   1225   *
   1226   * In the end, we expect both channels to be in the pending list after this
   1227   * scheduler run. */
   1228 
   1229  /* Put the second channel in the pending list. */
   1230  scheduler_channel_wants_writes(chan2);
   1231  scheduler_channel_has_waiting_cells(chan2);
   1232  tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 2);
   1233  tt_int_op(chan2->scheduler_state, OP_EQ, SCHED_CHAN_PENDING);
   1234 
   1235  /* This makes it that the first pass on socket_can_write() will be true but
   1236   * then when a single cell is flushed (514 + 29 bytes), the second call to
   1237   * socket_can_write() will be false. If it wasn't sending back false on the
   1238   * second run, we end up in an infinite loop of the scheduler. */
   1239  mock_update_socket_info_limit = 600;
   1240  /* We want to hit "Case 3:" of the scheduler so channel_more_to_flush() is
   1241   * true but socket_can_write() has to be false on the second check on the
   1242   * channel. */
   1243  mock_more_to_flush = 1;
   1244  mock_flush_some_cells_num = 1;
   1245  MOCK(channel_write_to_kernel, channel_write_to_kernel_mock_trigger_24700);
   1246  the_scheduler->run();
   1247  tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 2);
   1248  tt_int_op(chan1->scheduler_state, OP_EQ, SCHED_CHAN_PENDING);
   1249  tt_int_op(chan2->scheduler_state, OP_EQ, SCHED_CHAN_PENDING);
   1250 
   1251 done:
   1252  chan1->state = chan2->state = CHANNEL_STATE_CLOSED;
   1253  chan1->registered = chan2->registered = 0;
   1254  channel_free(chan1);
   1255  channel_free(chan2);
   1256  scheduler_free_all();
   1257 
   1258  UNMOCK(get_options);
   1259  UNMOCK(channel_flush_some_cells);
   1260  UNMOCK(channel_more_to_flush);
   1261  UNMOCK(update_socket_info_impl);
   1262  UNMOCK(channel_write_to_kernel);
   1263  UNMOCK(channel_should_write_to_kernel);
   1264 }
   1265 
   1266 struct testcase_t scheduler_tests[] = {
   1267  { "compare_channels", test_scheduler_compare_channels,
   1268    TT_FORK, NULL, NULL },
   1269  { "channel_states", test_scheduler_channel_states, TT_FORK, NULL, NULL },
   1270  { "initfree", test_scheduler_initfree, TT_FORK, NULL, NULL },
   1271  { "loop_vanilla", test_scheduler_loop_vanilla, TT_FORK, NULL, NULL },
   1272  { "loop_kist", test_scheduler_loop_kist, TT_FORK, NULL, NULL },
   1273  { "ns_changed", test_scheduler_ns_changed, TT_FORK, NULL, NULL},
   1274  { "should_use_kist", test_scheduler_can_use_kist, TT_FORK, NULL, NULL },
   1275  { "kist_pending_list", test_scheduler_kist_pending_list, TT_FORK,
   1276    NULL, NULL },
   1277  END_OF_TESTCASES
   1278 };