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>