]>
git.ipfire.org Git - thirdparty/bird.git/blob - nest/locks.c
4 * (c) 1999 Martin Mares <mj@ucw.cz>
6 * Can be freely distributed and used under the terms of the GNU GPL.
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.
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.
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
34 #include "nest/bird.h"
35 #include "lib/resource.h"
36 #include "nest/locks.h"
37 #include "nest/iface.h"
39 static list olock_list
;
40 static event
*olock_event
;
43 olock_same(struct object_lock
*x
, struct object_lock
*y
)
47 x
->iface
== y
->iface
&&
51 ipa_equal(x
->addr
, y
->addr
) &&
52 ipa_equal_wildcard(x
->addr_local
, y
->addr_local
);
56 olock_free(resource
*r
)
58 struct object_lock
*q
, *l
= (struct object_lock
*) r
;
61 DBG("olock: Freeing %p\n", l
);
64 case OLOCK_STATE_FREE
:
66 case OLOCK_STATE_LOCKED
:
67 case OLOCK_STATE_EVENT
:
72 DBG("olock: -> %p becomes locked\n", n
);
73 q
= SKIP_BACK(struct object_lock
, n
, n
);
75 add_tail_list(&q
->waiters
, &l
->waiters
);
76 q
->state
= OLOCK_STATE_EVENT
;
77 add_head(&olock_list
, n
);
78 ev_schedule(olock_event
);
81 case OLOCK_STATE_WAITING
:
90 olock_dump(resource
*r
)
92 struct object_lock
*l
= (struct object_lock
*) r
;
93 static char *olock_states
[] = { "free", "locked", "waiting", "event" };
95 debug("(%d:%s:%I:%I:%d:%d) [%s]\n", l
->type
, (l
->iface
? l
->iface
->name
: "?"), l
->addr
, l
->addr_local
, l
->port
, l
->inst
, olock_states
[l
->state
]);
96 if (!EMPTY_LIST(l
->waiters
))
100 static struct resclass olock_class
= {
102 sizeof(struct object_lock
),
110 * olock_new - create an object lock
111 * @p: resource pool to create the lock in.
113 * The olock_new() function creates a new resource of type &object_lock
114 * and returns a pointer to it. After filling in the structure, the caller
115 * should call olock_acquire() to do the real locking.
120 struct object_lock
*l
= ralloc(p
, &olock_class
);
122 l
->state
= OLOCK_STATE_FREE
;
123 init_list(&l
->waiters
);
128 * olock_acquire - acquire a lock
129 * @l: the lock to acquire
131 * This function attempts to acquire exclusive access to the non-shareable
132 * resource described by the lock @l. It returns immediately, but as soon
133 * as the resource becomes available, it calls the hook() function set up
136 * When you want to release the resource, just rfree() the lock.
139 olock_acquire(struct object_lock
*l
)
142 struct object_lock
*q
;
144 WALK_LIST(n
, olock_list
)
146 q
= SKIP_BACK(struct object_lock
, n
, n
);
147 if (olock_same(q
, l
))
149 l
->state
= OLOCK_STATE_WAITING
;
150 add_tail(&q
->waiters
, &l
->n
);
151 DBG("olock: %p waits\n", l
);
155 DBG("olock: %p acquired immediately\n", l
);
156 l
->state
= OLOCK_STATE_EVENT
;
157 add_head(&olock_list
, &l
->n
);
158 ev_schedule(olock_event
);
162 olock_run_event(void *unused UNUSED
)
165 struct object_lock
*q
;
167 DBG("olock: Processing events\n");
170 n
= HEAD(olock_list
);
173 q
= SKIP_BACK(struct object_lock
, n
, n
);
174 if (q
->state
!= OLOCK_STATE_EVENT
)
176 DBG("olock: %p locked\n", q
);
177 q
->state
= OLOCK_STATE_LOCKED
;
179 add_tail(&olock_list
, &q
->n
);
185 * olock_init - initialize the object lock mechanism
187 * This function is called during BIRD startup. It initializes
188 * all the internal data structures of the lock module.
193 DBG("olock: init\n");
194 init_list(&olock_list
);
195 olock_event
= ev_new_init(&root_pool
, olock_run_event
, NULL
);