2008-06-23 13:58:30 -07:00
|
|
|
@node Callbacks
|
|
|
|
|
@chapter Callbacks
|
2008-06-15 21:38:13 -07:00
|
|
|
|
|
|
|
|
Some new users to @command{ns-3} are unfamiliar with an extensively used
|
|
|
|
|
programming idiom used throughout the code: the ``ns-3 callback''. This
|
|
|
|
|
chapter provides some motivation on the callback, guidance on how to use
|
|
|
|
|
it, and details on its implementation.
|
|
|
|
|
|
|
|
|
|
@menu
|
2009-10-16 07:13:05 -07:00
|
|
|
* Callbacks Motivation::
|
|
|
|
|
* Callbacks Background::
|
2008-06-15 21:38:13 -07:00
|
|
|
* Using the Callback API::
|
2009-09-14 18:03:30 -07:00
|
|
|
* Bound Callbacks::
|
2008-06-15 21:38:13 -07:00
|
|
|
* Callback locations in ns-3::
|
2009-10-18 22:11:29 -07:00
|
|
|
* Traced Callbacks::
|
2008-06-15 21:38:13 -07:00
|
|
|
* Implementation details::
|
|
|
|
|
@end menu
|
|
|
|
|
|
2009-10-16 07:13:05 -07:00
|
|
|
@node Callbacks Motivation
|
2008-06-15 21:38:13 -07:00
|
|
|
@section Motivation
|
|
|
|
|
|
|
|
|
|
Consider that you have two simulation models A and B, and you wish
|
|
|
|
|
to have them pass information between them during the simulation. One
|
|
|
|
|
way that you can do that is that you can make A and B each explicitly
|
2009-09-04 17:23:34 -07:00
|
|
|
knowledgeable about the other, so that they can invoke methods on each
|
2008-06-15 21:38:13 -07:00
|
|
|
other.
|
|
|
|
|
|
|
|
|
|
@verbatim
|
|
|
|
|
class A {
|
|
|
|
|
public:
|
|
|
|
|
void ReceiveInput ( // parameters );
|
|
|
|
|
...
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(in another source file:)
|
|
|
|
|
|
|
|
|
|
class B {
|
|
|
|
|
public:
|
|
|
|
|
void DoSomething (void);
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
A* a_instance; // pointer to an A
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
B::DoSomething()
|
|
|
|
|
{
|
|
|
|
|
// Tell a_instance that something happened
|
|
|
|
|
a_instance->ReceiveInput ( // parameters);
|
|
|
|
|
...
|
|
|
|
|
}
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
|
|
|
|
This certainly works, but it has the drawback that it introduces a
|
|
|
|
|
dependency on A and B to know about the other at compile time (this
|
|
|
|
|
makes it harder to have independent compilation units in the simulator)
|
|
|
|
|
and is not generalized; if in a later usage scenario, B needs to talk
|
|
|
|
|
to a completely different C object, the source code for B needs to be
|
|
|
|
|
changed to add a ``c_instance'' and so forth. It is easy to see that
|
|
|
|
|
this is a brute force mechanism of communication that can lead to
|
|
|
|
|
programming cruft in the models.
|
|
|
|
|
|
|
|
|
|
This is not to say that objects should not know about one another
|
|
|
|
|
if there is a hard dependency between them, but that often the model
|
|
|
|
|
can be made more flexible if its interactions are less constrained at
|
|
|
|
|
compile time.
|
|
|
|
|
|
|
|
|
|
This is not an abstract problem for network simulation research,
|
|
|
|
|
but rather it has been a source of problems in previous simulators,
|
|
|
|
|
when researchers want to extend or modify the system to do different
|
|
|
|
|
things (as they are apt to do in research). Consider, for example,
|
|
|
|
|
a user who wants to add an IPsec security protocol sublayer
|
|
|
|
|
between TCP and IP:
|
|
|
|
|
@verbatim
|
|
|
|
|
------------ -----------
|
|
|
|
|
| TCP | | TCP |
|
|
|
|
|
------------ -----------
|
|
|
|
|
| becomes -> |
|
|
|
|
|
----------- -----------
|
|
|
|
|
| IP | | IPsec |
|
|
|
|
|
----------- -----------
|
|
|
|
|
|
|
|
|
|
|
-----------
|
|
|
|
|
| IP |
|
|
|
|
|
-----------
|
|
|
|
|
@end verbatim
|
|
|
|
|
If the simulator has
|
|
|
|
|
made assumptions, and hard coded into the code, that IP always talks
|
|
|
|
|
to a transport protocol above, the user may be forced to hack the
|
2009-09-14 18:03:30 -07:00
|
|
|
system to get the desired interconnections, This is clearly not an
|
|
|
|
|
optimal way to design a generic simulator.
|
|
|
|
|
|
2009-10-16 07:13:05 -07:00
|
|
|
@node Callbacks Background
|
2009-09-14 18:03:30 -07:00
|
|
|
@section Background
|
|
|
|
|
|
2009-10-18 22:11:29 -07:00
|
|
|
@cartouche
|
|
|
|
|
Readers familiar with programming callbacks may skip this tutorial section.
|
|
|
|
|
@end cartouche
|
|
|
|
|
|
2009-09-14 18:03:30 -07:00
|
|
|
The basic mechanism that allows one to address the problem above is known as
|
|
|
|
|
a @emph{callback}. The ultimate goal is to allow one piece of code to call
|
|
|
|
|
a function (or method in C++) without any specific inter-module dependency.
|
|
|
|
|
|
|
|
|
|
This ultimately means you need some kind of indirection -- you treat the address
|
|
|
|
|
of the called function as a variable. This variable is called a pointer-to-function
|
|
|
|
|
variable. The relationship between function and pointer-to-function pointer is
|
|
|
|
|
really no different that that of object and pointer-to-object.
|
|
|
|
|
|
|
|
|
|
In C the canonical example of a pointer-to-function is a
|
|
|
|
|
pointer-to-function-returning-integer (PFI). For a PFI taking one int parameter,
|
|
|
|
|
this could be declared like,
|
|
|
|
|
|
|
|
|
|
@verbatim
|
|
|
|
|
int (*pfi)(int arg) = 0;
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
|
|
|
|
What you get from this is a variable named simply ``pfi'' that is initialized
|
|
|
|
|
to the value 0. If you want to initialize this pointer to something meaningful,
|
|
|
|
|
you have to have a function with a matching signature. In this case,
|
|
|
|
|
|
|
|
|
|
@verbatim
|
|
|
|
|
int MyFunction (int arg) {}
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
|
|
|
|
If you have this target, you can initialize the variable to point to your
|
|
|
|
|
function like,
|
|
|
|
|
|
|
|
|
|
@verbatim
|
|
|
|
|
pfi = MyFunction;
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
|
|
|
|
You can then call MyFunction indirectly using the more suggestive form of
|
|
|
|
|
the call,
|
|
|
|
|
|
|
|
|
|
@verbatim
|
|
|
|
|
int result = (*pfi) (1234);
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
|
|
|
|
This is suggestive since it looks like you are dereferencing the function
|
|
|
|
|
pointer just like you would dereference any pointer. Typically, however,
|
|
|
|
|
people take advantage of the fact that the compiler knows what is going on
|
|
|
|
|
and will just use a shorter form,
|
|
|
|
|
|
|
|
|
|
@verbatim
|
|
|
|
|
int result = pfi (1234);
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
|
|
|
|
Notice that the function pointer obeys value semantics, so you can pass it
|
|
|
|
|
around like any other value. Typically, when you use an asynchronous interface
|
|
|
|
|
you will pass some entity like this to a function which will perform an action
|
|
|
|
|
and ``call back'' to let you know it completed. It calls back by following the
|
|
|
|
|
indirection and executing the provided function.
|
|
|
|
|
|
|
|
|
|
In C++ you have the added complexity of objects. The analogy with the PFI
|
|
|
|
|
above means you have a pointer to a member function returning an int (PMI)
|
|
|
|
|
instead of the pointer to function returning an int (PFI).
|
|
|
|
|
|
|
|
|
|
The declaration of the variable providing the indirection looks only slightly
|
|
|
|
|
different,
|
|
|
|
|
|
|
|
|
|
@verbatim
|
|
|
|
|
int (MyClass::*pmi) (int arg) = 0;
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
|
|
|
|
This declares a variable named ``pmi'' just as the previous example declared a
|
|
|
|
|
variable named ``pfi.'' Since the will be to call a method of an instance of
|
|
|
|
|
a particular class, one must declare that method in a class.
|
|
|
|
|
|
|
|
|
|
@verbatim
|
|
|
|
|
class MyClass {
|
|
|
|
|
public:
|
|
|
|
|
int MyMethod (int arg);
|
|
|
|
|
};
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
|
|
|
|
Given this class declaration, one would then initialize that variable like this,
|
|
|
|
|
|
|
|
|
|
@verbatim
|
|
|
|
|
pmi = &MyClass::MyMethod;
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
|
|
|
|
This assigns the address of the code implementing the method to the variable,
|
|
|
|
|
completing the indirection. In order to call a method, the code needs a ``this''
|
|
|
|
|
pointer. This, in turn, means there must be an object of MyClass to refer to.
|
|
|
|
|
A simplistic example of this is just calling a method indirectly (think virtual
|
|
|
|
|
function).
|
|
|
|
|
|
|
|
|
|
@verbatim
|
|
|
|
|
int (MyClass::*pmi) (int arg) = 0; // Declare a PMI
|
|
|
|
|
pmi = &MyClass::MyMethod; // Point at the implementation code
|
|
|
|
|
|
|
|
|
|
MyClass myClass; // Need an instance of the class
|
|
|
|
|
(myClass.*pmi) (1234); // Call the method with an object ptr
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
|
|
|
|
Just like in the C example, you can use this in an asynchronous call to another
|
|
|
|
|
module which will ``call back'' using a method and an object pointer. The
|
|
|
|
|
straightforward extension one might consider is to pass a pointer to the object
|
|
|
|
|
and the PMI variable. The module would just do,
|
|
|
|
|
|
|
|
|
|
@verbatim
|
|
|
|
|
(*objectPtr.*pmi) (1234);
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
|
|
|
|
to execute the callback on the desired object.
|
|
|
|
|
|
|
|
|
|
One might ask at this time, ``what's the point''? The called module will have
|
|
|
|
|
to understand the concrete type of the calling object in order to properly make
|
|
|
|
|
the callback. Why not just accept this, pass the correctly typed object pointer
|
|
|
|
|
and do object->Method(1234) in the code instead of the callback? This is
|
|
|
|
|
precisely the problem described above. What is needed is a way to decouple the
|
|
|
|
|
calling function from the called class completely. This requirement led to the
|
|
|
|
|
development of the @emph{Functor}.
|
|
|
|
|
|
|
|
|
|
A functor is the outgrowth of something invented in the 1960s called a closure.
|
|
|
|
|
It is basically just a packaged-up function call, possibly with some state.
|
|
|
|
|
|
|
|
|
|
A functor has two parts, a specific part and a generic part, related through
|
|
|
|
|
inheritance. The calling code (the code that executes the callback) will execute
|
|
|
|
|
a generic overloaded @code{operator ()} of a generic functor to cause the callback
|
|
|
|
|
to be called. The called code (the code that wants to be called back) will have
|
|
|
|
|
to provide a specialized implementation of the @code{operator ()} that performs the
|
|
|
|
|
class-specific work that caused the close-coupling problem above.
|
|
|
|
|
|
|
|
|
|
With the specific functor and its overloaded @code{operator ()} created, the called
|
|
|
|
|
code then gives the specialized code to the module that will execute the callback
|
|
|
|
|
(the calling code).
|
|
|
|
|
|
|
|
|
|
The calling code will take a generic functor as a parameter, so an implicit cast
|
|
|
|
|
is done in the function call to convert the specific functor to a generic functor.
|
|
|
|
|
This means that the calling module just needs to understand the generic functor
|
|
|
|
|
type. It is decoupled from the calling code completely.
|
|
|
|
|
|
|
|
|
|
The information one needs to make a specific functor is the object pointer and
|
|
|
|
|
the pointer-to-method address.
|
|
|
|
|
|
|
|
|
|
The essence of what needs to happen is that the system declares a generic part
|
|
|
|
|
of the functor,
|
|
|
|
|
|
|
|
|
|
@verbatim
|
|
|
|
|
template <typename T>
|
|
|
|
|
class Functor
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
virtual void operator() (T arg) = 0;
|
|
|
|
|
};
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
|
|
|
|
The caller defines a specific part of the functor that really is just there to
|
|
|
|
|
implement the specific operator() method,
|
|
|
|
|
|
|
|
|
|
@verbatim
|
|
|
|
|
template <typname T, typename ARG>
|
|
|
|
|
class SpecificFunctor : public Functor
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
SpecificFunctor(T* p, int (T::*_pmi)(ARG arg))
|
|
|
|
|
{
|
|
|
|
|
m_p = p;
|
|
|
|
|
m_pmi = pmi;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual int operator() (ARG arg)
|
|
|
|
|
{
|
|
|
|
|
(*m_p.*m_pmi)(arg);
|
|
|
|
|
}
|
|
|
|
|
private:
|
|
|
|
|
void (T::*m_pmi)(ARG arg);
|
|
|
|
|
T* m_p;
|
|
|
|
|
};
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
2009-09-15 11:57:12 -07:00
|
|
|
@emph{N.B. The previous code is not real ns-3 code. It is simplistic example
|
|
|
|
|
code used only to illustrate the concepts involved and to help you understand
|
|
|
|
|
the system more. Do not expect to find this code anywhere in the ns-3 tree}
|
|
|
|
|
|
2009-09-14 18:03:30 -07:00
|
|
|
Notice that there are two variables defined in the class above. The m_p
|
|
|
|
|
variable is the object pointer and m_pmi is the variable containing the
|
|
|
|
|
address of the function to execute.
|
|
|
|
|
|
|
|
|
|
Notice that when @code{operator()} is called, it in turn calls the method provided
|
|
|
|
|
with the object pointer using the C++ PMI syntax.
|
|
|
|
|
|
|
|
|
|
To use this, one could then declare some model code that takes a generic functor
|
|
|
|
|
as a parameter
|
|
|
|
|
|
|
|
|
|
@verbatim
|
|
|
|
|
void LibraryFunction (Functor functor);
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
|
|
|
|
The code that will talk to the model would build a specific functor and pass it to
|
|
|
|
|
@code{LibraryFunction},
|
|
|
|
|
|
|
|
|
|
@verbatim
|
|
|
|
|
MyClass myClass;
|
|
|
|
|
SpecificFunctor<MyClass, int> functor (&myclass, MyClass::MyMethod);
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
|
|
|
|
When @code{LibraryFunction} is done, it executes the callback using the
|
|
|
|
|
@code{operator()} on the generic functor it was passed, and in this particular
|
|
|
|
|
case, provides the integer argument:
|
|
|
|
|
|
|
|
|
|
@verbatim
|
|
|
|
|
void
|
|
|
|
|
LibraryFunction (Functor functor)
|
|
|
|
|
{
|
|
|
|
|
// Ececute the library function
|
|
|
|
|
functor(1234);
|
|
|
|
|
}
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
|
|
|
|
Notice that @code{LibraryFunction} is completely decoupled from the specific
|
|
|
|
|
type of the client. The connection is made through the Functor polymorphism.
|
|
|
|
|
|
|
|
|
|
The Callback API in @command{ns-3} implements object-oriented callbacks using
|
|
|
|
|
the functor mechanism. This callback API, being based on C++ templates, is
|
|
|
|
|
type-safe; that is, it performs static type checks to enforce proper signature
|
|
|
|
|
compatibility between callers and callees. It is therefore more type-safe to
|
|
|
|
|
use than traditional function pointers, but the syntax may look imposing at
|
|
|
|
|
first. This section is designed to walk you through the Callback system so
|
|
|
|
|
that you can be comfortable using it in @command{ns-3}.
|
2008-06-15 21:38:13 -07:00
|
|
|
|
|
|
|
|
@node Using the Callback API
|
|
|
|
|
@section Using the Callback API
|
|
|
|
|
|
|
|
|
|
The Callback API is fairly minimal, providing only two services:
|
|
|
|
|
@itemize @bullet
|
|
|
|
|
@item callback type declaration: a way to declare a type of callback
|
|
|
|
|
with a given signature, and,
|
|
|
|
|
@item callback instantiation: a way to instantiate a
|
|
|
|
|
template-generated forwarding callback which can forward any calls
|
|
|
|
|
to another C++ class member method or C++ function.
|
|
|
|
|
@end itemize
|
|
|
|
|
|
|
|
|
|
This is best observed via walking through an example, based on
|
|
|
|
|
@code{samples/main-callback.cc}.
|
|
|
|
|
|
|
|
|
|
@subsection Using the Callback API with static functions
|
|
|
|
|
|
|
|
|
|
Consider a function:
|
2009-09-14 18:03:30 -07:00
|
|
|
|
2008-06-15 21:38:13 -07:00
|
|
|
@verbatim
|
2009-09-14 18:03:30 -07:00
|
|
|
static double
|
|
|
|
|
CbOne (double a, double b)
|
|
|
|
|
{
|
|
|
|
|
std::cout << "invoke cbOne a=" << a << ", b=" << b << std::endl;
|
|
|
|
|
return a;
|
|
|
|
|
}
|
2008-06-15 21:38:13 -07:00
|
|
|
@end verbatim
|
|
|
|
|
|
2009-09-04 17:23:34 -07:00
|
|
|
Consider also the following main program snippet:
|
2009-09-14 18:03:30 -07:00
|
|
|
|
2008-06-15 21:38:13 -07:00
|
|
|
@verbatim
|
2009-09-14 18:03:30 -07:00
|
|
|
int main (int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
// return type: double
|
|
|
|
|
// first arg type: double
|
|
|
|
|
// second arg type: double
|
|
|
|
|
Callback<double, double, double> one;
|
|
|
|
|
}
|
2008-06-15 21:38:13 -07:00
|
|
|
@end verbatim
|
|
|
|
|
|
2009-09-14 18:03:30 -07:00
|
|
|
This is an example of a C-style callback -- one which does not include or need
|
2009-10-18 22:11:29 -07:00
|
|
|
a @code{this} pointer. The function template @code{Callback} is esentially the
|
2009-09-14 18:03:30 -07:00
|
|
|
declaration of the variable containing the pointer-to-function. In the example
|
|
|
|
|
above, we explicitly showed a pointer to a function that returned an integer and
|
|
|
|
|
took a single integer as a parameter, The @code{Callback} template function is
|
|
|
|
|
a generic version of that -- it is used to declare the type of a callback.
|
|
|
|
|
|
2009-10-18 22:11:29 -07:00
|
|
|
@strong{Note1:} Readers unfamiliar with C++ templates may consult
|
|
|
|
|
@uref{http://www.cplusplus.com/doc/tutorial/templates/,,this reference}.
|
|
|
|
|
|
2009-09-14 18:03:30 -07:00
|
|
|
The @code{Callback} template requires one mandatory argument (the return type
|
|
|
|
|
of the function to be assigned to this callback) and up to five optional
|
|
|
|
|
arguments, which each specify the type of the arguments (if your particular
|
2009-10-18 22:11:29 -07:00
|
|
|
callback function has more than five arguments, then this can be handled
|
2009-09-14 18:03:30 -07:00
|
|
|
by extending the callback implementation).
|
|
|
|
|
|
|
|
|
|
So in the above example, we have a declared a callback named "one" that will
|
|
|
|
|
eventually hold a function pointer. The signature of the function that it will
|
|
|
|
|
hold must return double and must support two double arguments. If one tries
|
|
|
|
|
to pass a function whose signature does not match the declared callback, the
|
|
|
|
|
compilation will fail.
|
|
|
|
|
|
|
|
|
|
Now, we need to tie together this callback instance and the actual target function
|
|
|
|
|
(CbOne). Notice above that CbOne has the same function signature types as the
|
|
|
|
|
callback-- this is important. We can pass in any such properly-typed function
|
|
|
|
|
to this callback. Let's look at this more closely:
|
2008-06-15 21:38:13 -07:00
|
|
|
|
|
|
|
|
@verbatim
|
|
|
|
|
static double CbOne (double a, double b) {}
|
|
|
|
|
^ ^ ^
|
|
|
|
|
| ---| ------|
|
|
|
|
|
| | |
|
|
|
|
|
Callback<double, double, double> one;
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
2009-09-14 18:03:30 -07:00
|
|
|
You can only bind a function to a callback if they have the matching signature.
|
|
|
|
|
The first template argument is the return type, and the additional template
|
|
|
|
|
arguments are the types of the arguments of the function signature.
|
|
|
|
|
|
|
|
|
|
Now, let's bind our callback "one" to the function that matches its signature:
|
|
|
|
|
|
2008-06-15 21:38:13 -07:00
|
|
|
@verbatim
|
|
|
|
|
// build callback instance which points to cbOne function
|
|
|
|
|
one = MakeCallback (&CbOne);
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
2009-09-14 18:03:30 -07:00
|
|
|
This call to @code{MakeCallback} is, in essence, creating one of the specialized
|
|
|
|
|
functors mentioned above. The variable declared using the @code{Callback}
|
|
|
|
|
template function is going to be playing the part of the generic functor. The
|
|
|
|
|
assignment @code{one = MakeCallback (&CbOne)} is the cast that converts the
|
|
|
|
|
specialized functor known to the callee to a generic functor known to the caller.
|
|
|
|
|
|
|
|
|
|
Then, later in the program, if the callback is needed, it can be used as follows:
|
2008-06-15 21:38:13 -07:00
|
|
|
@verbatim
|
|
|
|
|
NS_ASSERT (!one.IsNull ());
|
2009-09-14 18:03:30 -07:00
|
|
|
|
2008-06-15 21:38:13 -07:00
|
|
|
// invoke cbOne function through callback instance
|
|
|
|
|
double retOne;
|
|
|
|
|
retOne = one (10.0, 20.0);
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
2009-09-14 18:03:30 -07:00
|
|
|
The check for @code{IsNull()} ensures that the callback is not null -- that there
|
|
|
|
|
is a function to call behind this callback. Then, @code{one()} executes the
|
|
|
|
|
generic @code{operator()} which is really overloaded with a specific implementation
|
|
|
|
|
of @code{operator()} and returns the same result as if @code{CbOne()} had been
|
|
|
|
|
called directly.
|
2008-06-15 21:38:13 -07:00
|
|
|
|
|
|
|
|
@subsection Using the Callback API with member functions
|
|
|
|
|
|
2009-09-14 18:03:30 -07:00
|
|
|
Generally, you will not be calling static functions but instead public member
|
|
|
|
|
functions of an object. In this case, an extra argument is needed to the
|
|
|
|
|
MakeCallback function, to tell the system on which object the function should be
|
|
|
|
|
invoked. Consider this example, also from main-callback.cc:
|
2008-06-15 21:38:13 -07:00
|
|
|
|
|
|
|
|
@verbatim
|
2009-09-14 18:03:30 -07:00
|
|
|
class MyCb {
|
|
|
|
|
public:
|
|
|
|
|
int CbTwo (double a) {
|
|
|
|
|
std::cout << "invoke cbTwo a=" << a << std::endl;
|
|
|
|
|
return -5;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int main ()
|
|
|
|
|
{
|
|
|
|
|
...
|
|
|
|
|
// return type: int
|
|
|
|
|
// first arg type: double
|
|
|
|
|
Callback<int, double> two;
|
|
|
|
|
MyCb cb;
|
|
|
|
|
// build callback instance which points to MyCb::cbTwo
|
|
|
|
|
two = MakeCallback (&MyCb::CbTwo, &cb);
|
|
|
|
|
...
|
2008-06-15 21:38:13 -07:00
|
|
|
}
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
2009-09-14 18:03:30 -07:00
|
|
|
Here, we pass an additional object pointer to the @code{MakeCallback<>} function.
|
2009-10-18 22:11:29 -07:00
|
|
|
Recall from the background section above that @code{Operator()} will use the pointer to
|
2009-09-14 18:03:30 -07:00
|
|
|
member syntax when it executes on an object:
|
2008-06-15 21:38:13 -07:00
|
|
|
|
2009-09-14 18:03:30 -07:00
|
|
|
@verbatim
|
|
|
|
|
virtual int operator() (ARG arg)
|
|
|
|
|
{
|
|
|
|
|
(*m_p.*m_pmi)(arg);
|
|
|
|
|
}
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
|
|
|
|
And so we needed to provide the two variables (@code{m_p} and @code{m_pmi}) when
|
|
|
|
|
we made the specific functor. The line,
|
2008-06-15 21:38:13 -07:00
|
|
|
|
|
|
|
|
@verbatim
|
2009-09-14 18:03:30 -07:00
|
|
|
two = MakeCallback (&MyCb::CbTwo, &cb);
|
|
|
|
|
@end verbatim
|
2008-06-15 21:38:13 -07:00
|
|
|
|
2009-09-14 18:03:30 -07:00
|
|
|
does precisely that. In this case,
|
|
|
|
|
|
|
|
|
|
When @code{two ()} is invoked,
|
|
|
|
|
|
|
|
|
|
@verbatim
|
|
|
|
|
int result = two (1.0);
|
2008-06-15 21:38:13 -07:00
|
|
|
@end verbatim
|
|
|
|
|
|
2009-09-14 18:03:30 -07:00
|
|
|
I will result in a call the @code{CbTwo} member function (method) on the object
|
|
|
|
|
pointed to by @code{&cb}.
|
|
|
|
|
|
2008-06-15 21:38:13 -07:00
|
|
|
@subsection Building Null Callbacks
|
|
|
|
|
|
|
|
|
|
It is possible for callbacks to be null; hence it may be wise to
|
|
|
|
|
check before using them. There is a special construct for a null
|
|
|
|
|
callback, which is preferable to simply passing "0" as an argument;
|
|
|
|
|
it is the @code{MakeNullCallback<>} construct:
|
2009-09-14 18:03:30 -07:00
|
|
|
|
2008-06-15 21:38:13 -07:00
|
|
|
@verbatim
|
|
|
|
|
two = MakeNullCallback<int, double> ();
|
|
|
|
|
NS_ASSERT (two.IsNull ());
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
2009-09-14 18:03:30 -07:00
|
|
|
Invoking a null callback is just like invoking a null function pointer: it will
|
|
|
|
|
crash at runtime.
|
|
|
|
|
|
|
|
|
|
@node Bound Callbacks
|
|
|
|
|
@section Bound Callbacks
|
|
|
|
|
|
|
|
|
|
A very useful extension to the functor concept is that of a Bound Callback.
|
|
|
|
|
Previously it was mentioned that closures were originally function calls
|
|
|
|
|
packaged up for later execution. Notice that in all of the Callback
|
|
|
|
|
descriptions above, there is no way to package up any parameters for use
|
|
|
|
|
later -- when the @code{Callback} is called via @code{operator()}. All of
|
|
|
|
|
the parameters are provided by the calling function.
|
|
|
|
|
|
|
|
|
|
What if it is desired to allow the client function (the one that provides the
|
2009-10-18 22:11:29 -07:00
|
|
|
callback) to provide some of the parameters? @uref{http://erdani.com/book/main.html,,Alexandrescu} calls the process of
|
2009-09-14 18:03:30 -07:00
|
|
|
allowing a client to specify one of the parameters @emph{binding}. One of the
|
|
|
|
|
parameters of @code{operator()} has been bound (fixed) by the client.
|
|
|
|
|
|
|
|
|
|
Some of our pcap tracing code provides a nice example of this. There is a
|
|
|
|
|
function that needs to be called whenever a packet is received. This function
|
|
|
|
|
calls an object that actually writes the packet to disk in the pcap file
|
|
|
|
|
format. The signature of one of these functions will be,
|
|
|
|
|
|
|
|
|
|
@verbatim
|
|
|
|
|
static void SniffEvent (Ptr<PcapWriter> writer, Ptr<const Packet> packet);
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
|
|
|
|
The static keyword means this is a static function which does not need a
|
|
|
|
|
@code{this} pointer, so it will be using C-style callbacks. We don't want the
|
|
|
|
|
calling code to have to know about anything but the Packet. What we want there
|
|
|
|
|
is just a call that looks like,
|
|
|
|
|
|
|
|
|
|
@verbatim
|
|
|
|
|
m_promiscSnifferTrace (m_currentPkt);
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
|
|
|
|
What we want to do is to @emph{bind} the @code{Ptr<PcapWriter> writer} to the
|
|
|
|
|
specific callback implementation when it is created and arrange for the
|
|
|
|
|
@code{operator()} of the Callback to provide that parameter for free.
|
|
|
|
|
|
|
|
|
|
We provide the @code{MakeBoundCallback} template function for that purpose. It
|
|
|
|
|
takes the same parameters as the @code{MakeCallback} template function but also
|
|
|
|
|
takes the parameters to be bound. In the case of the example above,
|
|
|
|
|
|
|
|
|
|
@verbatim
|
|
|
|
|
MakeBoundCallback (&CsmaHelper::SniffEvent, pcap));
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
2009-10-18 22:11:29 -07:00
|
|
|
will create a specific callback implementation that knows to add in the extra
|
2009-09-14 18:03:30 -07:00
|
|
|
bound arguments. Conceptually, it extends the specific functor described above
|
|
|
|
|
with one or more bound arguments
|
|
|
|
|
|
|
|
|
|
@verbatim
|
|
|
|
|
template <typname T, typename ARG, typename BOUND_ARG>
|
|
|
|
|
class SpecificFunctor : public Functor
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
SpecificFunctor(T* p, int (T::*_pmi)(ARG arg), BOUND_ARG boundArg)
|
|
|
|
|
{
|
|
|
|
|
m_p = p;
|
|
|
|
|
m_pmi = pmi;
|
|
|
|
|
m_boundArg = boundArg;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual int operator() (ARG arg)
|
|
|
|
|
{
|
|
|
|
|
(*m_p.*m_pmi)(m_boundArg, arg);
|
|
|
|
|
}
|
|
|
|
|
private:
|
|
|
|
|
void (T::*m_pmi)(ARG arg);
|
|
|
|
|
T* m_p;
|
|
|
|
|
BOUND_ARG m_boundArg;
|
|
|
|
|
};
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
|
|
|
|
You can see that when the specific functor is created, the bound argument is saved
|
|
|
|
|
in the functor / callback object itself. When the @code{operator()} is invoked with
|
|
|
|
|
the single parameter, as in
|
|
|
|
|
|
|
|
|
|
@verbatim
|
|
|
|
|
m_promiscSnifferTrace (m_currentPkt);
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
|
|
|
|
the imlpementation of @code{operator()} adds the bound parameter into the actual
|
|
|
|
|
function call:
|
|
|
|
|
|
|
|
|
|
@verbatim
|
|
|
|
|
(*m_p.*m_pmi)(m_boundArg, arg);
|
|
|
|
|
@end verbatim
|
|
|
|
|
|
2009-10-18 22:11:29 -07:00
|
|
|
@node Traced Callbacks
|
|
|
|
|
@section Traced Callbacks
|
|
|
|
|
@cartouche
|
|
|
|
|
Placeholder subsection
|
|
|
|
|
@end cartouche
|
|
|
|
|
@section Callback locations in @command{ns-3}
|
2008-06-15 21:38:13 -07:00
|
|
|
@node Callback locations in ns-3
|
|
|
|
|
@section Callback locations in @command{ns-3}
|
|
|
|
|
|
|
|
|
|
Where are callbacks frequently used in @command{ns-3}? Here are some of the
|
|
|
|
|
more visible ones to typical users:
|
|
|
|
|
|
2009-10-18 22:11:29 -07:00
|
|
|
@itemize @bullet
|
|
|
|
|
@item Socket API
|
|
|
|
|
@item Layer-2/Layer-3 API
|
|
|
|
|
@item Tracing subsystem
|
|
|
|
|
@item API between IP and routing subsystems
|
|
|
|
|
@end itemize
|
2008-06-15 21:38:13 -07:00
|
|
|
|
|
|
|
|
@node Implementation details
|
|
|
|
|
@section Implementation details
|
|
|
|
|
|
2009-09-14 18:03:30 -07:00
|
|
|
The code snippets above are simplistic and only designed to illustrate the mechanism
|
|
|
|
|
itself. The actual Callback code is quite complicated and very template-intense and
|
|
|
|
|
a deep understanding of the code is not required. If interested, expert users may
|
|
|
|
|
find the following useful:
|
2008-06-15 21:38:13 -07:00
|
|
|
|
2009-10-18 22:11:29 -07:00
|
|
|
The code was originally written based on the techniques described in
|
|
|
|
|
@uref{http://www.codeproject.com/cpp/TTLFunction.asp,,
|
|
|
|
|
http://www.codeproject.com/cpp/TTLFunction.asp}.
|
2009-09-14 18:03:30 -07:00
|
|
|
It was subsequently rewritten to follow the architecture outlined in
|
2008-06-15 21:38:13 -07:00
|
|
|
@uref{http://www.amazon.com/Modern-C\%2B\%2B-Design-Programming-Patterns/dp/0201704315/ref=pd_bbs_sr_1/102-0157303-1900156?ie=UTF8\&s=books\&qid=1187982662\&sr=1-1,,Modern C++ Design: Generic Programming and Design Patterns Applied-- Alexandrescu}, chapter 5, "Generalized Functors".
|
|
|
|
|
|
|
|
|
|
This code uses:
|
|
|
|
|
@itemize @bullet
|
|
|
|
|
@item default template parameters to saves users from having to
|
|
|
|
|
specify empty parameters when the number of parameters
|
|
|
|
|
is smaller than the maximum supported number
|
|
|
|
|
@item the pimpl idiom: the Callback class is passed around by
|
|
|
|
|
value and delegates the crux of the work to its pimpl pointer.
|
|
|
|
|
@item two pimpl implementations which derive from CallbackImpl
|
|
|
|
|
FunctorCallbackImpl can be used with any functor-type
|
|
|
|
|
while MemPtrCallbackImpl can be used with pointers to
|
|
|
|
|
member functions.
|
|
|
|
|
@item a reference list implementation to implement the Callback's
|
|
|
|
|
value semantics.
|
|
|
|
|
@end itemize
|
|
|
|
|
|
2009-09-14 18:03:30 -07:00
|
|
|
This code most notably departs from the Alexandrescu implementation in that it
|
|
|
|
|
does not use type lists to specify and pass around the types of the callback
|
|
|
|
|
arguments. Of course, it also does not use copy-destruction semantics and
|
|
|
|
|
relies on a reference list rather than autoPtr to hold the pointer.
|