[Asterisk-code-review] ao2 container: Add support for transparent storage of weakpr... (asterisk[master])
Corey Farrell
asteriskteam at digium.com
Fri Sep 9 09:22:58 CDT 2016
Corey Farrell has posted comments on this change.
Change subject: ao2_container: Add support for transparent storage of weakproxy objects.
......................................................................
Patch Set 2:
Thank you for your advice Richard, hopefully I'll be able to address most of this in the next week.
> > Questions/Concerns:
> > 1) The need to check ao2_weakproxy_ref_object() in the
> > named_locks_cmp is ugly. I'd love if this could just be handled
> by
> > internal_ao2_traverse, but I'm not sure a good way to abort
> > CMP_MATCH in the case where weakproxy has no object.
>
> The callback should not do the check because you are lying to the
> container
> and the check code is generic anyway. To ignore the CMP_MATCH in
> the
> container traversal code you just need to continue to the next
> iteration
> after finding out that the object is empty. The traversal code
> would need
> to determine if this is intended to unlink the specific weak proxy
> object
> though. i.e., We meant to find the weak proxy object to remove it
> from
> the container because the real object got destroyed.
Understood.
> An alternate view is that if you found an empty proxy object then
> there
> isn't a real object to be found even if you ignored the empty
> proxy.
Locking order can cause the old object to still exist after a new one is linked. Flow:
Thread 1: acquire container lock in ast_named_lock_get
Thread 2: blocked for container lock in ast_named_lock_get
Thread 3: last reference to named lock "aor/alice" released, node_obj_proxy_cb blocks at ao2_unlink.
Thread 1: ao2_find returns NULL, create and link new named_lock "aor/alice". release container lock.
Thread 2: container lock acquired, ao2_find traversal order finds old "aor/alice" first but must skip.
> > 2) Do we want this to be an alloc option, or flags given to
> > ao2_link, ao2_find and ao2_callback?
>
> I think this should be a container option flag at container
> allocation
> time as you have already started. The container callback functions
> would
> deal with the proxy object. The container will be given normal ao2
> objects and return normal ao2 objects just like a normal container.
> The
> difference being that the container would not hold a reference to
> the ao2
> object. The only caveat would be that the stored ao2 objects must
> already
> have an associated proxy object. The container would handle the
> weak
> proxy subscribe/unsubscribe and the subscribe notification callback
> would
> need to be an internal unlink function. The container code would
> need to
> check the option flag when it needs to do weak proxy actions.
So ao2_link/ao2_unlink would take the real object for it's parameter. I feel like the weakproxy object (or at least the struct type) should normally be used as 'arg' for ao2_find/ao2_callback when OBJ_POINTER / OBJ_SEARCH_OBJECT are used?
It was already intentional that weakproxy containers would not (can not) accept unassociated objects. In the reverse direction if we were giving the weakproxy to ao2_link this would cause ao2_weakproxy_subscribe to run the callback immediately.
> Some thought is needed to determine if weak containers can support
> AO2_ALLOC_OPT_LOCK_RWLOCK. There might be a reentrancy locking
> problem
> with AO2_ALLOC_OPT_LOCK_RWLOCK within the container traversal code.
I'm not sure it's worth the risk to allow/support this? I think the normal usage pattern for weakproxy containers would be: lock the container, do a find, if find returns NULL allocate a new object and insert it, then unlock the container. So for the ao2_find you would still need a write lock since a new object will be inserted if non was available. Question is do we document a big warning about this or block it in container allocation (error out)?
> AO2_ALLOC_OPT_LOCK_NOLOCK weak containers are possible but the real
> objects must also be controlled by the owning thread. Weak proxy
> notification callbacks could happen at any time if other threads
> have
> references to the real object. The added restrictions for
> AO2_ALLOC_OPT_LOCK_NOLOCK weak containers really negate the
> benefits of
> reference counting altogether.
NOLOCK would not be useful or safe and most likely should be blocked. Long term maybe someone will have a use for giving the container a lockobj, but that's out of scope for this commit.
> A weakness of the proxy object is that any container keys in the
> proxy must be immutable.
I'm not sure how this is different from standard containers? I thought any key that can be used by container callbacks must be immutable as long as the object is in any container.
> The code should not need to know which containers the
> proxy is a member.
I don't understand this comment. Are you talking about not giving the container reference to ao2_weakproxy_subscribe?
> As an extension, the keys in the real ao2 object must
> be immutable (if the real object even has a copy of the keys in the
> proxy
> object).
Actually ao2 weakproxy design had this in mind. The correct pattern for keys on weak and real objects is:
struct myobj_proxy {
AO2_WEAKPROXY();
const char key[0];
};
struct myobj {
const char *key;
};
myobj->key would be a pointer to myobj_proxy->key. This is safe once the ao2 weakproxy association is made, it is impossible for myobj_proxy to be destroyed before myobj, so immutable strings on the weakproxy should never be duplicated to the real object.
> > 3) How to deal with manual ao2_unlink?
>
> I don't see a problem. Part of any weak proxy unlinking from the
> container is to unsubscribe from the weak proxy notifications.
>
> However, the automatic unlink is a problem if the proxy object is
> in the
> container multiple times. The weakproxy_run_callbacks() would need
> to run
> through the list calling the callbacks and then delete the list as
> two
> separate loops. It needs to be two loops because the callback for
> the
> weak proxy container would try to unsubscribe and if it were
> already
> removed then the second subscription would be removed and orphan
> the
> second weak proxy object in the container.
Maybe ao2_weakproxy_subscribe should be passed a reference to 'node' instead of 'self'? This way each ao2_link would have a unique subscription.
> > 4) How to deal with shutdown (cleanup of non-empty container)?
>
> I don't see a problem. The container would just unlink any objects
> it
> contains just like it currently does. Part of any weak proxy
> unlinking
> from the container is to unsubscribe from the weak proxy
> notifications.
This actually is currently a problem, but I think my idea for #3 will solve it. Currently ao2_weakproxy_subscribe gets a bumped reference to the container, so it is a circular reference.
> > 5) Do we need to deal with the possibility that a weakproxy can
> be
> > associated with a new object before node_obj_proxy_cb() is
> called?
> > Current patch does not support reuse of weakproxy objects added
> to
> > container due to this.
>
> Weak proxy objects are only associated with one object at a time.
> They
> can only get unassociated when the associated object gets destroyed
> and
> the notification subscription callbacks get called. There isn't a
> weak
> proxy unset function to disassociate an object from the weak proxy
> since
> it couldn't be thread safe when altering the real object's proxy
> pointer.
I actually misstated my concern. By the time node_obj_proxy_cb is called the weakproxy is already unassociated. ao2_unlink will block if another thread has the container locked, that other thread could then associate a new real object to the weakproxy. This is a very unlikely execution flow, maybe not even worth worrying about. named_locks.c cannot have this problem since it makes no attempt to reuse the weakproxy objects.
--
To view, visit https://gerrit.asterisk.org/3749
To unsubscribe, visit https://gerrit.asterisk.org/settings
Gerrit-MessageType: comment
Gerrit-Change-Id: I48f2dfb85e97fd0a382a869cd084afda129c95d9
Gerrit-PatchSet: 2
Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Owner: Corey Farrell <git at cfware.com>
Gerrit-Reviewer: Anonymous Coward #1000019
Gerrit-Reviewer: Corey Farrell <git at cfware.com>
Gerrit-Reviewer: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Richard Mudgett <rmudgett at digium.com>
Gerrit-HasComments: No
More information about the asterisk-code-review
mailing list