Statistics
| Branch: | Revision:

iof-bird-daemon / nest / locks.c @ fbde6c39

History | View | Annotate | Download (4.81 KB)

1 f545d387 Martin Mares
/*
2
 *        BIRD Object Locks
3
 *
4
 *        (c) 1999 Martin Mares <mj@ucw.cz>
5
 *
6
 *        Can be freely distributed and used under the terms of the GNU GPL.
7
 */
8
9 1f495723 Martin Mares
/**
10
 * DOC: Object locks
11
 *
12
 * The lock module provides a simple mechanism for avoiding conflicts between
13
 * various protocols which would like to use a single physical resource (for
14
 * example a network port). It would be easy to say that such collisions can
15
 * occur only when the user specifies an invalid configuration and therefore
16
 * he deserves to get what he has asked for, but unfortunately they can also
17
 * arise legitimately when the daemon is reconfigured and there exists (although
18 58f7d004 Martin Mares
 * for a short time period only) an old protocol instance being shut down and a new one
19 1f495723 Martin Mares
 * willing to start up on the same interface.
20
 *
21
 * The solution is very simple: when any protocol wishes to use a network port
22 58f7d004 Martin Mares
 * or some other non-shareable resource, it asks the core to lock it and it doesn't
23 1f495723 Martin Mares
 * use the resource until it's notified that it has acquired the lock.
24
 *
25 58f7d004 Martin Mares
 * Object locks are represented by &object_lock structures which are in turn a kind of
26 1f495723 Martin Mares
 * resource. Lockable resources are uniquely determined by resource type
27
 * (%OBJLOCK_UDP for a UDP port etc.), IP address (usually a broadcast or
28
 * multicast address the port is bound to), port number and interface.
29
 */
30
31 1d9622e1 Martin Mares
#undef LOCAL_DEBUG
32 f545d387 Martin Mares
33
#include "nest/bird.h"
34
#include "lib/resource.h"
35
#include "nest/locks.h"
36
#include "nest/iface.h"
37
38
static list olock_list;
39
static event *olock_event;
40
41
static inline int
42
olock_same(struct object_lock *x, struct object_lock *y)
43
{
44
  return
45
    x->type == y->type &&
46
    x->iface == y->iface &&
47
    x->port == y->port &&
48
    ipa_equal(x->addr, y->addr);
49
}
50
51
static void
52
olock_free(resource *r)
53
{
54
  struct object_lock *q, *l = (struct object_lock *) r;
55
  node *n;
56
57
  DBG("olock: Freeing %p\n", l);
58
  switch (l->state)
59
    {
60
    case OLOCK_STATE_FREE:
61
      break;
62
    case OLOCK_STATE_LOCKED:
63
    case OLOCK_STATE_EVENT:
64
      rem_node(&l->n);
65
      n = HEAD(l->waiters);
66
      if (n->next)
67
        {
68
          DBG("olock: -> %p becomes locked\n", n);
69
          q = SKIP_BACK(struct object_lock, n, n);
70
          rem_node(n);
71
          add_tail_list(&l->waiters, &q->waiters);
72
          q->state = OLOCK_STATE_EVENT;
73
          add_head(&olock_list, n);
74
          ev_schedule(olock_event);
75
        }
76
      break;
77
    case OLOCK_STATE_WAITING:
78
      rem_node(&l->n);
79
      break;
80
    default:
81
      ASSERT(0);
82
    }
83
}
84
85
static void
86
olock_dump(resource *r)
87
{
88
  struct object_lock *l = (struct object_lock *) r;
89
  static char *olock_states[] = { "free", "locked", "waiting", "event" };
90
91 267a2c0e Martin Mares
  debug("(%d:%s:%I:%d) [%s]\n", l->type, (l->iface ? l->iface->name : "?"), l->addr, l->port, olock_states[l->state]);
92 f545d387 Martin Mares
  if (!EMPTY_LIST(l->waiters))
93
    debug(" [wanted]\n");
94
}
95
96
static struct resclass olock_class = {
97
  "ObjLock",
98
  sizeof(struct object_lock),
99
  olock_free,
100
  olock_dump
101
};
102
103 1f495723 Martin Mares
/**
104
 * olock_new - create an object lock
105
 * @p: resource pool to create the lock in.
106
 *
107
 * The olock_new() function creates a new resource of type &object_lock
108
 * and returns a pointer to it. After filling in the structure, the caller
109
 * should call olock_acquire() to do the real locking.
110
 */
111 f545d387 Martin Mares
struct object_lock *
112
olock_new(pool *p)
113
{
114
  struct object_lock *l = ralloc(p, &olock_class);
115
116
  l->state = OLOCK_STATE_FREE;
117
  init_list(&l->waiters);
118
  return l;
119
}
120
121 1f495723 Martin Mares
/**
122
 * olock_acquire - acquire a lock
123
 * @l: the lock to acquire
124
 *
125
 * This function attempts to acquire exclusive access to the non-shareable
126
 * resource described by the lock @l. It returns immediately, but as soon
127
 * as the resource becomes available, it calls the hook() function set up
128
 * by the caller.
129
 *
130
 * When you want to release the resource, just rfree() the lock.
131
 */
132 f545d387 Martin Mares
void
133
olock_acquire(struct object_lock *l)
134
{
135
  node *n;
136
  struct object_lock *q;
137
138
  WALK_LIST(n, olock_list)
139
    {
140
      q = SKIP_BACK(struct object_lock, n, n);
141
      if (olock_same(q, l))
142
        {
143
          l->state = OLOCK_STATE_WAITING;
144
          add_tail(&q->waiters, &l->n);
145
          DBG("olock: %p waits\n", l);
146
          return;
147
        }
148
    }
149
  DBG("olock: %p acquired immediately\n", l);
150
  l->state = OLOCK_STATE_EVENT;
151
  add_head(&olock_list, &l->n);
152
  ev_schedule(olock_event);
153
}
154
155 8f6accb5 Martin Mares
static void
156 7c103b1e Martin Mares
olock_run_event(void *unused UNUSED)
157 f545d387 Martin Mares
{
158
  node *n;
159
  struct object_lock *q;
160
161
  DBG("olock: Processing events\n");
162
  for(;;)
163
    {
164
      n = HEAD(olock_list);
165
      if (!n->next)
166
        break;
167
      q = SKIP_BACK(struct object_lock, n, n);
168
      if (q->state != OLOCK_STATE_EVENT)
169
        break;
170
      DBG("olock: %p locked\n", q);
171
      q->state = OLOCK_STATE_LOCKED;
172
      rem_node(&q->n);
173
      add_tail(&olock_list, &q->n);
174
      q->hook(q);
175
    }
176
}
177
178 1f495723 Martin Mares
/**
179
 * olock_init - initialize the object lock mechanism
180
 *
181
 * This function is called during BIRD startup. It initializes
182
 * all the internal data structures of the lock module.
183
 */
184 f545d387 Martin Mares
void
185
olock_init(void)
186
{
187
  DBG("olock: init\n");
188
  init_list(&olock_list);
189
  olock_event = ev_new(&root_pool);
190
  olock_event->hook = olock_run_event;
191
}