summaryrefslogtreecommitdiff
path: root/src/or/scheduler.h
blob: 3932e60490b6319eb2301693ad7c641465e6871f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/* * Copyright (c) 2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */

/**
 * \file scheduler.h
 * \brief Header file for scheduler*.c
 **/

#ifndef TOR_SCHEDULER_H
#define TOR_SCHEDULER_H

#include "or.h"
#include "channel.h"
#include "testsupport.h"

/*
 * A scheduler implementation is a collection of function pointers. If you
 * would like to add a new scheduler called foo, create scheduler_foo.c,
 * implement at least the mandatory ones, and implement get_foo_scheduler()
 * that returns a complete scheduler_t for your foo scheduler. See
 * scheduler_kist.c for an example.
 *
 * These function pointers SHOULD NOT be used anywhere outside of the
 * scheduling source files. The rest of Tor should communicate with the
 * scheduling system through the functions near the bottom of this file, and
 * those functions will call into the current scheduler implementation as
 * necessary.
 *
 * If your scheduler doesn't need to implement something (for example: it
 * doesn't create any state for itself, thus it has nothing to free when Tor
 * is shutting down), then set that function pointer to NULL.
 */
typedef struct scheduler_s {
  /* (Optional) To be called when we want to prepare a scheduler for use.
   * Perhaps Tor just started and we are the lucky chosen scheduler, or
   * perhaps Tor is switching to this scheduler. No matter the case, this is
   * where we would prepare any state and initialize parameters. You might
   * think of this as the opposite of free_all(). */
  void (*init)(void);

  /* (Optional) To be called when we want to tell the scheduler to delete all
   * of its state (if any). Perhaps Tor is shutting down or perhaps we are
   * switching schedulers. */
  void (*free_all)(void);

  /* (Mandatory) Libevent controls the main event loop in Tor, and this is
   * where we register with libevent the next execution of run_sched_ev [which
   * ultimately calls run()]. */
  void (*schedule)(void);

  /* (Mandatory) This is the heart of a scheduler! This is where the
   * excitement happens! Here libevent has given us the chance to execute, and
   * we should do whatever we need to do in order to move some cells from
   * their circuit queues to output buffers in an intelligent manner. We
   * should do this quickly. When we are done, we'll try to schedule() ourself
   * if more work needs to be done to setup the next scehduling run. */
  void (*run)(void);

  /*
   * External event not related to the scheduler but that can influence it.
   */

  /* (Optional) To be called whenever Tor finds out about a new consensus.
   * First the scheduling system as a whole will react to the new consensus
   * and change the scheduler if needed. After that, whatever is the (possibly
   * new) scheduler will call this so it has the chance to react to the new
   * consensus too. If there's a consensus parameter that your scheduler wants
   * to keep an eye on, this is where you should check for it.  */
  void (*on_new_consensus)(const networkstatus_t *old_c,
                           const networkstatus_t *new_c);

  /* (Optional) To be called when a channel is being freed. Sometimes channels
   * go away (for example: the relay on the other end is shutting down). If
   * the scheduler keeps any channel-specific state and has memory to free
   * when channels go away, implement this and free it here. */
  void (*on_channel_free)(const channel_t *);

  /* (Optional) To be called whenever Tor is reloading configuration options.
   * For example: SIGHUP was issued and Tor is rereading its torrc. A
   * scheduler should use this as an opportunity to parse and cache torrc
   * options so that it doesn't have to call get_options() all the time. */
  void (*on_new_options)(void);
} scheduler_t;

/*****************************************************************************
 * Globally visible scheduler functions
 *
 * These functions are how the rest of Tor communicates with the scheduling
 * system.
 *****************************************************************************/

void scheduler_init(void);
void scheduler_free_all(void);
void scheduler_conf_changed(void);
void scheduler_notify_networkstatus_changed(const networkstatus_t *old_c,
                                            const networkstatus_t *new_c);
MOCK_DECL(void, scheduler_release_channel, (channel_t *chan));

/*
 * Ways for a channel to interact with the scheduling system. A channel only
 * really knows (i) whether or not it has cells it wants to send, and
 * (ii) whether or not it would like to write.
 */
void scheduler_channel_wants_writes(channel_t *chan);
MOCK_DECL(void, scheduler_channel_doesnt_want_writes, (channel_t *chan));
MOCK_DECL(void, scheduler_channel_has_waiting_cells, (channel_t *chan));

/*****************************************************************************
 * Private scheduler functions
 *
 * These functions are only visible to the scheduling system, the current
 * scheduler implementation, and tests.
 *****************************************************************************/
#ifdef SCHEDULER_PRIVATE_

/*********************************
 * Defined in scheduler.c
 *********************************/
int scheduler_should_use_kist(void);
smartlist_t *get_channels_pending(void);
struct event *get_run_sched_ev(void);
MOCK_DECL(int, scheduler_compare_channels,
          (const void *c1_v, const void *c2_v));

#ifdef TOR_UNIT_TESTS
extern smartlist_t *channels_pending;
extern struct event *run_sched_ev;
extern scheduler_t *scheduler;
void scheduler_touch_channel(channel_t *chan);
#endif /* TOR_UNIT_TESTS */

/*********************************
 * Defined in scheduler_kist.c
 *********************************/

/* Socke table entry which holds information of a channel's socket and kernel
 * TCP information. Only used by KIST. */
typedef struct socket_table_ent_s {
  HT_ENTRY(socket_table_ent_s) node;
  const channel_t *chan;
  /* Amount written this scheduling run */
  uint64_t written;
  /* Amount that can be written this scheduling run */
  uint64_t limit;
  /* TCP info from the kernel */
  uint32_t cwnd;
  uint32_t unacked;
  uint32_t mss;
  uint32_t notsent;
} socket_table_ent_t;

typedef HT_HEAD(outbuf_table_s, outbuf_table_ent_s) outbuf_table_t;

MOCK_DECL(int, channel_should_write_to_kernel,
          (outbuf_table_t *table, channel_t *chan));
MOCK_DECL(void, channel_write_to_kernel, (channel_t *chan));
MOCK_DECL(void, update_socket_info_impl, (socket_table_ent_t *ent));

scheduler_t *get_kist_scheduler(void);
int32_t kist_scheduler_run_interval(const networkstatus_t *ns);

#ifdef TOR_UNIT_TESTS
extern int32_t sched_run_interval;
#endif /* TOR_UNIT_TESTS */

/*********************************
 * Defined in scheduler_vanilla.c
 *********************************/

scheduler_t *get_vanilla_scheduler(void);

#endif /* SCHEDULER_PRIVATE_ */

#endif /* TOR_SCHEDULER_H */