Locking Rules for LWIO

These rules are about locking and referencing/dereferencing objects in LWIO.

Terminology:
- P = parent object.
- C = child object.
- O = some object.

1) Any parent and/or child object must have a reference count.

2) Any object that can be a child must have a parent pointer.

3) If acquiring more than one object, the ordering is from leaf object up
   towards the root.

Algorighms for common operations:

A. Referencing an object:

ReferenceObject(O)
{
    return InterlockedIncrement(&O->RefCount);
}

B. Looking up a parent's child:

FindChild(P, Key)
{
    Lock(P)
    C = { Lookup child of P using Key }
    ReferenceObject(C)
    Unlock(P)
    return C
}

C. Dereferencing an object that can have a parent:

DereferenceObject(O)
{
    count = InterlockedDecrerement(&O->RefCount);
    if (count == 0)
    {
        parent = O->P
        if (parent)
        {
            ReferenceObject(parent)
            Lock(parent)
            count = InterlockedGet(&O->RefCount)
        }
        if (count == 0)
        {
            /* This will dereference the parent once */
            DestroyObject(O)
        }
        if (parent)
        {
            Unlock(parent)
            /* This will destroy the parent if this was the last reference */
            DereferenceObject(parent)
        }
    }
    return count
}

DestroyObject(O)
{
   if (O->P)
   {
      RemoveChild(P, O)
      DereferenceObject(O->P)
      O->P = NULL
   }
   ... free object ...
}


C.2. Dereferencing an object that cannot have a parent:

DereferenceObject(O)
{
    count = InterlockedDecrerement(&O->RefCount);
    if (count == 0)
    {
        DestroyObject(O)
    }
    return count
}


IMPORTANT:
---------

The fallout of this is that we need recurive locks on any object that can be a parent.
