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 };