Re: cbdata

From: Henrik Nordstrom <hno@dont-contact.us>
Date: Thu, 12 Jul 2001 19:15:25 +0200

Alex Rousskov wrote:

> How about:
> cbdataCreate/Destroy
> cbdataUse/Abandon
> cbdataValid

Use/Abandon does not feel like the right words to me. These are creation
and destruction of rather long term references to the object, and these
references are most often only stored and verified to be valid, not
actually referenced. In fact, in 90% of the cases the reference is a
void *, and it is up to the original caller what it represents.

> Also, please explicitly state whether cbdataAlloc() calls
> cbdataUse() implicitly (I guess it does not).

Not.

Each cbdata object is intended to have one main reference, returned by
cbdataAlloc/Create(), managed by the one who asked for it, and destroyed
by cbdataFree/Destroy() when the owner of the object no longer wants it.

Others who need to store references to the object as parameers to a
callback handle created additional references by cbdataReference/Use(),
validates their valitidy before use by calling cbdataValid(), and
destroys the reference when no longer needed by calling
cbdataUnreference/Abandon().

> I doubt cbdataReferenceDone() is needed. Can cbdataAbandon() have the
> same functionality?

The only difference is that one returns a temporary reference, the other
does not. Should probably be merged into one.

cbdataReferenceDone() was added very recently in an attempt to address
an efficiency in the most intuitive cbdata use in the scope cbdata is
designed for.

The intuitive standard use (using your names) is

struct mystate {
   ...
   void (*callback)(..., void *data);
   void *callback_data;
};

fooStart(..., callback, void *data)
{
   
   mystate->callback = callback;
   mystate->callback_data = cbdataUse(data);
...
}

fooDone(...)
{
   ...
   if (cbdataValid(mystate->callback_data))
        mystate->callback(..., mystate->callback_data);
   cbdataAbandon(mystate->callback_data);
}

This hoever have the problem that the reference persists after the
callback has been called, quite often causing it to stay around longer
than needed and being harder to debug as the destruction is deferred
until the callback returned and fooDone() continues and calls
cbdataAbandon().

Before the concept of references, code quite often looked like

fooDone(...)
{
    int valid;
    ...
    valid=cbdataValid(mystate->callback_data);
    cbdataUnlock(mystate->callback_data);
    if (valid)
        mystate->callback(..., mystate->callback_data);
}

but this approach had the drawback that stale references to unlocked
data was easily left lying around.

In an attempt to address this cbdataReferenceDone() was introduced,
allowing code like

fooDone(...)
{
    void *cbdata;
    ...
    if ((cbdata = cbdataReferenceDone(mystate->calllback_data)) != NULL)
        mystate->callback(..., cbdata);
}

which tries to join the best of both approaches.

A related note on GCC: Having the callback last in a function is
optimized in a very efficient manner by GCC-3. It unwinds the stack
frame and jumps to the new function (the callback), saving both a few
CPU cycles and valuable stack space.

--
Henrik
Received on Thu Jul 12 2001 - 11:17:04 MDT

This archive was generated by hypermail pre-2.1.9 : Tue Dec 09 2003 - 16:14:07 MST