|
@@ -174,6 +174,25 @@ STATIC struct event *run_sched_ev = NULL;
|
|
|
* Functions that can only be accessed from this file.
|
|
|
*****************************************************************************/
|
|
|
|
|
|
+/** Return a human readable string for the given scheduler type. */
|
|
|
+static const char *
|
|
|
+get_scheduler_type_string(scheduler_types_t type)
|
|
|
+{
|
|
|
+ switch(type) {
|
|
|
+ case SCHEDULER_VANILLA:
|
|
|
+ return "Vanilla";
|
|
|
+ case SCHEDULER_KIST:
|
|
|
+ return "KIST";
|
|
|
+ case SCHEDULER_KIST_LITE:
|
|
|
+ return "KISTLite";
|
|
|
+ case SCHEDULER_NONE:
|
|
|
+ /* fallthrough */
|
|
|
+ default:
|
|
|
+ tor_assert_unreached();
|
|
|
+ return "(N/A)";
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* Scheduler event callback; this should get triggered once per event loop
|
|
|
* if any scheduling work was created during the event loop.
|
|
@@ -204,65 +223,6 @@ scheduler_evt_callback(evutil_socket_t fd, short events, void *arg)
|
|
|
the_scheduler->schedule();
|
|
|
}
|
|
|
|
|
|
-/*****************************************************************************
|
|
|
- * Scheduling system private function definitions
|
|
|
- *
|
|
|
- * Functions that can only be accessed from scheduler*.c
|
|
|
- *****************************************************************************/
|
|
|
-
|
|
|
-/** Return the pending channel list. */
|
|
|
-smartlist_t *
|
|
|
-get_channels_pending(void)
|
|
|
-{
|
|
|
- return channels_pending;
|
|
|
-}
|
|
|
-
|
|
|
-/** Comparison function to use when sorting pending channels. */
|
|
|
-MOCK_IMPL(int,
|
|
|
-scheduler_compare_channels, (const void *c1_v, const void *c2_v))
|
|
|
-{
|
|
|
- const channel_t *c1 = NULL, *c2 = NULL;
|
|
|
- /* These are a workaround for -Wbad-function-cast throwing a fit */
|
|
|
- const circuitmux_policy_t *p1, *p2;
|
|
|
- uintptr_t p1_i, p2_i;
|
|
|
-
|
|
|
- tor_assert(c1_v);
|
|
|
- tor_assert(c2_v);
|
|
|
-
|
|
|
- c1 = (const channel_t *)(c1_v);
|
|
|
- c2 = (const channel_t *)(c2_v);
|
|
|
-
|
|
|
- if (c1 != c2) {
|
|
|
- if (circuitmux_get_policy(c1->cmux) ==
|
|
|
- circuitmux_get_policy(c2->cmux)) {
|
|
|
- /* Same cmux policy, so use the mux comparison */
|
|
|
- return circuitmux_compare_muxes(c1->cmux, c2->cmux);
|
|
|
- } else {
|
|
|
- /*
|
|
|
- * Different policies; not important to get this edge case perfect
|
|
|
- * because the current code never actually gives different channels
|
|
|
- * different cmux policies anyway. Just use this arbitrary but
|
|
|
- * definite choice.
|
|
|
- */
|
|
|
- p1 = circuitmux_get_policy(c1->cmux);
|
|
|
- p2 = circuitmux_get_policy(c2->cmux);
|
|
|
- p1_i = (uintptr_t)p1;
|
|
|
- p2_i = (uintptr_t)p2;
|
|
|
-
|
|
|
- return (p1_i < p2_i) ? -1 : 1;
|
|
|
- }
|
|
|
- } else {
|
|
|
- /* c1 == c2, so always equal */
|
|
|
- return 0;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/*****************************************************************************
|
|
|
- * Scheduling system global functions
|
|
|
- *
|
|
|
- * Functions that can be accessed from anywhere in Tor.
|
|
|
- *****************************************************************************/
|
|
|
-
|
|
|
/** Using the global options, select the scheduler we should be using. */
|
|
|
static void
|
|
|
select_scheduler(void)
|
|
@@ -312,6 +272,8 @@ select_scheduler(void)
|
|
|
new_scheduler = get_kist_scheduler();
|
|
|
scheduler_kist_set_lite_mode();
|
|
|
goto end;
|
|
|
+ case SCHEDULER_NONE:
|
|
|
+ /* fallthrough */
|
|
|
default:
|
|
|
/* Our option validation should have caught this. */
|
|
|
tor_assert_unreached();
|
|
@@ -333,8 +295,6 @@ select_scheduler(void)
|
|
|
|
|
|
/* Set the chosen scheduler. */
|
|
|
the_scheduler = new_scheduler;
|
|
|
- log_notice(LD_CONFIG, "Scheduler type %s has been enabled.",
|
|
|
- chosen_sched_type);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -346,11 +306,21 @@ static void
|
|
|
set_scheduler(void)
|
|
|
{
|
|
|
const scheduler_t *old_scheduler = the_scheduler;
|
|
|
+ scheduler_types_t old_scheduler_type = SCHEDULER_NONE;
|
|
|
+
|
|
|
+ /* We keep track of the type in order to log only if the type switched. We
|
|
|
+ * can't just use the scheduler pointers because KIST and KISTLite share the
|
|
|
+ * same object. */
|
|
|
+ if (the_scheduler) {
|
|
|
+ old_scheduler_type = the_scheduler->type;
|
|
|
+ }
|
|
|
|
|
|
/* From the options, select the scheduler type to set. */
|
|
|
select_scheduler();
|
|
|
tor_assert(the_scheduler);
|
|
|
|
|
|
+ /* We look at the pointer difference in case the old sched and new sched
|
|
|
+ * share the same scheduler object, as is the case with KIST and KISTLite. */
|
|
|
if (old_scheduler != the_scheduler) {
|
|
|
/* Allow the old scheduler to clean up, if needed. */
|
|
|
if (old_scheduler && old_scheduler->free_all) {
|
|
@@ -362,8 +332,74 @@ set_scheduler(void)
|
|
|
the_scheduler->init();
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ /* Finally we notice log if we switched schedulers. We use the type in case
|
|
|
+ * two schedulers share a scheduler object. */
|
|
|
+ if (old_scheduler_type != the_scheduler->type) {
|
|
|
+ log_notice(LD_CONFIG, "Scheduler type %s has been enabled.",
|
|
|
+ get_scheduler_type_string(the_scheduler->type));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*****************************************************************************
|
|
|
+ * Scheduling system private function definitions
|
|
|
+ *
|
|
|
+ * Functions that can only be accessed from scheduler*.c
|
|
|
+ *****************************************************************************/
|
|
|
+
|
|
|
+/** Return the pending channel list. */
|
|
|
+smartlist_t *
|
|
|
+get_channels_pending(void)
|
|
|
+{
|
|
|
+ return channels_pending;
|
|
|
}
|
|
|
|
|
|
+/** Comparison function to use when sorting pending channels. */
|
|
|
+MOCK_IMPL(int,
|
|
|
+scheduler_compare_channels, (const void *c1_v, const void *c2_v))
|
|
|
+{
|
|
|
+ const channel_t *c1 = NULL, *c2 = NULL;
|
|
|
+ /* These are a workaround for -Wbad-function-cast throwing a fit */
|
|
|
+ const circuitmux_policy_t *p1, *p2;
|
|
|
+ uintptr_t p1_i, p2_i;
|
|
|
+
|
|
|
+ tor_assert(c1_v);
|
|
|
+ tor_assert(c2_v);
|
|
|
+
|
|
|
+ c1 = (const channel_t *)(c1_v);
|
|
|
+ c2 = (const channel_t *)(c2_v);
|
|
|
+
|
|
|
+ if (c1 != c2) {
|
|
|
+ if (circuitmux_get_policy(c1->cmux) ==
|
|
|
+ circuitmux_get_policy(c2->cmux)) {
|
|
|
+ /* Same cmux policy, so use the mux comparison */
|
|
|
+ return circuitmux_compare_muxes(c1->cmux, c2->cmux);
|
|
|
+ } else {
|
|
|
+ /*
|
|
|
+ * Different policies; not important to get this edge case perfect
|
|
|
+ * because the current code never actually gives different channels
|
|
|
+ * different cmux policies anyway. Just use this arbitrary but
|
|
|
+ * definite choice.
|
|
|
+ */
|
|
|
+ p1 = circuitmux_get_policy(c1->cmux);
|
|
|
+ p2 = circuitmux_get_policy(c2->cmux);
|
|
|
+ p1_i = (uintptr_t)p1;
|
|
|
+ p2_i = (uintptr_t)p2;
|
|
|
+
|
|
|
+ return (p1_i < p2_i) ? -1 : 1;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ /* c1 == c2, so always equal */
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*****************************************************************************
|
|
|
+ * Scheduling system global functions
|
|
|
+ *
|
|
|
+ * Functions that can be accessed from anywhere in Tor.
|
|
|
+ *****************************************************************************/
|
|
|
+
|
|
|
/**
|
|
|
* This is how the scheduling system is notified of Tor's configuration
|
|
|
* changing. For example: a SIGHUP was issued.
|