Revision 67bd949a nest/proto.c

View differences:

nest/proto.c
14 14
#include "nest/protocol.h"
15 15
#include "lib/resource.h"
16 16
#include "lib/lists.h"
17
#include "lib/event.h"
17 18
#include "conf/conf.h"
18 19
#include "nest/route.h"
19 20
#include "nest/iface.h"
20 21

  
22
static pool *proto_pool;
23

  
21 24
list protocol_list;
22 25
list proto_list;
23
list inactive_proto_list;
26

  
27
static list inactive_proto_list;
28
static list initial_proto_list;
29

  
30
static char *p_states[] = { "DOWN", "START", "UP", "STOP" };
31
static char *c_states[] = { "HUNGRY", "FEEDING", "HAPPY", "FLUSHING" };
32

  
33
static void
34
proto_relink(struct proto *p)
35
{
36
  rem_node(&p->n);
37
  add_tail(p->core_state == FS_HAPPY ? &proto_list : &inactive_proto_list, &p->n);
38
}
24 39

  
25 40
void *
26 41
proto_new(struct proto_config *c, unsigned size)
27 42
{
28 43
  struct protocol *pr = c->proto;
29
  struct proto *p = cfg_allocz(size);	/* FIXME: Allocate from global pool */
44
  pool *r = rp_new(proto_pool, c->name);
45
  struct proto *p = mb_alloc(r, size);
30 46

  
31 47
  p->cf = c;
32 48
  p->debug = c->debug;
49
  p->name = c->name;
33 50
  p->preference = c->preference;
34 51
  p->disabled = c->disabled;
35 52
  p->proto = pr;
36
  p->pool = rp_new(&root_pool, c->name);
53
  p->pool = r;
54
  p->attn = ev_new(r);
55
  p->attn->data = p;
37 56
  return p;
38 57
}
39 58

  
......
57 76

  
58 77
  init_list(&proto_list);
59 78
  init_list(&inactive_proto_list);
79
  init_list(&initial_proto_list);
60 80
  debug("Protocol preconfig:");
61 81
  WALK_LIST(p, protocol_list)
62 82
    {
......
97 117
      debug(" %s", x->name);
98 118
      p = x->proto;
99 119
      q = p->init(x);
100
      add_tail(&inactive_proto_list, &q->n);
120
      q->proto_state = PS_DOWN;
121
      q->core_state = FS_HUNGRY;
122
      add_tail(&initial_proto_list, &q->n);
101 123
    }
102 124
  debug("\n");
103 125
}
104 126

  
105 127
static void
106
proto_start(struct proto *p)
128
proto_rethink_goal(struct proto *p)
107 129
{
108
  rem_node(&p->n);
109
  if (p->disabled)
130
  struct protocol *q = p->proto;
131

  
132
  if (p->core_state == p->core_goal)
110 133
    return;
111
  p->proto_state = PS_DOWN;
112
  p->core_state = FS_HUNGRY;
113
  if (p->proto->start && p->proto->start(p) != PS_UP)
114
    bug("Delayed protocol start not supported yet");
115
  p->proto_state = PS_UP;
116
  p->core_state = FS_FEEDING;
117
  if_feed_baby(p);
118
  rt_feed_baby(p);
119
  p->core_state = FS_HAPPY;
120
  add_tail(&proto_list, &p->n);
134
  if (p->core_goal == FS_HAPPY)		/* Going up */
135
    {
136
      if (p->core_state == FS_HUNGRY && p->proto_state == PS_DOWN)
137
	{
138
	  DBG("Kicking %s up\n", p->name);
139
	  proto_notify_state(p, (q->start ? q->start(p) : PS_UP));
140
	}
141
    }
142
  else 					/* Going down */
143
    {
144
      if (p->proto_state == PS_START || p->proto_state == PS_UP)
145
	{
146
	  DBG("Kicking %s down\n", p->name);
147
	  proto_notify_state(p, (q->shutdown ? q->shutdown(p) : PS_DOWN));
148
	}
149
    }
150
}
151

  
152
static void
153
proto_set_goal(struct proto *p, unsigned goal)
154
{
155
  if (p->disabled)
156
    goal = FS_HUNGRY;
157
  p->core_goal = goal;
158
  proto_rethink_goal(p);
121 159
}
122 160

  
123 161
void
......
126 164
  struct proto *p, *n;
127 165

  
128 166
  debug("Protocol start\n");
129
  WALK_LIST_DELSAFE(p, n, inactive_proto_list)
