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