|
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 |
*/
|