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