Annotation of embedaddon/bird2/nest/locks.c, revision 1.1.1.1
1.1 misho 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_init(&root_pool, olock_run_event, NULL);
195: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>