Annotation of embedaddon/bird/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->port == y->port &&
49: x->inst == y->inst &&
50: ipa_equal(x->addr, y->addr);
51: }
52:
53: static void
54: olock_free(resource *r)
55: {
56: struct object_lock *q, *l = (struct object_lock *) r;
57: node *n;
58:
59: DBG("olock: Freeing %p\n", l);
60: switch (l->state)
61: {
62: case OLOCK_STATE_FREE:
63: break;
64: case OLOCK_STATE_LOCKED:
65: case OLOCK_STATE_EVENT:
66: rem_node(&l->n);
67: n = HEAD(l->waiters);
68: if (n->next)
69: {
70: DBG("olock: -> %p becomes locked\n", n);
71: q = SKIP_BACK(struct object_lock, n, n);
72: rem_node(n);
73: add_tail_list(&q->waiters, &l->waiters);
74: q->state = OLOCK_STATE_EVENT;
75: add_head(&olock_list, n);
76: ev_schedule(olock_event);
77: }
78: break;
79: case OLOCK_STATE_WAITING:
80: rem_node(&l->n);
81: break;
82: default:
83: ASSERT(0);
84: }
85: }
86:
87: static void
88: olock_dump(resource *r)
89: {
90: struct object_lock *l = (struct object_lock *) r;
91: static char *olock_states[] = { "free", "locked", "waiting", "event" };
92:
93: 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]);
94: if (!EMPTY_LIST(l->waiters))
95: debug(" [wanted]\n");
96: }
97:
98: static struct resclass olock_class = {
99: "ObjLock",
100: sizeof(struct object_lock),
101: olock_free,
102: olock_dump,
103: NULL,
104: NULL,
105: };
106:
107: /**
108: * olock_new - create an object lock
109: * @p: resource pool to create the lock in.
110: *
111: * The olock_new() function creates a new resource of type &object_lock
112: * and returns a pointer to it. After filling in the structure, the caller
113: * should call olock_acquire() to do the real locking.
114: */
115: struct object_lock *
116: olock_new(pool *p)
117: {
118: struct object_lock *l = ralloc(p, &olock_class);
119:
120: l->state = OLOCK_STATE_FREE;
121: init_list(&l->waiters);
122: return l;
123: }
124:
125: /**
126: * olock_acquire - acquire a lock
127: * @l: the lock to acquire
128: *
129: * This function attempts to acquire exclusive access to the non-shareable
130: * resource described by the lock @l. It returns immediately, but as soon
131: * as the resource becomes available, it calls the hook() function set up
132: * by the caller.
133: *
134: * When you want to release the resource, just rfree() the lock.
135: */
136: void
137: olock_acquire(struct object_lock *l)
138: {
139: node *n;
140: struct object_lock *q;
141:
142: WALK_LIST(n, olock_list)
143: {
144: q = SKIP_BACK(struct object_lock, n, n);
145: if (olock_same(q, l))
146: {
147: l->state = OLOCK_STATE_WAITING;
148: add_tail(&q->waiters, &l->n);
149: DBG("olock: %p waits\n", l);
150: return;
151: }
152: }
153: DBG("olock: %p acquired immediately\n", l);
154: l->state = OLOCK_STATE_EVENT;
155: add_head(&olock_list, &l->n);
156: ev_schedule(olock_event);
157: }
158:
159: static void
160: olock_run_event(void *unused UNUSED)
161: {
162: node *n;
163: struct object_lock *q;
164:
165: DBG("olock: Processing events\n");
166: for(;;)
167: {
168: n = HEAD(olock_list);
169: if (!n->next)
170: break;
171: q = SKIP_BACK(struct object_lock, n, n);
172: if (q->state != OLOCK_STATE_EVENT)
173: break;
174: DBG("olock: %p locked\n", q);
175: q->state = OLOCK_STATE_LOCKED;
176: rem_node(&q->n);
177: add_tail(&olock_list, &q->n);
178: q->hook(q);
179: }
180: }
181:
182: /**
183: * olock_init - initialize the object lock mechanism
184: *
185: * This function is called during BIRD startup. It initializes
186: * all the internal data structures of the lock module.
187: */
188: void
189: olock_init(void)
190: {
191: DBG("olock: init\n");
192: init_list(&olock_list);
193: olock_event = ev_new(&root_pool);
194: olock_event->hook = olock_run_event;
195: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>