Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
NAME
     dyncallback -- callback interface of dyncall

SYNOPSIS
     #include <dyncall_callback.h>

     typedef DCsigchar
     (DCCallbackHandler)(DCCallback* pcb, DCArgs* args, DCValue* result,
	 void* userdata);

     DCCallback *
     dcbNewCallback(const DCsigchar * signature, DCCallbackHandler * funcptr,
	 void * userdata);

     DCCallback *
     dcbNewCallback2(const DCsigchar * signature, DCCallbackHandler * funcptr,
	 void * userdata, DCaggr *const * aggrs);

     void
     dcbInitCallback(DCCallback * pcb, const DCsigchar * signature,
	 DCCallbackHandler * funcptr, void * userdata);

     void
     dcbInitCallback2(DCCallback * pcb, const DCsigchar * signature,
	 DCCallbackHandler * funcptr, void * userdata, DCaggr *const * aggrs);

     void
     dcbFreeCallback(DCCallback * pcb);

     void
     dcbGetUserData(DCCallback * pcb);

     DCbool
     dcbArgBool(DCArgs * p);

     DCchar
     dcbArgChar(DCArgs * p);

     DCshort
     dcbArgShort(DCArgs * p);

     DCint
     dcbArgInt(DCArgs * p);

     DClong
     dcbArgLong(DCArgs * p);

     DClonglong
     dcbArgLongLong(DCArgs * p);

     DCuchar
     dcbArgUChar(DCArgs * p);

     DCushort
     dcbArgUShort(DCArgs * p);

     DCuint
     dcbArgUInt(DCArgs * p);

     DCulong
     dcbArgULong(DCArgs * p);

     DCulonglong
     dcbArgULongLong(DCArgs * p);

     DCfloat
     dcbArgFloat(DCArgs * p);

     DCdouble
     dcbArgDouble(DCArgs * p);

     DCpointer
     dcbArgPointer(DCArgs * p);

     DCpointer
     dcbArgAggr(DCArgs * p, DCpointer target);

     void
     dcbReturnAggr(DCArgs * args, DCValue * result, DCpointer ret);

DESCRIPTION
     The  dyncallback  dyncall	library  has an interface to create callback ob-
     jects, that can be passed to functions as callback  function  pointers.  In
     other  words, a pointer to the callback object can be "called", directly. A
     generic callback handler invoked by this object then allows  iterating  dy-
     namically over the arguments once called back.

     dcbNewCallback2()	creates a new callback object, where signature is a sig-
     nature string describing the function to be called back (see manual or dyn-
     call_signature.h for format), and funcptr is a pointer to a  generic  call-
     back  handler  (see below). The signature is needed in the generic callback
     handler to correctly retrieve the arguments provided by the caller  of  the
     callback.	Note that the generic handler's function type/declaration is al-
     ways the same for any callback.  userdata is a pointer  to  arbitrary  user
     data  to  be available in the generic callback handler. If the callback ex-
     pects aggregates (struct, union) to be  passed  or  returned  by  value,  a
     pointer  to  an array of DCaggr* descriptions must be provided (exactly one
     per aggregate, in the same order as in the signature) via the aggrs parame-
     ter, otherwise pass NULL. This pointer must  point  to  valid  data  during
     callback.

     dcbNewCallback()  is  the	same as dcbNewCallback2(), with an implicit NULL
     passed via the aggrs parameter, meaning it can only be used  for  callbacks
     that do not use any aggregate by value.

     NOTE:  C++  non-trivial  aggregates  (check  with	the std::is_trivial type
     trait) do not use aggregate descriptions, so the respective pointers in the
     provided array must be NULL. See dyncall(3) for  more  information  on  C++
     non-trivial aggregates.

     Use  the pointer returned by dcbNewCallback*() as argument in functions re-
     quiring a callback function pointer.

     dcbInitCallback() and dcbInitCallback2() (re)initialize  the  callback  ob-
     ject. For a description of their parameters, see dcbNewCallback*().

     dcbFreeCallback() destroys and frees the callback handler.

     dcbGetUserData()  returns	a pointer to the userdata passed to the callback
     object on creation or (re)initialization.

     Declaration of a dyncallback handler (following function  pointer	declara-
     tion in dyncall_callback.h):

	   DCsigchar cbHandler(DCCallback* cb,
			       DCArgs*	   args,
			       DCValue*    result,
			       void*	   userdata);

     cb  is  a	pointer to the DCCallback object in use, args is to be used with
     the dcbArg*() functions to iterate over the arguments passed to  the  call-
     back, and result is a pointer to an object used to store the callback's re-
     turn  value  (output,  to	be set by the handler). Finally, userdata is the
     user defined data pointer set when creating or (re)initializing  the  call-
     back  object.   The  handler  itself must return a signature character (see
     manual or dyncall_signature.h for	format)  specifying  the  data	type  of
     result.

     Retrieving aggregates by value from the generic handler's args argument can
     be  done  via  dcbArgAggr(), where target must point to memory large enough
     for the aggregate to be copied to, iff the aggregate is trivial (see  below
     for non-trivial C++ aggregates), in which case target is returned.

     To  return  a trivial aggregate by value, a helper function dcbReturnAggr()
     needs to be used in order to correctly place the aggregate  pointed  to  by
     ret into result, then let the generic handler return DC_SIGCHAR_AGGREGATE.

     Retrieving   or  returning  C++  non-trivial  aggregates  (check  with  the
     std::is_trivial type trait) is done differently, as dyncall cannot know how
     to do this copy and the C++ ABI handles those differently:

     When retrieving a C++ non-trivial aggregate via dcbArgAggr(), target is ig-
     nored, and a pointer to the non-trivial aggregate	is  returned  (the  user
     should  then  do  a  local copy).	To return a C++ non-trivial aggregate by
     value via dcbReturnAggr(), pass NULL for ret,  which  will  make  result->p
     point  to	(implicit, caller-provided) memory where the aggregate should be
     copied to.

