Re: callback function context value

Denis Corbin <[email protected]> Tue, 27 Apr 2004 22:46:44 +0200
Newsgroups gmane.comp.sysutils.backup.dar.libdar
Message-ID <[email protected]>
Johnathan Burchill wrote:
 > Hi Denis,

Hello Johnathan,

 >
 > Apparently it is standard coding practice for API callback functions to
 > accept a "context value", which is a void *, that allows one to use a
 > class member function as a callback without resorting to a global 
pointer
 > variable.

Well, to my point of view, after having read the tutorial you give
reference bellow, there is no standard coding practice that speaks about
a "context value" for callback. The "context value" is used as a trick
to make a callback function pointing to non-static member functions of a
C++ class. The trick implies a static method or normal function to 
explicitely pass the "this" pointer (pointer to the current object which 
is a hidden argument in C++) as explicit argument.

Now my question, is do we need libdar calling a non-static member of a
given object (as callback) ?

First there is a risk, if this objects dies, we will have big problems
like memory violations. But OK, if you give a wrong argument as address 
of the callback function we get to the same point.

Second, libdar would always call the method of the same object, and it
would require first, a way for kdar (for example) to tell libdar which
object address (the "this" argument) to give to the callback function in
the "context value".

Third, logically, it is a class defined in the user application like
kdar, and libdar does not know anything about this class. This would not
be very useful to libdar point of view.

 >
 > As I understand dar, it uses a regular function as the callback. 
Could you
 > add perhaps a new set of callback setting functions to the libdar API 
that
 > accept a void * context value to be passed. It would be easy to keep
 > backwards compatibility with earlier libdar versions by redefining the
 > standard callback setting functions to call the new ones with NULL 
for the
 > void *.

Yes, this is still possible.

I think the need behind is the thread safe libdar library. If the
library is thread safe, there must not be a function in the API that
receive the address of a callback function without any context.

Let's take an example:

actually (version 2.1.2 is the last release) libdar API proposes the
following function:

	set_warning_callback(&my_warning_callback);

to reach thread safe level, set_warning_callback must have a contextual 
argument, to have a thread discriminant, the callback function stays the 
same. In my idea actually, a possible solution is a new class that will 
gather all static variables that currently make the libdar thread 
unsafe. I have not yet a name for that class, so let's call it 'junk' 
for now. We would then have set_warning_callback a method of the 'junk' 
class, and probably any other functions of the current API (op_create, etc.)

Before anything else, each thread should create its own 'junk' object 
forcing the calling application to give a thread specific callback 
function in the 'junk' constructor.

OK now, I see, if you have several threads, you could give several 
callback functions (one per thread), but that could lead to some 
ineficiency, you could rather give the same callback function to all 
thread and have an additional argument in the callback prototype that 
tell this common callback function which thread it is called from, and 
which action to do (which object to call, etc...). A void pointer should 
be effectively interesting as it could carry the address to a function 
or the address to an object which method to call.

we would have someting like this:

class junk
{
public:
    set_warning_callback(void (*callback)(const std::string &x,
                                          void *context) )
        { warning_callback = callback; };
    set_warning_callback_context_to_give(void *context)
        { context_to_give = context; };

    op_create(....);
    op_create_noexcept(...);
    [...]

private:
    void *context_to_give;
    void (*warning_callback)(const std::string &x, void *context);
};

and inside a give thread :

     ...
     junk toto;
     toto.set_warning_callback(&mycallback);
     toto.set_warning_context_to_give(this);
     toto.op_create_noexcept(...);
     ...

with the global callback function:

     void mycallback(const std::string &x, void *context)
     {
          context->some_method(x);
    	  // well, this is much simplified.
     }


Does this makes sens to you ?

 >
 > There is a good tutorial at
 > http://www.function-pointer.org/callback.html
 > #3:  How to Implement Callbacks in C and C++
 >
 > In the examples given, I currently use method B, but it would be 
better to
 > use method A to avoid using the global variable.

I agree, I dislike global variables.

 >
 > Cheers,
 > JB
 >

Cheers,
Denis.

P.S.: the sample code are not expected to compile, there are here for 
further reference if necessary.





-------------------------------------------------------
This SF.Net email is sponsored by: Oracle 10g
Get certified on the hottest thing ever to hit the market... Oracle 10g. 
Take an Oracle 10g class now, and we'll give you the exam FREE. 
http://ads.osdn.com/?ad_id=3149&alloc_id=8166&op=click