File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / bird / nest / locks.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 19:50:23 2021 UTC (3 years, 3 months ago) by misho
Branches: bird, MAIN
CVS tags: v1_6_8p3, HEAD
bird 1.6.8

    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(&root_pool);
  195:   olock_event->hook = olock_run_event;
  196: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>