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", di-
       rectly. A generic callback handler invoked by this object  then	allows
       iterating dynamically over the arguments	once called back.

       dcbNewCallback2()  creates  a new callback object, where	signature is a
       signature string	describing the function	to be called back (see	manual
       or  dyncall_signature.h	for  format),  and  funcptr  is	a pointer to a
       generic callback	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 always the same for any callback.   userdata	 is  a
       pointer	to arbitrary user data to be available in the generic callback
       handler.	If the callback	 expects  aggregates  (struct,	union)	to  be
       passed  or returned by value, a pointer to an array of DCaggr* descrip-
       tions must be provided (exactly one per aggregate, in the same order as
       in the signature) via the aggrs parameter, 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
       requiring a callback function pointer.

       dcbInitCallback()  and  dcbInitCallback2()  (re)initialize the callback
       object. 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	 call-
       back object on creation or (re)initialization.

       Declaration of a	dyncallback handler (following function	pointer	decla-
       ration 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  callback,  and  result is a	pointer	to an object used to store the
       callback's return value (output,	to be set by  the  handler).  Finally,
       userdata	is the user defined data pointer set when creating or (re)ini-
       tializing the callback object.  The handler itself must return a	signa-
       ture  character (see manual or dyncall_signature.h for format) specify-
       ing 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 re-
       turned.

       To  return  a  trivial  aggregate   by	value,	 a   helper   function
       dcbReturnAggr() needs to	be used	in order to correctly place the	aggre-
       gate 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
       ignored,	and a pointer to the non-trivial aggregate  is	returned  (the
       user  should then do a local copy).  To return a	C++ non-trivial	aggre-
       gate by value via dcbReturnAggr(), pass NULL for	ret, which  will  make
       result->p  point	to (implicit, caller-provided) memory where the	aggre-
       gate 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 values:

	     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  descrip-
       tion 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 re-
       turns 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 descrip-
       tions 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	 loca-
       tion of the vtable entry	of Klass::Method(), of course; the above exam-
       ple omits this for simplicity.

CONFORMING TO
       The  dyncallback	 library needs at least	a c99 compiler with additional
       support 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.0>

home | help