]>
Commit | Line | Data |
---|---|---|
f545d387 MM |
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 | #include <stdio.h> | |
10 | ||
11 | #define LOCAL_DEBUG | |
12 | ||
13 | #include "nest/bird.h" | |
14 | #include "lib/resource.h" | |
15 | #include "nest/locks.h" | |
16 | #include "nest/iface.h" | |
17 | ||
18 | static list olock_list; | |
19 | static event *olock_event; | |
20 | ||
21 | static inline int | |
22 | olock_same(struct object_lock *x, struct object_lock *y) | |
23 | { | |
24 | return | |
25 | x->type == y->type && | |
26 | x->iface == y->iface && | |
27 | x->port == y->port && | |
28 | ipa_equal(x->addr, y->addr); | |
29 | } | |
30 | ||
31 | static void | |
32 | olock_free(resource *r) | |
33 | { | |
34 | struct object_lock *q, *l = (struct object_lock *) r; | |
35 | node *n; | |
36 | ||
37 | DBG("olock: Freeing %p\n", l); | |
38 | switch (l->state) | |
39 | { | |
40 | case OLOCK_STATE_FREE: | |
41 | break; | |
42 | case OLOCK_STATE_LOCKED: | |
43 | case OLOCK_STATE_EVENT: | |
44 | rem_node(&l->n); | |
45 | n = HEAD(l->waiters); | |
46 | if (n->next) | |
47 | { | |
48 | DBG("olock: -> %p becomes locked\n", n); | |
49 | q = SKIP_BACK(struct object_lock, n, n); | |
50 | rem_node(n); | |
51 | add_tail_list(&l->waiters, &q->waiters); | |
52 | q->state = OLOCK_STATE_EVENT; | |
53 | add_head(&olock_list, n); | |
54 | ev_schedule(olock_event); | |
55 | } | |
56 | break; | |
57 | case OLOCK_STATE_WAITING: | |
58 | rem_node(&l->n); | |
59 | break; | |
60 | default: | |
61 | ASSERT(0); | |
62 | } | |
63 | } | |
64 | ||
65 | static void | |
66 | olock_dump(resource *r) | |
67 | { | |
68 | struct object_lock *l = (struct object_lock *) r; | |
69 | static char *olock_states[] = { "free", "locked", "waiting", "event" }; | |
70 | ||
267a2c0e | 71 | debug("(%d:%s:%I:%d) [%s]\n", l->type, (l->iface ? l->iface->name : "?"), l->addr, l->port, olock_states[l->state]); |
f545d387 MM |
72 | if (!EMPTY_LIST(l->waiters)) |
73 | debug(" [wanted]\n"); | |
74 | } | |
75 | ||
76 | static struct resclass olock_class = { | |
77 | "ObjLock", | |
78 | sizeof(struct object_lock), | |
79 | olock_free, | |
80 | olock_dump | |
81 | }; | |
82 | ||
83 | struct object_lock * | |
84 | olock_new(pool *p) | |
85 | { | |
86 | struct object_lock *l = ralloc(p, &olock_class); | |
87 | ||
88 | l->state = OLOCK_STATE_FREE; | |
89 | init_list(&l->waiters); | |
90 | return l; | |
91 | } | |
92 | ||
93 | void | |
94 | olock_acquire(struct object_lock *l) | |
95 | { | |
96 | node *n; | |
97 | struct object_lock *q; | |
98 | ||
99 | WALK_LIST(n, olock_list) | |
100 | { | |
101 | q = SKIP_BACK(struct object_lock, n, n); | |
102 | if (olock_same(q, l)) | |
103 | { | |
104 | l->state = OLOCK_STATE_WAITING; | |
105 | add_tail(&q->waiters, &l->n); | |
106 | DBG("olock: %p waits\n", l); | |
107 | return; | |
108 | } | |
109 | } | |
110 | DBG("olock: %p acquired immediately\n", l); | |
111 | l->state = OLOCK_STATE_EVENT; | |
112 | add_head(&olock_list, &l->n); | |
113 | ev_schedule(olock_event); | |
114 | } | |
115 | ||
116 | int | |
117 | olock_run_event(void *unused) | |
118 | { | |
119 | node *n; | |
120 | struct object_lock *q; | |
121 | ||
122 | DBG("olock: Processing events\n"); | |
123 | for(;;) | |
124 | { | |
125 | n = HEAD(olock_list); | |
126 | if (!n->next) | |
127 | break; | |
128 | q = SKIP_BACK(struct object_lock, n, n); | |
129 | if (q->state != OLOCK_STATE_EVENT) | |
130 | break; | |
131 | DBG("olock: %p locked\n", q); | |
132 | q->state = OLOCK_STATE_LOCKED; | |
133 | rem_node(&q->n); | |
134 | add_tail(&olock_list, &q->n); | |
135 | q->hook(q); | |
136 | } | |
137 | return 0; | |
138 | } | |
139 | ||
140 | void | |
141 | olock_init(void) | |
142 | { | |
143 | DBG("olock: init\n"); | |
144 | init_list(&olock_list); | |
145 | olock_event = ev_new(&root_pool); | |
146 | olock_event->hook = olock_run_event; | |
147 | } |