Annotation of embedaddon/bird/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->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>