Statistics
| Branch: | Revision:

iof-bird / bird-2.0.1 / nest / locks.c @ 6b3f1a54

History | View | Annotate | Download (4.91 KB)

1
/*
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
/**
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
 * for a short time period only) an old protocol instance being shut down and a new one
19
 * 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
 * or some other non-shareable resource, it asks the core to lock it and it doesn't
23
 * use the resource until it's notified that it has acquired the lock.
24
 *
25
 * Object locks are represented by &object_lock structures which are in turn a
26
 * kind of 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, interface and optional
29
 * instance ID.
30
 */
31

    
32
#undef LOCAL_DEBUG
33

    
34
#include "nest/bird.h"
35
#include "lib/resource.h"
36
#include "nest/locks.h"
37
#include "nest/iface.h"
38

    
39
static list olock_list;
40
static event *olock_event;
41

    
42
static inline int
43
olock_same(struct object_lock *x, struct object_lock *y)
44
{
45
  return
46
    x->type == y->type &&
47
    x->iface == y->iface &&
48
    x->vrf == y->vrf &&
49
    x->port == y->port &&
50
    x->inst == y->inst &&
51
    ipa_equal(x->addr, y->addr);
52
}
53

    
54
static void
55
olock_free(resource *r)
56
{
57
  struct object_lock *q, *l = (struct object_lock *) r;
58
  node *n;
59

    
60
  DBG("olock: Freeing %p\n", l);
61
  switch (l->state)
62
    {
63
    case OLOCK_STATE_FREE:
64
      break;
65
    case OLOCK_STATE_LOCKED:
66
    case OLOCK_STATE_EVENT:
67
      rem_node(&l->n);
68
      n = HEAD(l->waiters);
69
      if (n->next)
70
        {
71
          DBG("olock: -> %p becomes locked\n", n);
72
          q = SKIP_BACK(struct object_lock, n, n);
73
          rem_node(n);
74
          add_tail_list(&q->waiters, &l->waiters);
75
          q->state = OLOCK_STATE_EVENT;
76
          add_head(&olock_list, n);
77
          ev_schedule(olock_event);
78
        }
79
      break;
80
    case OLOCK_STATE_WAITING:
81
      rem_node(&l->n);
82
      break;
83
    default:
84
      ASSERT(0);
85
    }
86
}
87

    
88
static void
89
olock_dump(resource *r)
90
{
91
  struct object_lock *l = (struct object_lock *) r;
92
  static char *olock_states[] = { "free", "locked", "waiting", "event" };
93

    
94
  debug("(%d:%s:%I:%d:%d) [%s]\n", l->type, (l->iface ? l->iface->name : "?"), l->addr, l->port, l->inst, olock_states[l->state]);
95
  if (!EMPTY_LIST(l->waiters))
96
    debug(" [wanted]\n");
97
}
98

    
99
static struct resclass olock_class = {
100
  "ObjLock",
101
  sizeof(struct object_lock),
102
  olock_free,
103
  olock_dump,
104
  NULL,
105
  NULL,
106
};
107

    
108
/**
109
 * olock_new - create an object lock
110
 * @p: resource pool to create the lock in.
111
 *
112
 * The olock_new() function creates a new resource of type &object_lock
113
 * and returns a pointer to it. After filling in the structure, the caller
114
 * should call olock_acquire() to do the real locking.
115
 */
116
struct object_lock *
117
olock_new(pool *p)
118
{
119
  struct object_lock *l = ralloc(p, &olock_class);
120

    
121
  l->state = OLOCK_STATE_FREE;
122
  init_list(&l->waiters);
123
  return l;
124
}
125

    
126
/**
127
 * olock_acquire - acquire a lock
128
 * @l: the lock to acquire
129
 *
130
 * This function attempts to acquire exclusive access to the non-shareable
131
 * resource described by the lock @l. It returns immediately, but as soon
132
 * as the resource becomes available, it calls the hook() function set up
133
 * by the caller.
134
 *
135
 * When you want to release the resource, just rfree() the lock.
136
 */
137
void
138
olock_acquire(struct object_lock *l)
139
{
140
  node *n;
141
  struct object_lock *q;
142

    
143
  WALK_LIST(n, olock_list)
144
    {
145
      q = SKIP_BACK(struct object_lock, n, n);
146
      if (olock_same(q, l))
147
        {
148
          l->state = OLOCK_STATE_WAITING;
149
          add_tail(&q->waiters, &l->n);
150
          DBG("olock: %p waits\n", l);
151
          return;
152
        }
153
    }
154
  DBG("olock: %p acquired immediately\n", l);
155
  l->state = OLOCK_STATE_EVENT;
156
  add_head(&olock_list, &l->n);
157
  ev_schedule(olock_event);
158
}
159

    
160
static void
161
olock_run_event(void *unused UNUSED)
162
{
163
  node *n;
164
  struct object_lock *q;
165

    
166
  DBG("olock: Processing events\n");
167
  for(;;)
168
    {
169
      n = HEAD(olock_list);
170
      if (!n->next)
171
        break;
172
      q = SKIP_BACK(struct object_lock, n, n);
173
      if (q->state != OLOCK_STATE_EVENT)
174
        break;
175
      DBG("olock: %p locked\n", q);
176
      q->state = OLOCK_STATE_LOCKED;
177
      rem_node(&q->n);
178
      add_tail(&olock_list, &q->n);
179
      q->hook(q);
180
    }
181
}
182

    
183
/**
184
 * olock_init - initialize the object lock mechanism
185
 *
186
 * This function is called during BIRD startup. It initializes
187
 * all the internal data structures of the lock module.
188
 */
189
void
190
olock_init(void)
191
{
192
  DBG("olock: init\n");
193
  init_list(&olock_list);
194
  olock_event = ev_new(&root_pool);
195
  olock_event->hook = olock_run_event;
196
}