Annotation of embedaddon/bird2/nest/locks.c, revision 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>