Blame doc/tutorial_dts.dox

rpm-build 95f51c
/**
rpm-build 95f51c
@page libtalloc_dts Chapter 3: Dynamic type system
rpm-build 95f51c
rpm-build 95f51c
@section dts Dynamic type system
rpm-build 95f51c
rpm-build 95f51c
Generic programming in the C language is very difficult. There is no inheritance
rpm-build 95f51c
nor templates known from object oriented languages. There is no dynamic type
rpm-build 95f51c
system. Therefore, generic programming in this language is usually done by
rpm-build 95f51c
type-casting a variable to void* and transferring it through
rpm-build 95f51c
a generic function to a specialized callback as illustrated on the next listing.
rpm-build 95f51c
rpm-build 95f51c
@code
rpm-build 95f51c
void generic_function(callback_fn cb, void *pvt)
rpm-build 95f51c
{
rpm-build 95f51c
  /* do some stuff and call the callback */
rpm-build 95f51c
  cb(pvt);
rpm-build 95f51c
}
rpm-build 95f51c
rpm-build 95f51c
void specific_callback(void *pvt)
rpm-build 95f51c
{
rpm-build 95f51c
  struct specific_struct *data;
rpm-build 95f51c
  data = (struct specific_struct*)pvt;
rpm-build 95f51c
  /* ... */
rpm-build 95f51c
}
rpm-build 95f51c
rpm-build 95f51c
void specific_function()
rpm-build 95f51c
{
rpm-build 95f51c
  struct specific_struct data;
rpm-build 95f51c
  generic_function(callback, &data);
rpm-build 95f51c
}
rpm-build 95f51c
@endcode
rpm-build 95f51c
rpm-build 95f51c
Unfortunately, the type information is lost as a result of this type cast. The
rpm-build 95f51c
compiler cannot check the type during the compilation nor are we able to do it
rpm-build 95f51c
at runtime. Providing an invalid data type to the callback will result in
rpm-build 95f51c
unexpected behaviour (not necessarily a crash) of the application. This mistake
rpm-build 95f51c
is usually hard to detect because it is not the first thing which comes the
rpm-build 95f51c
mind.
rpm-build 95f51c
rpm-build 95f51c
As we already know, every talloc context contains a name. This name is available
rpm-build 95f51c
at any time and it can be used to determine the type of a context even if we
rpm-build 95f51c
lose the type of a variable.
rpm-build 95f51c
rpm-build 95f51c
Although the name of the context can be set to any arbitrary string, the best
rpm-build 95f51c
way of using it to simulate the dynamic type system is to set it directly to the
rpm-build 95f51c
type of the variable.
rpm-build 95f51c
rpm-build 95f51c
It is recommended to use one of talloc() and talloc_array() (or its
rpm-build 95f51c
variants) to create the context as they set its name to the name of the
rpm-build 95f51c
given type automatically.
rpm-build 95f51c
rpm-build 95f51c
If we have a context with such as a name, we can use two similar functions that
rpm-build 95f51c
do both the type check and the type cast for us:
rpm-build 95f51c
rpm-build 95f51c
- talloc_get_type()
rpm-build 95f51c
- talloc_get_type_abort()
rpm-build 95f51c
rpm-build 95f51c
@section dts-examples Examples
rpm-build 95f51c
rpm-build 95f51c
The following example will show how generic programming with talloc is handled -
rpm-build 95f51c
if we provide invalid data to the callback, the program will be aborted. This
rpm-build 95f51c
is a sufficient reaction for such an error in most applications.
rpm-build 95f51c
rpm-build 95f51c
@code
rpm-build 95f51c
void foo_callback(void *pvt)
rpm-build 95f51c
{
rpm-build 95f51c
  struct foo *data = talloc_get_type_abort(pvt, struct foo);
rpm-build 95f51c
  /* ... */
rpm-build 95f51c
}
rpm-build 95f51c
rpm-build 95f51c
int do_foo()
rpm-build 95f51c
{
rpm-build 95f51c
  struct foo *data = talloc_zero(NULL, struct foo);
rpm-build 95f51c
  /* ... */
rpm-build 95f51c
  return generic_function(foo_callback, data);
rpm-build 95f51c
}
rpm-build 95f51c
@endcode
rpm-build 95f51c
rpm-build 95f51c
But what if we are creating a service application that should be running for the
rpm-build 95f51c
uptime of a server, we may want to abort the application during the development
rpm-build 95f51c
process (to make sure the error is not overlooked) and try to recover from the
rpm-build 95f51c
error in the customer release. This can be achieved by creating a custom abort
rpm-build 95f51c
function with a conditional build.
rpm-build 95f51c
rpm-build 95f51c
@code
rpm-build 95f51c
void my_abort(const char *reason)
rpm-build 95f51c
{
rpm-build 95f51c
  fprintf(stderr, "talloc abort: %s\n", reason);
rpm-build 95f51c
#ifdef ABORT_ON_TYPE_MISMATCH
rpm-build 95f51c
  abort();
rpm-build 95f51c
#endif
rpm-build 95f51c
}
rpm-build 95f51c
@endcode
rpm-build 95f51c
rpm-build 95f51c
The usage of talloc_get_type_abort() would be then:
rpm-build 95f51c
rpm-build 95f51c
@code
rpm-build 95f51c
talloc_set_abort_fn(my_abort);
rpm-build 95f51c
rpm-build 95f51c
TALLOC_CTX *ctx = talloc_new(NULL);
rpm-build 95f51c
char *str = talloc_get_type_abort(ctx, char);
rpm-build 95f51c
if (str == NULL) {
rpm-build 95f51c
  /* recovery code */
rpm-build 95f51c
}
rpm-build 95f51c
/* talloc abort: ../src/main.c:25: Type mismatch:
rpm-build 95f51c
   name[talloc_new: ../src/main.c:24] expected[char] */
rpm-build 95f51c
@endcode
rpm-build 95f51c
rpm-build 95f51c
*/