tor  0.4.2.1-alpha-dev
scheduler_vanilla.c
1 /* Copyright (c) 2017-2019, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
3 
4 #include "core/or/or.h"
5 #include "app/config/config.h"
6 #define TOR_CHANNEL_INTERNAL_
7 #include "core/or/channel.h"
8 #define SCHEDULER_PRIVATE_
9 #include "core/or/scheduler.h"
10 
11 /*****************************************************************************
12  * Other internal data
13  *****************************************************************************/
14 
15 /* Maximum cells to flush in a single call to channel_flush_some_cells(); */
16 #define MAX_FLUSH_CELLS 1000
17 
18 /*****************************************************************************
19  * Externally called function implementations
20  *****************************************************************************/
21 
22 /* Return true iff the scheduler has work to perform. */
23 static int
24 have_work(void)
25 {
27  IF_BUG_ONCE(!cp) {
28  return 0; // channels_pending doesn't exist so... no work?
29  }
30  return smartlist_len(cp) > 0;
31 }
32 
35 static void
36 vanilla_scheduler_schedule(void)
37 {
38  if (!have_work()) {
39  return;
40  }
41 
42  /* Activate our event so it can process channels. */
44 }
45 
46 static void
47 vanilla_scheduler_run(void)
48 {
49  int n_cells, n_chans_before, n_chans_after;
50  ssize_t flushed, flushed_this_time;
52  smartlist_t *to_readd = NULL;
53  channel_t *chan = NULL;
54 
55  log_debug(LD_SCHED, "We have a chance to run the scheduler");
56 
57  n_chans_before = smartlist_len(cp);
58 
59  while (smartlist_len(cp) > 0) {
60  /* Pop off a channel */
61  chan = smartlist_pqueue_pop(cp,
62  scheduler_compare_channels,
63  offsetof(channel_t, sched_heap_idx));
64  IF_BUG_ONCE(!chan) {
65  /* Some-freaking-how a NULL got into the channels_pending. That should
66  * never happen, but it should be harmless to ignore it and keep looping.
67  */
68  continue;
69  }
70 
71  /* Figure out how many cells we can write */
72  n_cells = channel_num_cells_writeable(chan);
73  if (n_cells > 0) {
74  log_debug(LD_SCHED,
75  "Scheduler saw pending channel %"PRIu64 " at %p with "
76  "%d cells writeable",
77  (chan->global_identifier), chan, n_cells);
78 
79  flushed = 0;
80  while (flushed < n_cells) {
81  flushed_this_time =
82  channel_flush_some_cells(chan,
83  MIN(MAX_FLUSH_CELLS, (size_t) n_cells - flushed));
84  if (flushed_this_time <= 0) break;
85  flushed += flushed_this_time;
86  }
87 
88  if (flushed < n_cells) {
89  /* We ran out of cells to flush */
90  scheduler_set_channel_state(chan, SCHED_CHAN_WAITING_FOR_CELLS);
91  } else {
92  /* The channel may still have some cells */
93  if (channel_more_to_flush(chan)) {
94  /* The channel goes to either pending or waiting_to_write */
95  if (channel_num_cells_writeable(chan) > 0) {
96  /* Add it back to pending later */
97  if (!to_readd) to_readd = smartlist_new();
98  smartlist_add(to_readd, chan);
99  log_debug(LD_SCHED,
100  "Channel %"PRIu64 " at %p "
101  "is still pending",
102  (chan->global_identifier),
103  chan);
104  } else {
105  /* It's waiting to be able to write more */
106  scheduler_set_channel_state(chan, SCHED_CHAN_WAITING_TO_WRITE);
107  }
108  } else {
109  /* No cells left; it can go to idle or waiting_for_cells */
110  if (channel_num_cells_writeable(chan) > 0) {
111  /*
112  * It can still accept writes, so it goes to
113  * waiting_for_cells
114  */
115  scheduler_set_channel_state(chan, SCHED_CHAN_WAITING_FOR_CELLS);
116  } else {
117  /*
118  * We exactly filled up the output queue with all available
119  * cells; go to idle.
120  */
121  scheduler_set_channel_state(chan, SCHED_CHAN_IDLE);
122  }
123  }
124  }
125 
126  log_debug(LD_SCHED,
127  "Scheduler flushed %d cells onto pending channel "
128  "%"PRIu64 " at %p",
129  (int)flushed, (chan->global_identifier),
130  chan);
131  } else {
132  log_info(LD_SCHED,
133  "Scheduler saw pending channel %"PRIu64 " at %p with "
134  "no cells writeable",
135  (chan->global_identifier), chan);
136  /* Put it back to WAITING_TO_WRITE */
137  scheduler_set_channel_state(chan, SCHED_CHAN_WAITING_TO_WRITE);
138  }
139  }
140 
141  /* Readd any channels we need to */
142  if (to_readd) {
143  SMARTLIST_FOREACH_BEGIN(to_readd, channel_t *, readd_chan) {
144  scheduler_set_channel_state(readd_chan, SCHED_CHAN_PENDING);
146  scheduler_compare_channels,
147  offsetof(channel_t, sched_heap_idx),
148  readd_chan);
149  } SMARTLIST_FOREACH_END(readd_chan);
150  smartlist_free(to_readd);
151  }
152 
153  n_chans_after = smartlist_len(cp);
154  log_debug(LD_SCHED, "Scheduler handled %d of %d pending channels",
155  n_chans_before - n_chans_after, n_chans_before);
156 }
157 
158 /* Stores the vanilla scheduler function pointers. */
159 static scheduler_t vanilla_scheduler = {
160  .type = SCHEDULER_VANILLA,
161  .free_all = NULL,
162  .on_channel_free = NULL,
163  .init = NULL,
164  .on_new_consensus = NULL,
165  .schedule = vanilla_scheduler_schedule,
166  .run = vanilla_scheduler_run,
167  .on_new_options = NULL,
168 };
169 
170 scheduler_t *
171 get_vanilla_scheduler(void)
172 {
173  return &vanilla_scheduler;
174 }
175 
#define LD_SCHED
Definition: log.h:105
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
void smartlist_pqueue_add(smartlist_t *sl, int(*compare)(const void *a, const void *b), ptrdiff_t idx_field_offset, void *item)
Definition: smartlist.c:726
void * smartlist_pqueue_pop(smartlist_t *sl, int(*compare)(const void *a, const void *b), ptrdiff_t idx_field_offset)
Definition: smartlist.c:755
void smartlist_add(smartlist_t *sl, void *element)
smartlist_t * get_channels_pending(void)
Definition: scheduler.c:397
Header file for config.c.
void scheduler_ev_active(void)
Definition: scheduler.c:598
Header file for scheduler*.c.
int channel_num_cells_writeable(channel_t *chan)
Definition: channel.c:3102
Header file for channel.c.
Master header file for Tor-specific functionality.
#define IF_BUG_ONCE(cond)
Definition: util_bug.h:234
void scheduler_set_channel_state(channel_t *chan, int new_state)
Definition: scheduler.c:386
uint64_t global_identifier
Definition: channel.h:197