Re: Introducing "toggle references"



Ok, I have a better idea.
What if we use the toggle references in the other way.

The situation would generally look like this:

                      +---------+
                      | Other   |
		      | GObject |
		      +---------+
                           |
			   |
			   V
    +---------+       +---------+       +---------+
    | Proxy A |<------| GObject |------>| Proxy B |
    |         |------>|         |<------|         |
    +---------+       +---------+       +---------+
        ^                                   ^      
        |                                   |      
    +---------+				+---------+
    | Other A |				| Other B |
    | object  |				| object  |
    +---------+				+---------+

However, when the last reference to the Proxy exept the GObject
reference is gone, we convert the Gobject reference to a weak one:

                      +---------+
                      | Other   |
		      | GObject |
		      +---------+
                           |
			   |
			   V
    +---------+       +---------+       +---------+
    | Proxy A |<------| GObject |------>| Proxy B |
    |         |------>|         |<......|         |
    +---------+       +---------+       +---------+
        ^                                
        |                               
    +---------+				
    | Other A |				
    | object  |				
    +---------+				    

This means the Proxies will not die until the GObject dies, and
the proxy won't keep the GObject alive unless something references
them. Just what we want. The problem is of course implementing the
toggle-reference for the Language runtime (its easy in the GObject
runtime, because we can just hack the runtime).

I think I have a solution that should work in general. What you do is
split up the Proxy into two objects, one keeping all the data for the
proxy, and the other one is just a facade that you give out to other
objects to use as a reference. The Proxy Data object knows about the
facade object, but only through a weak reference, so when the facade
is not referenced anymore we'll get told, and we can change our
reference on the GObject from a strong to a weak ref.

In this situation Proxy A has a reference, but Proxy B not:

    +---------+       +---------+       +---------+
    | Proxy A |<------| GObject |------>| Proxy B |
    | Data    |------>|         |<......|         |
    +---------+       +---------+       +---------+
        ^ .                             
        | .                             
        | V                             
    +---------+				
    | Proxy A |				
    | Facade  |				
    +---------+				
        ^                                
        |                               
    +---------+				
    | Other A |				
    | object  |				
    +---------+				    


The implementation in Java would be something like:
(Note: this example is not threadsafe)

static Hashtable gobjectHash; /* Long -> GObjectProxy */

static GObjectFacade lookupGObject(Long gobject) {
  GObjectProxy proxy = gobjectHash.get(gobject);
  if (proxy == null) {
    proxy = new GObjectProxy(gobject);
  }
  return proxy.getFacade();
}

void gobject_died(Long gobject, GObjectProxy proxy) {
  /* facade should be null here */
  gobjectHash.remove(gobject);
}

class GObjectProxy {
  WeakReference facade;
  Long gobject       ;
  HashTable data; /* whatever data you want to store in the proxy */

  GObjectProxy(Long gobject) {
    this.gobject = gobject;
    data = new HashTable();
    
    gobjectHash.put(gobject, proxy);
    g_object_weak_ref(gobject, gobject_died, this);
  }
  
  clearFacace() {
    facade = null;
    g_object_weak_ref(gobject, gobject_died, this);
    g_object_unref(gobject);
  }

  GObjectFacade getFacade() {
    if (facade == null) {
      GObjectFacade facade = new GObjectFacade(this);
      facade = WeakReference(facade);
      g_object_ref(gobject);
      g_object_weak_unref(gobject, gobject_died, this);
    }
    return facade.get();
  }
}

class GObjectFacade {
  GObjectProxy proxy;

  Object getData(String attr) {
    return proxy.data.get(attr);
  }

  void finalize() {
    proxy.clearFacade();
  }
}

There is a disadvantage of course, we use two objects per proxy
instead of one, and we do one extra dereference to get to the proxy
data. We also do one extra dereference to get to the gobject pointer,
but at the cost of some memory that could be optimized by also storing
the gobject pointer in the facade.

Of course, as an optimization, data-less proxies can just be handled
by a weak reference from the GObject.

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 Alexander Larsson                                            Red Hat, Inc 
                   alexl redhat com    alla lysator liu se 
He's a jaded vegetarian boxer moving from town to town, helping folk in 
trouble. She's a supernatural green-skinned bounty hunter from a family of 
eight older brothers. They fight crime! 




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]