130
    {
131
      debug("Starting %s\n", p->cf->name);
132
      proto_start(p);
133
    }
167
  WALK_LIST_DELSAFE(p, n, initial_proto_list)
168
    proto_set_goal(p, FS_HAPPY);
134 169
}
135 170

  
136 171
void
137 172
protos_dump_all(void)
138 173
{
139 174
  struct proto *p;
140
  static char *p_states[] = { "DOWN", "START", "UP", "STOP" };
141
  static char *c_states[] = { "HUNGRY", "FEEDING", "HAPPY", "FLUSHING" };
142 175

  
143 176
  debug("Protocols:\n");
144 177

  
145 178
  WALK_LIST(p, proto_list)
146 179
    {
147
      debug("  protocol %s: state %s/%s\n", p->cf->name, p_states[p->proto_state], c_states[p->core_state]);
180
      debug("  protocol %s: state %s/%s\n", p->name, p_states[p->proto_state], c_states[p->core_state]);
148 181
      if (p->disabled)
149 182
	debug("\tDISABLED\n");
150 183
      else if (p->proto->dump)
151 184
	p->proto->dump(p);
152 185
    }
153 186
  WALK_LIST(p, inactive_proto_list)
154
    debug("  inactive %s\n", p->cf->name);
187
    debug("  inactive %s: state %s/%s\n", p->name, p_states[p->proto_state], c_states[p->core_state]);
188
  WALK_LIST(p, initial_proto_list)
189
    debug("  initial %s\n", p->name);
155 190
}
156 191

  
157 192
void
......
165 200
#ifdef CONFIG_STATIC
166 201
  add_tail(&protocol_list, &proto_static.n);
167 202
#endif
203
  proto_pool = rp_new(&root_pool, "Protocols");
204
}
205

  
206
static void
207
proto_fell_down(struct proto *p)
208
{
209
  DBG("Protocol %s down\n", p->name);
210
  proto_rethink_goal(p);
211
}
212

  
213
static void
214
proto_feed(void *P)
215
{
216
  struct proto *p = P;
217

  
218
  DBG("Feeding protocol %s\n", p->name);
219
  if_feed_baby(p);
220
  rt_feed_baby(p);
221
  p->core_state = FS_HAPPY;
222
  proto_relink(p);
223
  DBG("Protocol %s up and running\n", p->name);
224
}
225

  
226
static void
227
proto_flush(void *P)
228
{
229
  struct proto *p = P;
230

  
231
  DBG("Flushing protocol %s\n", p->name);
232
  bug("Protocol flushing not supported yet!"); /* FIXME */
233
}
234

  
235
void
236
proto_notify_state(struct proto *p, unsigned ps)
237
{
238
  unsigned ops = p->proto_state;
239
  unsigned cs = p->core_state;
240

  
241
  DBG("%s reporting state transition %s/%s -> */%s\n", p->name, c_states[cs], p_states[ops], p_states[ps]);
242
  if (ops == ps)
243
    return;
244

  
245
  switch (ps)
246
    {
247
    case PS_DOWN:
248
      if (cs == FS_HUNGRY)		/* Shutdown finished */
249
	proto_fell_down(p);
250
      else if (cs == FS_FLUSHING)	/* Still flushing... */
251
	;
252
      else				/* Need to start flushing */
253
	goto schedule_flush;
254
      break;
255
    case PS_START:
256
      ASSERT(ops == PS_DOWN);
257
      ASSERT(cs == FS_HUNGRY);
258
      break;
259
    case PS_UP:
260
      ASSERT(ops == PS_DOWN || ops == PS_START);
261
      ASSERT(cs == FS_HUNGRY);
262
      DBG("%s: Scheduling meal\n", p->name);
263
      cs = FS_FEEDING;
264
      p->attn->hook = proto_feed;
265
      ev_schedule(p->attn);
266
      break;
267
    case PS_STOP:
268
      if (cs == FS_FEEDING || cs == FS_HAPPY)
269
	{
270
	schedule_flush:
271
	  DBG("%s: Scheduling flush\n", p->name);
272
	  cs = FS_FLUSHING;
273
	  p->attn->hook = proto_flush;
274
	  ev_schedule(p->attn);
275
	}
276
    default:
277
    error:
278
      bug("Invalid state transition for %s from %s/%s to */%s", p->name, c_states[cs], p_states[ops], p_states[ps]);
279
    }
280
  p->proto_state = ps;
281
  p->core_state = cs;
282
  proto_relink(p);
168 283
}

Also available in: Unified diff