EXAMPLES
     Note: for simplicity, none of the examples below  do  any	error  checking.
     Also,  none  of  them  pass the callback object pointer as an argument to a
     function doing the respective callback (e.g.  compar  in  qsort(3),  etc.),
     but demonstrate calling it, directly, for clarity.

     Let's  say, we want to create a callback object and call it. First, we need
     to define our callback handler - the following handler illustrates  how  to
     access  the  passed-in arguments, optional userdata, and how to return val-
     ues:

	   DCsigchar cbHandler(DCCallback* cb,
			       DCArgs*	   args,
			       DCValue*    result,
			       void*	   userdata)
	   {
	     int* ud = (int*)userdata;
	     int       arg1 = dcbArgInt     (args);
	     float     arg2 = dcbArgFloat   (args);
	     short     arg3 = dcbArgShort   (args);
	     double    arg4 = dcbArgDouble  (args);
	     long long arg5 = dcbArgLongLong(args);

	     /* .. do something .. */

	     result->s = 1244;
	     return 's';
	   }

     Note that the return value of the handler is a signature character, and not
     the actual return value, itself.  Now, let's call it through  a  DCCallback
     object:

	   DCCallback* cb;
	   short result = 0;
	   int userdata = 1337;
	   cb = dcbNewCallback("ifsdl)s", &cbHandler, &userdata);

	   /* call the callback object */
	   result = ((short(*)(int, float, short, double, long long))cb)
	     (123, 23.f, 3, 1.82, 9909ll);

	   dcbFreeCallback(cb);

   C/trivial aggregates by-value
     Onto  an  example calling back a function which takes an aggregate by value
     (note  that   this   is   only   available   on   platforms   where   macro
     DC__Feature_AggrByVal is defined). E.g. with the following function f() and
     struct S:

	   struct S { char x[3]; double y; };
	   int f(struct S, float);

     the callback handler would look like:

	   DCsigchar cbHandler(DCCallback* cb,
			       DCArgs*	   args,
			       DCValue*    result,
			       void*	   userdata)
	   {
	     struct S arg1;
	     float arg2;
	     dcbArgAggr(args, (DCpointer)&arg1);
	     arg2 = dcbArgFloat(args);

	     /* ... */

	     result->i = 1;
	     return 'i';
	   }

     and  the  callback object as well as the aggregate field/layout description
     are set up (and the former called back) as follows:

	   struct S s = { { 56, -23, 0 }, -6.28 };
	   int result;

	   DCCallback* cb;

	   DCaggr *a = dcNewAggr(2, sizeof(struct S));
	   dcAggrField(a, DC_SIGCHAR_CHAR,   offsetof(struct S, x), 3);
	   dcAggrField(a, DC_SIGCHAR_DOUBLE, offsetof(struct S, y), 1);
	   dcCloseAggr(a);

	   /* an array of DCaggr* must be passed as last arg, with one
	    * entry per 'A' signature character; we got only one, here
	    */
	   cb = dcbNewCallback2("Af)v", &cbHandler, NULL, &a);

	   /* call the callback object */
	   result = ((int(*)(struct S, float))cb)(s, 42.f);

	   dcbFreeCallback(cb);
	   dcFreeAggr(a);

     Let's extend the last example, so that the callback function  also  returns
     struct S by value.  The struct definition, function declaration and handler
     definition would be:

	   /* callback function decl */
	   struct S f(struct S, float);

	   struct S { char x[3]; double y; };

	   DCsigchar cbHandler(DCCallback* cb,
			       DCArgs*	   args,
			       DCValue*    result,
			       void*	   userdata)
	   {
	     struct S arg1, r;
	     float arg2;
	     dcbArgAggr(args, (DCpointer)&arg1);
	     arg2 = dcbArgFloat(args);

	     /* ... */

	     /* use helper to write aggregate return value to result */
	     dcbReturnAggr(args, result, (DCpointer)&r);
	     return 'A';
	   }

     and  the callback object as well as the aggregate field/layout descriptions
     are set up (and the former called back) as follows:

	   struct S s = { { 33, 29, -1 }, 6.8 };
	   struct S result;

	   DCCallback* cb;

	   DCaggr *a = { dcNewAggr(2, sizeof(struct S)) };
	   dcAggrField(a, DC_SIGCHAR_CHAR,   offsetof(struct S, x), 3);
	   dcAggrField(a, DC_SIGCHAR_DOUBLE, offsetof(struct S, y), 1);
	   dcCloseAggr(a);

	   /* an array of DCaggr* must be passed as last arg, with one
	    * entry per 'A' signature character
	    */
	   cb = dcbNewCallback2("Af)A", &cbHandler, NULL, (DCaggr*[2]){a,a});

	   /* call the callback object */
	   result = ((struct S(*)(struct S, float))cb)(s, 42.f);

	   dcbFreeCallback(cb);
	   dcFreeAggr(a);

   C++
     In our next example, let's look at setting up a DCCallback object	to  call
     back  a  simple  C++  method (illustrating the need to specify the thiscall
     calling convention). If the class and method is declared as:

	   class Klass {
	   public:
		   virtual void Method(float, int);
	   };

     the respective callback handler would be something along the lines of:

	   DCsigchar cbHandler(DCCallback* cb,
			       DCArgs*	   args,
			       DCValue*    result,
			       void*	   userdata)
	   {
	     Klass*    thisptr = (Klass*)dcbArgPointer(args);
	     float     arg1 = dcbArgFloat(args);
	     int       arg2 = dcbArgInt(args);

	     /* ... */

	     return 'v';
	   }

     and the callback object would be used as follows:

	   DCCallback* cb;
	   cb = dcbNewCallback("_*pfi)v", &cbHandler, NULL);

	   /* HACK: this is a hack just for this example to force the compiler
	    * generating a thiscall, below (creates a fake vtable mimicking
	    * Klass, setting all of its possible entries to our callback handler;
	    */
	   DCpointer fakeClass[sizeof(Klass)/sizeof(DCpointer)];
	   for(int j=0; j<sizeof(Klass)/sizeof(DCpointer); ++j)
		   fakeClass[j] = &cb;

	   /* (this)call the callback object */
	   ((Klass*)&fakeClass)->Method(8, 23.f);

	   dcbFreeCallback(cb);

     NOTE: In a real world scenario one would figure out the precise location of
     the vtable entry of Klass::Method(), of course;  the  above  example  omits
     this for simplicity.

CONFORMING TO
     The  dyncallback library needs at least a c99 compiler with additional sup-
     port for anonymous structs/unions	(which	were  introduced  officially  in
     c11). Given that those are generally supported by pretty much all major c99
     conforming  compilers  (as  default extension), it should build fine with a
     c99 toolchain.  Strictly speaking, dyncall conforms to c11, though.

SEE ALSO
     dyncall(3), dynload(3) and the dyncall manual (available in  HTML	and  PDF
     format) for more information.

AUTHORS
     Daniel Adler <dadler@uni-goettingen.de>
     Tassilo Philipp <tphilipp@potion-studios.com>

				   $Mdocdate$			  dyncallback(3)

Want to link to this manual page? Use this URL:
<https://man.freebsd.org/cgi/man.cgi?query=dyncallback&sektion=3&manpath=FreeBSD+Ports+15.1.quarterly>

home | help