merge tracing overhaul in trunk

This commit is contained in:
Mathieu Lacage
2007-09-11 12:11:00 +02:00
90 changed files with 5536 additions and 2237 deletions

View File

@@ -6,5 +6,6 @@ build
.*\.sconsign
doc/html.*
doc/latex.*
doc/trace-source-list.h
.lock-wscript
.waf*

View File

@@ -450,7 +450,7 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
INPUT = src doc/main.txt
INPUT = src doc/main.txt doc/trace-source-list.h doc/tracing.h
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
@@ -514,7 +514,7 @@ EXAMPLE_RECURSIVE = NO
# directories that contain image that are included in the documentation (see
# the \image command).
IMAGE_PATH =
IMAGE_PATH = doc
# The INPUT_FILTER tag can be used to specify a program that doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program

View File

@@ -23,6 +23,7 @@
* - \ref config
* - a base class for objects which need to support reference counting
* and QueryInterface: ns3::Object and ns3::InterfaceId
* - a set of low-level trace facilities integrated in the ns3::Object system: \ref tracing
* - a ns3::ComponentManager which can be used to manage the creation
* of any object which derives from ns3::Object through an ns3::ClassId
* - a smart-pointer class ns3::Ptr designed to work together with ns3::Object
@@ -33,11 +34,10 @@
* ns3::Scheduler and ns3::SchedulerFactory
* - a simulator class used to create, schedule and cancel events: ns3::Simulator
*
* The "common" module contains:
* The "core" module contains:
* - a packet class to create and manipulate simulation packets: ns3::Packet, ns3::Header,
* and ns3::Trailer. This packet class also supports per-packet ns3::Tag which are
* globs of data which can be attached to any packet.
* - a set of low-level trace facilities: \ref lowleveltracing
*
* The "node" module contains:
* - a ns3::Node base class which should be subclassed by any new type of

1658
doc/namespace-2.dia Normal file

File diff suppressed because it is too large Load Diff

BIN
doc/namespace-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

204
doc/trace-source-list.h Normal file
View File

@@ -0,0 +1,204 @@
///
/// \ingroup TraceSourceList
/// \brief send ipv4 packet to outgoing interface
/// \param arg1 the trace context associated to the connected trace source.
/// \param arg2 packet sent.
/// \param arg3 index of output ipv4 interface.
///
///
/// The path to this trace source is: /nodes/[0-n]/ipv4/tx.
///
/// The following classes can be extracted from \p arg1 with
/// ns3::TraceContext::GetElement:
/// - ns3::NodeListIndex
/// - ns3::Ipv4L3ProtocolTraceContextElement
void TraceSinkCallback0 (const TraceContext & arg1, const Packet & arg2, uint32_t arg3);
///
/// \ingroup TraceSourceList
/// \brief receive ipv4 packet from incoming interface
/// \param arg1 the trace context associated to the connected trace source.
/// \param arg2 packet received.
/// \param arg3 index of input ipv4 interface.
///
///
/// The path to this trace source is: /nodes/[0-n]/ipv4/rx.
///
/// The following classes can be extracted from \p arg1 with
/// ns3::TraceContext::GetElement:
/// - ns3::NodeListIndex
/// - ns3::Ipv4L3ProtocolTraceContextElement
void TraceSinkCallback1 (const TraceContext & arg1, const Packet & arg2, uint32_t arg3);
///
/// \ingroup TraceSourceList
/// \brief drop ipv4 packet
/// \param arg1 the trace context associated to the connected trace source.
/// \param arg2 packet dropped.
///
///
/// The path to this trace source is: /nodes/[0-n]/ipv4/drop.
///
/// The following classes can be extracted from \p arg1 with
/// ns3::TraceContext::GetElement:
/// - ns3::NodeListIndex
/// - ns3::Ipv4L3ProtocolTraceContextElement
void TraceSinkCallback2 (const TraceContext & arg1, const Packet & arg2);
///
/// \ingroup TraceSourceList
/// \brief store packet in queue
/// \param arg1 the trace context associated to the connected trace source.
/// \param arg2 packet queued.
///
///
/// The path to this trace source is: /nodes/[0-n]/devices/[0-n]/queue/enqueue.
///
/// The following classes can be extracted from \p arg1 with
/// ns3::TraceContext::GetElement:
/// - ns3::NodeListIndex
/// - ns3::NodeNetDeviceIndex
/// - ns3::QueueTraceType
void TraceSinkCallback3 (const TraceContext & arg1, const Packet & arg2);
///
/// \ingroup TraceSourceList
/// \brief remove packet from queue
/// \param arg1 the trace context associated to the connected trace source.
/// \param arg2 packet dequeued.
///
///
/// The path to this trace source is: /nodes/[0-n]/devices/[0-n]/queue/dequeue.
///
/// The following classes can be extracted from \p arg1 with
/// ns3::TraceContext::GetElement:
/// - ns3::NodeListIndex
/// - ns3::NodeNetDeviceIndex
/// - ns3::QueueTraceType
void TraceSinkCallback4 (const TraceContext & arg1, const Packet & arg2);
///
/// \ingroup TraceSourceList
/// \brief drop packet from queue
/// \param arg1 the trace context associated to the connected trace source.
/// \param arg2 packet dropped.
///
///
/// The path to this trace source is: /nodes/[0-n]/devices/[0-n]/queue/drop.
///
/// The following classes can be extracted from \p arg1 with
/// ns3::TraceContext::GetElement:
/// - ns3::NodeListIndex
/// - ns3::NodeNetDeviceIndex
/// - ns3::QueueTraceType
void TraceSinkCallback5 (const TraceContext & arg1, const Packet & arg2);
///
/// \ingroup TraceSourceList
/// \brief receive MAC packet
/// \param arg1 the trace context associated to the connected trace source.
/// \param arg2 packet received.
///
///
/// The path to this trace source is: /nodes/[0-n]/devices/[0-n]/rx.
///
/// The following classes can be extracted from \p arg1 with
/// ns3::TraceContext::GetElement:
/// - ns3::NodeListIndex
/// - ns3::NodeNetDeviceIndex
/// - ns3::PointToPointTraceType
void TraceSinkCallback6 (const TraceContext & arg1, const Packet & arg2);
///
/// \ingroup TraceSourceList
/// \brief receive MAC packet
/// \param arg1 the trace context associated to the connected trace source.
/// \param arg2 packet received.
///
///
/// The path to this trace source is: /nodes/[0-n]/devices/[0-n]/rx.
///
/// The following classes can be extracted from \p arg1 with
/// ns3::TraceContext::GetElement:
/// - ns3::NodeListIndex
/// - ns3::NodeNetDeviceIndex
/// - ns3::CsmaTraceType
void TraceSinkCallback7 (const TraceContext & arg1, const Packet & arg2);
///
/// \ingroup TraceSourceList
/// \brief drop MAC packet
/// \param arg1 the trace context associated to the connected trace source.
/// \param arg2 packet dropped.
///
///
/// The path to this trace source is: /nodes/[0-n]/devices/[0-n]/drop.
///
/// The following classes can be extracted from \p arg1 with
/// ns3::TraceContext::GetElement:
/// - ns3::NodeListIndex
/// - ns3::NodeNetDeviceIndex
/// - ns3::CsmaTraceType
void TraceSinkCallback8 (const TraceContext & arg1, const Packet & arg2);
///
/// \ingroup TraceSourceList
/// \brief The value of the speed vector changed
/// \param arg1 the trace context associated to the connected trace source.
/// \param arg2 the mobility model whose course changed.
///
///
/// The path to this trace source is: /nodes/[0-n]/$MobilityModelNotifier/course-change.
///
/// The following classes can be extracted from \p arg1 with
/// ns3::TraceContext::GetElement:
/// - ns3::NodeListIndex
void TraceSinkCallback9 (const TraceContext & arg1, Ptr<const MobilityModel> arg2);
///
/// \ingroup TraceSourceList
/// \brief send ipv4 packet to outgoing interface
/// \param arg1 the trace context associated to the connected trace source.
/// \param arg2 packet sent.
/// \param arg3 index of output ipv4 interface.
///
///
/// The path to this trace source is: /nodes/[0-n]/$Ipv4L3Protocol/tx.
///
/// The following classes can be extracted from \p arg1 with
/// ns3::TraceContext::GetElement:
/// - ns3::NodeListIndex
/// - ns3::Ipv4L3ProtocolTraceContextElement
void TraceSinkCallback10 (const TraceContext & arg1, const Packet & arg2, uint32_t arg3);
///
/// \ingroup TraceSourceList
/// \brief receive ipv4 packet from incoming interface
/// \param arg1 the trace context associated to the connected trace source.
/// \param arg2 packet received.
/// \param arg3 index of input ipv4 interface.
///
///
/// The path to this trace source is: /nodes/[0-n]/$Ipv4L3Protocol/rx.
///
/// The following classes can be extracted from \p arg1 with
/// ns3::TraceContext::GetElement:
/// - ns3::NodeListIndex
/// - ns3::Ipv4L3ProtocolTraceContextElement
void TraceSinkCallback11 (const TraceContext & arg1, const Packet & arg2, uint32_t arg3);
///
/// \ingroup TraceSourceList
/// \brief drop ipv4 packet
/// \param arg1 the trace context associated to the connected trace source.
/// \param arg2 packet dropped.
///
///
/// The path to this trace source is: /nodes/[0-n]/$Ipv4L3Protocol/drop.
///
/// The following classes can be extracted from \p arg1 with
/// ns3::TraceContext::GetElement:
/// - ns3::NodeListIndex
/// - ns3::Ipv4L3ProtocolTraceContextElement
void TraceSinkCallback12 (const TraceContext & arg1, const Packet & arg2);

576
doc/tracing.h Normal file
View File

@@ -0,0 +1,576 @@
/**
* \defgroup TraceSourceList List of trace sources
*/
/**
* \defgroup tracing Tracing
*
* The flexibility of the ns-3 tracing system comes at the cost of quite
* a bit of complexity so, before trying to use the low-level aspects
* of the tracing API, it is important to focus on some basic definitions:
*
* - A trace source is an object instance which can report trace events
* to a set of listening trace sinks.
*
* - A trace sink is a user-provided callback (a function) which can
* be connected to a set of trace sources to receive the events generated
* by each trace source.
*
* - A trace resolver is an object which allows users to establish
* connections between a set of trace sources and a set of trace sinks.
*
* \section TraceSource Generating Trace Events
*
* So, what does it look like in practice ? First, let's look at trace
* sources. We have two types of trace sources: numeric, and, normal
* trace sources. Numeric trace sources behave as normal c++ integers
* or c++ floating point numbers except that they report as trace events
* each change of their value. For example:
* \code
* class MyModel
* {
* public:
* void DoSomething (void)
* {
* // use the "int" trace source just
* // like any other "int" variable.
* m_cwnd *= 2;
* m_cwnd += 4;
* if (m_cwnd > 100)
* {
* // do something.
* }
* }
* private:
* // declare an instance of a "int" trace source
* SVTraceSource<int> m_cwnd;
* };
* \endcode
* Normal trace sources, on the other hand, allow you to trace the
* call of arbitrary functions and methods, as shown below. They are
* typically used to track "rx", "tx", or "drop" events but could
* also be used to track route change events, or position change
* events:
* \code
* class MyModel
* {
* public:
* void DoSomething (Packet packet)
* {
* // report this event on packet
* m_doSomething (packet);
* // do something
* }
* private:
* // report every "something" function call.
* CallbackTraceSource<Packet> m_doSomething;
* };
* \endcode
* Every type of trace source derives from the ns3::TraceSource base class.
* As of today, the set of concrete subclasses is relatively short:
* ns3::CallbackTraceSource, ns3::SvTraceSource, ns3::UvTraceSource, and,
* ns3::FvTraceSource.
*
* \section TraceSink Receiving Trace Events
*
* To receive these trace events, a user should specify a set of trace sinks.
* For example, to receive the "int" and the "something" events shown in the
* examples above, a user would declare the following functions:
* \code
* // oldValue and newValue contain the previous and new values of
* // the connected SVTraceSource<int> trace source.
* void
* CwndTraceSink (const TraceContext &context, int64_t oldValue, int64_t newValue)
* {
* // for example, print the new value:
* std::cout << "cwnd=" << newValue << std::endl;
* }
* void
* DoSomethingTraceSink (const TraceContext &context, Packet packet)
* {
* // for example, print the arguments
* std::cout << "packet " << packet << std::endl;
* }
* \endcode
* Each of these sink function takes, as a first argument, a reference to a
* const TraceContext object. This context object contains information which
* describes the instance of the connected trace source: that information is
* setup during the connection process and does not change afterwards
* The type and the number of the other arguments to each trace sink depends
* on the type of the connected trace source: it conveys per-event information
* from the trace source to the trace sink. For example, UVTraceSource and
* SVTraceSource trace sources require two extra arguments. The former requires
* two unsigned 64 bit integers while the latter requires two signed 64 bit
* integers. More generally, users can consult the \ref TraceSourceList
* to figure out the arguments which a trace sink is required to receive
* for each trace source: a signature of the user trace sink must match
* _exactly_ the signature documented in the \ref TraceSourceList.
*
*
* \section TraceSourceSimpleExport A simple way to connect Trace Sources with Trace Sinks
*
* The crux of the complexity of the ns-3 tracing system comes from its
* flexible system used to connect trace sources to trace sinks but what is really
* nice about it is that it is not necessary to use it to setup simple traces.
*
* The simplest way to export a set of trace sources to a user, for example,
* during the early prototyping phases of a system, is to add a set of public methods
* to give to your users access to the trace source object instances you use to generate
* trace events:
* \code
* class MyModel
* {
* public:
* void DoSomething (Packet packet)
* {
* // report this event on packet
* m_doSomething (packet);
* // do something
* }
* CallbackTraceSource<Packet> *PeekSomethingTraceSource (void) const
* {
* return &m_doSomething
* }
* private:
* // report every "something" function call.
* CallbackTraceSource<Packet> m_doSomething;
* };
* \endcode
* If your users hold a pointer to an instance of MyModel, and if they want to connect
* a MySomethingSink, they can simply do the following which invokes the
* TraceSource::AddCallback method and creates a Callback object from the user's
* sink with the MakeCallback function.
* \code
* void
* MySomethingSink (const TraceContext &context, Packet packet)
* {
* // do whatever you want.
* }
* MyModel *model = ...;
* CallbackTraceSource<Packet> *source = model->PeekSomethingTraceSource ();
* source->AddCallback (MakeCallback (&MySomethingSink));
* \endcode
*
* The full power of the tracing system comes however from its ns3::NodeList::Connect
* method which is described in the following sections.
*
* \section TraceConnection Connecting Trace Sources to Trace Sinks
*
* If a trace source is integrated in the ns-3 trace connection facility, a user
* should call the ns3::NodeList::Connect method to establish a connection between
* a trace sink and a set of matching trace sources. The second argument to that
* method is a callback to the user's trace sink.
* That callback is easy to construct: call ns3::MakeCallback and you are done. The
* first argument is a string whose format is similar to a unix path and which is
* used to uniquely identify the set of trace sources you want to connect to.
* The set of acceptable path strings is also documented in the \ref TraceSourceList.
*
* So, what does this look like from the perspective of a user ? If we wanted to
* connect to a trace source defined somewhere deep into the a set of NetDevice objects
* located in some nodes of the system, we could write the following:
* \code
* void
* DoSomethingTraceSink (const TraceContext &context, Packet packet)
* {
* // for example, print the arguments
* std::cout << "packet: " << packet << std::endl;
* }
* // connect the above sink to a matching trace source
* NodeList::Connect ("/nodes/* /devices/* /rx", MakeCallback &DoSomethingTraceSink);
* \endcode
*
* The connection path string "/nodes/* /devices/* /rx" matches the "rx" trace source
* located in every netdevice located in every node. The syntax of that path string
* is loosely based on regular expressions so, a user could conceivably connect
* to the trace sources present in only one node identified by node index:
* "/nodex/3/devices/* /rx".
*
* The matching algorithm used here is very useful since it allows you to connect
* at once a large set of trace sources to a single sink but it introduces another
* problem: it becomes impossible when you receive an event in your trace sink to
* know from _which_ trace source the event is coming from. In our example, the
* trace source might be coming from the NetDevice number 2 of Node 10 or Netdevice
* number 0 of Node 5. In both cases, you might need to know which of these NetDevice
* is generating this event, if only to generate some ascii trace dump. Another
* similar use-case is that you might have connected the same trace sink to
* multiple types of events which have the same signature: it is quite common
* to receive all tx, rx, and drop events in the same trace sink and that would be
* quite trivial to achieve with a string such as: "/nodes/* /devices/* /*"
*
* The source of a trace event can be retrieved from a trace sink using
* different means: the simplest
* way to get this information is to use the builtin printing facility of
* the TraceContext object:
* \code
* void
* DoSomethingTraceSink (const TraceContext &context, Packet packet)
* {
* // for example, print the arguments
* std::cout << "context=\"" << context << "\" packet: " << packet << std::endl;
* }
* \endcode
* The above code is going to generate output which looks like the following:
* \code
* context="nodeid=2 device=0 dev-rx" packet: IPV4(tos 0x0 ttl 64 id 0 offset ...
* context="nodeid=1 device=0 dev-rx" packet: IPV4(tos 0x0 ttl 64 id 0 offset ...
* ...
* \endcode
*
* Another more advanced way to get information out of a TraceContext is to call its
* ns3::TraceContext::GetElement method. This method takes as its first and only
* argument an instance of the object we want to read and the list of available
* object instances we can read from a TraceContext is documented, once again,
* in the \ref TraceSourceList. For example, we could write the following to
* generate adhoc trace output:
* \code
* void DeviceRxSink (const TraceContext &context, const Packet &packet)
* {
* NodeListIndex nodeIndex;
* NodeNetDeviceIndex deviceIndex;
* context.GetElement (nodeIndex);
* context.GetElement (deviceIndex);
* std::cout << "node-index=" << nodeIndex.Get ();
* std::cout << ", device-index=" << deviceIndex.Get ();
* std::cout << ", packet: " << packet;
* std::cout << std::endl;
* }
* \endcode
*
* \section ExportingTraceSources Exporting new Trace Sources
*
* Using existing trace sources to connect them to a set of adhoc trace sinks
* is not really complicated but, setting up new trace sources which can hook
* in this automatic connection system is a bit more complicated.
*
* So far, we know that a model author can generate trace events really easily:
* \code
* class MyModel
* {
* public:
* void DoSomething (Packet packet)
* {
* // report this event on packet with value
* m_doSomething (packet);
* // do something
* }
* private:
* // report every "something" function call.
* CallbackTraceSource<Packet> m_doSomething;
* };
* \endcode
*
* To make these new trace sources available to the rest of the connection system,
* the first step is to make sure that your model object derives from the ns3::Object
* base class either directly (as shown below) or indirectly through another base class:
* \code
* class MyModel : public Object {...};
* // or:
* class SomeOtherObject : public Object {...};
* class MyModel : public SomeOtherObject {...};
* \endcode
*
* This is pretty trivial and lays the ground for the second step: overriding the
* ns3::Object::GetTraceResolver method:
* \code
* class MyModel : public MyParent
* {
* public:
* // declare overriden method
* virtual Ptr<TraceResolver> GetTraceResolver (void) const;
* private:
* // the new trace source to export.
* CallbackTraceSource<Packet> m_rxSource;
* };
* \endcode
*
* To implement this method, you could attempt to implement a new subclass of
* the ns3::TraceResolver base class and return an instance from this method but
* this would be very hard. Instead, you should use the helper class
* ns3::CompositeTraceResolver to register your trace sources and chain up to
* your parent:
* \code
* Ptr<TraceResolver>
* MyModel::GetTraceResolver (void) const
* {
* // create an empty trace resolver
* Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
* // register m_rxSource
* resolver->AddSource ("rx", // the name of the trace source in the path string
* TraceDoc ("some help text to explain the purpose of this trace source",
* "Packet", // the type of the first argument to the trace source
* "the purpose of the first argument",
* "type-of-second-argument", "purpose-of-second-argument"),
* m_rxSource // the trace source itself is registered
* );
* // make sure we include the trace sources implemented in the parent.
* resolver->SetParentResolver (MyParent::GetTraceResolver ());
* return resolver;
* }
* \endcode
*
* Once you have written that code, you must make sure that this new method GetTraceResolver
* is going to be called at some point by the tracing system. If your model is located somewhere
* deep in MAC or PHY layer, that is, it is part of a NetDevice implementation, all you
* have to do is to make sure that your model is registered as a "composite" of your NetDevice
* subclass:
* \code
* class MyNetDevice : public NetDevice
* {
* public:
* Ptr<TraceResolver> GetTraceResolver (void) const;
* private:
* Ptr<MyModel> m_model;
* };
*
* Ptr<TraceResolver>
* MyNetDevice::GetTraceResolver (void) const
* {
* Ptr<CompositeTraceResolver> resolver = ...;
* // register other trace source
* ...
* // register now your model as a "composite"
* resolver->AddComposite ("my-model", m_model);
* // chain up to parent.
* resolver->SetParentResolver (NetDevice::GetTraceResolver ());
* return resolver;
* }
* \endcode
*
* The code above will make your "rx" trace source appear under the
* /nodes/xx/devices/xx/my-model/rx namespace path.
*
* If you have implemented a new layer 3 or 4 protocol object, the process to
* export your trace sources is quite similar. You need to subclass from
* ns3::Object, override the ns3::Object::GetTraceResolver method, make
* sure you chain up to your parent's GetTraceResolver method, and, finally,
* make sure that someone calls your new GetTraceResolver method. How to accomplish
* the latter should be documented in the node's API documentation which describes
* how to implement a new layer 3 or 4 protocol object.
*
* \section AdvancedTraceContext Creating new Trace Context Elements
*
* The last important feature which model developers need to understand
* is how to provide extra context information to trace sinks. For example,
* if your model exports both rx and tx trace sources which share the same
* signature, it is quite natural for a user to connect to a single trace sink
* to both of them with a trace path string such as "/nodes/* /devices/* /(rx|tx)".
* In this case, it becomes necessary to be able, from the trace sink function,
* to tell which event triggered the call to the trace sink: a rx or a tx event.
*
* That example is detailed below with a TX, a RX, and a DROP source:
* \code
* class MyModel
* {
* private:
* CallbackTraceSource<Packet> m_rxSource;
* CallbackTraceSource<Packet> m_txSource;
* CallbackTraceSource<Packet> m_dropSource;
* };
* \endcode
* When a single sink is connected to all 3 sources here, one might want
* to write code like the following:
* \code
* void DeviceRxSink (const TraceContext &context, const Packet &packet)
* {
* switch (type) {
* case RX:
* std::cout << "rx" << std::endl;
* break;
* case TX:
* std::cout << "tx" << std::endl;
* break;
* case DROP:
* std::cout << "drop" << std::endl;
* break;
* }
* \endcode
*
* \subsection AdvancedTraceContextSimpleSolution The simple solution
*
* The simplest way to do achieve the result shown above is to include
* in the trace source an extra explicit argument which describes the source event:
* - define a small enum with 3 values
* - change the signature of m_rxSource, m_txSource, and m_dropSource to include
* the enum
* - pass the enum value in each event
*
* The resulting code is shown below:
* \code
* class MyModel
* {
* public:
* // define the trace type enum.
* enum TraceType {
* RX,
* TX,
* DROP
* };
* private:
* // generate events
* void NotifyRxPacket (Packet p) {
* m_rxSource (p, MyModel::RX);
* }
* void NotifyTxPacket (Packet p) {
* m_rxSource (p, MyModel::TX);
* }
* void NotifyDropPacket (Packet p) {
* m_rxSource (p, MyModel::DROP);
* }
* CallbackTraceSource<Packet,enum TraceType> m_rxSource;
* CallbackTraceSource<Packet,enum TraceType> m_txSource;
* CallbackTraceSource<Packet,enum TraceType> m_dropSource;
* };
* \endcode
* These 3 new sources can be connected easily to a new trace sink:
* \code
* void ASimpleTraceSink (const TraceContext &context, const Packet &packet, enum MyModel::TraceType type)
* {
* // here, read the "type" argument
* }
* \endcode
*
* This solution works but it makes it impossible to connect a single trace sink to a set
* of trace sources which represent "rx" events in different NetDevice objects since
* each of them will define a different enum type with different values: since the
* trace sink signature must match exactly the trace source signature, it is impossible
* to connect at the same time to all "rx" events of different NetDevice.
*
* \subsection AdvancedTraceContextFancySolution The more complex and generic solution
*
* There is, hopefully, a way to get the best of both worlds, that is, to allow a
* user to connect to a lot of trace source events of the same kind but coming from different
* implementations and to allow the user to differentiate between these different
* implementations.
*
* Rather than define an adhoc enum type with a list of trace sources, you can also
* define a new ns3::TraceContextElement for your source sources. For example, if you
* define a new MyModelTraceType class which contains the type of trace, your users can
* then write trace sink code which looks like this:
* \code
* void AFancyTraceSink (const TraceContext &context, const Packet &packet)
* {
* MyModelTraceType type;
* if (context.GetElement (type))
* {
* switch (type.Get ())
* {
* case MyModelTraceType::RX:
* std::cout << "rx" << std::endl;
* break;
* case MyModelTraceType::TX:
* std::cout << "tx" << std::endl;
* break;
* case MyModelTraceType::DROP:
* std::cout << "drop" << std::endl;
* break;
* }
* }
* }
* \endcode
*
* Of course, since the type of trace is stored in the TraceContext, your users can
* also take the shortcut which uses the printing functionality of the TraceContext:
* \code
* void ALessFancyTraceSink (const TraceContext &context, const Packet &packet)
* {
* std::cout << "context=\"" << context << "\" packet: " << packet << std::endl;
* }
* \endcode
* which will generate something like the following when the trace source comes
* from MyModel:
* \code
* context="my-model-rx" packet: ...
* \endcode
*
* The first step to achieve this is to define and implement a new
* subclass of the ns3::TraceContextElement base class. The exact list of
* public methods which must be implemented is described in the API
* documentation of the ns3::TraceContextElement class.
* \code
* class MyModelTraceType : public TraceContextElement
* {
* public:
* enum Type {
* RX,
* TX,
* DROP
* };
* // called from MyModel::GetTraceResolver
* MyModelTraceType (enum Type type);
* // called from trace sink
* enum Type Get (void) const;
* // needed by the tracing subsystem
* static uint16_t GetUid (void);
* // needed by the tracing subsystem to
* // print the content of a TraceContext
* void Print (std::ostream &os) const;
* // needed by the tracing subsystem to
* // generate the doxygen documentation.
* std::string GetTypeName (void) const;
* private:
* enum Type m_type;
* };
* \endcode
* The implementation does not require much thinking:
* \code
* MyModelTraceType::MyModelTraceType (enum Type type)
* : m_type (type)
* {}
* enum Type
* MyModelTraceType::Get (void) const
* {
* return m_type;
* }
* uint16_t
* MyModelTraceType::GetUid (void)
* {
* // use protected TraceContextElement::AllocateUid method
* // the input string is used to uniquely identify this new subclass
* static uint16_t uid = AllocateUid<MyModelTraceType> ("ns3::MyModelTraceType");
* return uid;
* }
* void
* MyModelTraceType::Print (std::ostream &os) const
* (
* // this method is invoked by the print function of a TraceContext
* // if it contains an instance of this TraceContextElement.
* switch (m_type) {
* case RX: os << "rx"; break;
* // ...
* }
* )
* std::string
* MyModelTraceType::GetTypeName (void) const
* {
* // This method should return a fully-qualified c++ typename
* // This method is used only for documentation purposes to
* // generate the content of the Trace Source List.
* return "ns3::MyModelTraceType";
* }
* \endcode
*
* Once this subclass is implemented, the work is almost completed: you
* just need to pass an instance of that class as the last argument of
* the ns3::CompositeTraceResolver::AddSource method as shown below:
* \code
* Ptr<TraceResolver>
* MyModel::GetTraceResolver (void) const
* {
* // create an empty trace resolver
* Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
* // register m_rxSource
* resolver->AddSource ("rx", // the name of the trace source in the path string
* TraceDoc ("some help text to explain the purpose of this trace source",
* "Packet", // the type of the first argument to the trace source
* "the purpose of the first argument",
* "type-of-second-argument", "purpose-of-second-argument"),
* m_rxSource, // the trace source itself is registered
* // the TraceContextElement associated to this trace source.
* MyModelTraceType (MyModelTraceType::RX)
* );
* // make sure we include the trace sources implemented in the parent.
* resolver->SetParentResolver (MyParent::GetTraceResolver ());
* return resolver;
* }
* \endcode
*/

View File

@@ -15,7 +15,7 @@
using namespace ns3;
static void
CourseChange (Ptr<const MobilityModel> position)
CourseChange (const TraceContext &context, Ptr<const MobilityModel> position)
{
Position pos = position->Get ();
std::cout << Simulator::Now () << ", pos=" << position << ", x=" << pos.x << ", y=" << pos.y
@@ -39,7 +39,7 @@ int main (int argc, char *argv[])
for (uint32_t i = 0; i < 10000; i++)
{
Ptr<MobilityModelNotifier> notifier = Create<MobilityModelNotifier> ();
notifier->RegisterListener (MakeCallback (&CourseChange));
notifier->TraceConnect ("/course-change", MakeCallback (&CourseChange));
objects.push_back (notifier);
}

View File

@@ -1,95 +0,0 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#ifndef ARRAY_TRACE_RESOLVER_H
#define ARRAY_TRACE_RESOLVER_H
#include <stdint.h>
#include <string>
#include "ns3/callback.h"
#include "trace-resolver.h"
namespace ns3 {
/**
* \brief a helper class to offer trace resolution for an array of objects.
* \ingroup lowleveltracing
*/
template <typename T, typename INDEX>
class ArrayTraceResolver : public TraceResolver
{
public:
/**
* \param context trace context associated to this trace resolver
* \param getSize callback which returns dynamically the size of underlying array
* \param get callback which returns any element in the underlying array
*
* Construct a trace resolver which can match any input integer
* against an element in an array. The array is accessed using a
* pair of callbacks. It is the responsability of the user to
* provide two such callbacks whose job is to adapt the array
* API to the resolver needs. Each element of the array is expected
* to provide a method named CreateTraceResolver which takes as
* only argument a reference to a const TraceContext and returns
* a pointer to a TraceResolver. i.e. the signature is:
* TraceResolver * (*) (TraceContext const &)
*/
ArrayTraceResolver (TraceContext const &context,
Callback<uint32_t> getSize,
Callback<T, uint32_t> get);
private:
virtual TraceResolverList DoLookup (std::string id) const;
Callback<uint32_t> m_getSize;
Callback<T, uint32_t> m_get;
};
}//namespace ns3
namespace ns3 {
template <typename T, typename INDEX>
ArrayTraceResolver<T,INDEX>::ArrayTraceResolver (TraceContext const &context,
Callback<uint32_t> getSize,
Callback<T, uint32_t> get)
: TraceResolver (context),
m_getSize (getSize),
m_get (get)
{}
template <typename T, typename INDEX>
TraceResolver::TraceResolverList
ArrayTraceResolver<T,INDEX>::DoLookup (std::string id) const
{
TraceResolverList list;
if (id == "*")
{
for (uint32_t i = 0; i < m_getSize (); i++)
{
TraceContext context = GetContext ();
INDEX index = i;
context.Add (index);
list.push_back (m_get (i)->CreateTraceResolver (context));
}
}
return list;
}
}//namespace ns3
#endif /* ARRAY_TRACE_RESOLVER_H */

View File

@@ -1,157 +0,0 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2005,2006,2007 INRIA
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#ifndef CALLBACK_TRACE_H
#define CALLBACK_TRACE_H
#include <list>
#include "ns3/callback.h"
#include "ns3/fatal-error.h"
#include "trace-context.h"
namespace ns3 {
/**
* \brief log arbitrary number of parameters to a matching ns3::Callback
* \ingroup lowleveltracing
*
* Whenever operator () is invoked on this class, the call and its arguments
* are forwarded to the internal matching ns3::Callback.
*/
template<typename T1 = empty, typename T2 = empty,
typename T3 = empty, typename T4 = empty>
class CallbackTraceSource {
public:
CallbackTraceSource ();
void AddCallback (CallbackBase const & callback, TraceContext const & context);
void RemoveCallback (CallbackBase const & callback);
void operator() (void);
void operator() (T1 a1);
void operator() (T1 a1, T2 a2);
void operator() (T1 a1, T2 a2, T3 a3);
void operator() (T1 a1, T2 a2, T3 a3, T4 a4);
private:
typedef std::list<Callback<void,TraceContext const &,T1,T2,T3,T4> > CallbackList;
TraceContext m_context;
CallbackList m_callbackList;
};
}; // namespace ns3
// implementation below.
namespace ns3 {
template<typename T1, typename T2,
typename T3, typename T4>
CallbackTraceSource<T1,T2,T3,T4>::CallbackTraceSource ()
: m_callbackList ()
{}
template<typename T1, typename T2,
typename T3, typename T4>
void
CallbackTraceSource<T1,T2,T3,T4>::AddCallback (CallbackBase const & callback,
TraceContext const &context)
{
Callback<void,TraceContext const &,T1,T2,T3,T4> cb;
cb.Assign (callback);
m_context.Add (context);
m_callbackList.push_back (cb);
}
template<typename T1, typename T2,
typename T3, typename T4>
void
CallbackTraceSource<T1,T2,T3,T4>::RemoveCallback (CallbackBase const & callback)
{
for (typename CallbackList::iterator i = m_callbackList.begin ();
i != m_callbackList.end (); /* empty */)
{
if ((*i).IsEqual (callback))
{
i = m_callbackList.erase (i);
}
else
{
i++;
}
}
}
template<typename T1, typename T2,
typename T3, typename T4>
void
CallbackTraceSource<T1,T2,T3,T4>::operator() (void)
{
for (typename CallbackList::iterator i = m_callbackList.begin ();
i != m_callbackList.end (); i++)
{
(*i) (m_context);
}
}
template<typename T1, typename T2,
typename T3, typename T4>
void
CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1)
{
for (typename CallbackList::iterator i = m_callbackList.begin ();
i != m_callbackList.end (); i++)
{
(*i) (m_context, a1);
}
}
template<typename T1, typename T2,
typename T3, typename T4>
void
CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1, T2 a2)
{
for (typename CallbackList::iterator i = m_callbackList.begin ();
i != m_callbackList.end (); i++)
{
(*i) (m_context, a1, a2);
}
}
template<typename T1, typename T2,
typename T3, typename T4>
void
CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1, T2 a2, T3 a3)
{
for (typename CallbackList::iterator i = m_callbackList.begin ();
i != m_callbackList.end (); i++)
{
(*i) (m_context, a1, a2, a3);
}
}
template<typename T1, typename T2,
typename T3, typename T4>
void
CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1, T2 a2, T3 a3, T4 a4)
{
for (typename CallbackList::iterator i = m_callbackList.begin ();
i != m_callbackList.end (); i++)
{
(*i) (m_context, a1, a2, a3, a4);
}
}
}//namespace ns3
#endif /* CALLBACK_TRACE_H */

View File

@@ -1,375 +0,0 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "composite-trace-resolver.h"
namespace ns3 {
CompositeTraceResolver::CompositeTraceResolver (TraceContext const &context)
: TraceResolver (context)
{}
CompositeTraceResolver::~CompositeTraceResolver ()
{}
void
CompositeTraceResolver::Add (std::string name,
Callback<TraceResolver *,TraceContext const &> createResolver)
{
TraceContext traceContext = GetContext ();
DoAdd (name, createResolver, traceContext);
}
void
CompositeTraceResolver::DoAdd (std::string name,
Callback<TraceResolver *,TraceContext const &> createResolver,
TraceContext const &context)
{
struct CallbackTraceSourceItem item;
item.name = name;
item.createResolver = createResolver;
item.context = context;
m_items.push_back (item);
}
TraceResolver::TraceResolverList
CompositeTraceResolver::DoLookup (std::string id) const
{
if (id == "*")
{
TraceResolver::TraceResolverList list;
for (TraceItems::const_iterator i = m_items.begin (); i != m_items.end (); i++)
{
list.push_back (i->createResolver (i->context));
}
return list;
}
std::string::size_type start, end;
start = id.find_first_of ("(", 0);
end = id.find_first_of (")", 0);
if (start != 0 || end != (id.size ()-1))
{
for (TraceItems::const_iterator i = m_items.begin (); i != m_items.end (); i++)
{
if (i->name == id)
{
TraceResolver::TraceResolverList list;
list.push_back (i->createResolver (i->context));
return list;
}
}
}
std::list<std::string> names;
std::string alternatives = std::string (id, start+1, end-1);
std::string::size_type next, cur;
next = 0;
cur = 0;
while (true)
{
std::string element;
next = alternatives.find ("|", cur);
if (next == std::string::npos)
{
element = std::string (alternatives, cur, alternatives.size ());
names.push_back (element);
break;
}
element = std::string (alternatives, cur, next);
names.push_back (element);
cur = next + 1;
}
TraceResolver::TraceResolverList list;
for (std::list<std::string>::const_iterator i = names.begin (); i != names.end (); i++)
{
for (TraceItems::const_iterator j = m_items.begin (); j != m_items.end (); j++)
{
if (j->name == *i)
{
list.push_back (j->createResolver (j->context));
break;
}
}
}
return list;
}
}//namespace ns3
#ifdef RUN_SELF_TESTS
#include "ns3/test.h"
#include "trace-context-element.h"
namespace ns3 {
class TraceSourceTest : public TraceContextElement
{
public:
enum Sources {
DOUBLEA,
DOUBLEB,
SUBRESOLVER,
};
static uint16_t GetUid (void)
{static uint16_t uid = AllocateUid<TraceSourceTest> ("TraceSourceTest"); return uid;}
void Print (std::ostream &os)
{os << "tracesource=";
if (m_sources == DOUBLEA) {os << "doubleA";}
else if (m_sources == DOUBLEB) {os << "doubleB";}
else if (m_sources == SUBRESOLVER) {os << "subresolver";}
}
TraceSourceTest () : m_sources (TraceSourceTest::DOUBLEA) {}
TraceSourceTest (enum Sources sources) :m_sources (sources) {}
bool IsDoubleA (void) {return m_sources == TraceSourceTest::DOUBLEA;}
bool IsDoubleB (void) {return m_sources == TraceSourceTest::DOUBLEB;}
private:
enum TraceSourceTest::Sources m_sources;
};
class SubTraceSourceTest : public TraceContextElement
{
public:
enum Sources {
INT,
};
static uint16_t GetUid (void)
{static uint16_t uid = AllocateUid<SubTraceSourceTest> ("SubTraceSourceTest"); return uid;}
void Print (std::ostream &os)
{os << "subtracesource=int";}
SubTraceSourceTest () : m_sources (SubTraceSourceTest::INT) {}
SubTraceSourceTest (enum Sources sources) : m_sources (sources) {}
private:
enum Sources m_sources;
};
class CompositeTraceResolverTest : public Test
{
public:
CompositeTraceResolverTest ();
virtual ~CompositeTraceResolverTest ();
virtual bool RunTests (void);
private:
void TraceDouble (TraceContext const &context, double v);
void TraceInt (TraceContext const &context, int v);
TraceResolver *CreateSubResolver (TraceContext const &context);
bool m_gotDoubleA;
bool m_gotDoubleB;
CallbackTraceSource<int> m_traceInt;
bool m_gotInt;
};
CompositeTraceResolverTest::CompositeTraceResolverTest ()
: Test ("CompositeTraceResolver")
{}
CompositeTraceResolverTest::~CompositeTraceResolverTest ()
{}
void
CompositeTraceResolverTest::TraceDouble (TraceContext const &context, double v)
{
TraceSourceTest source;
context.Get (source);
if (source.IsDoubleA ())
{
m_gotDoubleA = true;
}
else if (source.IsDoubleB ())
{
m_gotDoubleB = true;
}
else
{
NS_FATAL_ERROR ("should not get any other trace source in this sink");
}
}
void
CompositeTraceResolverTest::TraceInt (TraceContext const &context, int v)
{
m_gotInt = true;
}
TraceResolver *
CompositeTraceResolverTest::CreateSubResolver (TraceContext const &context)
{
CompositeTraceResolver *subresolver = new CompositeTraceResolver (context);
subresolver->Add ("trace-int", m_traceInt,
SubTraceSourceTest (SubTraceSourceTest::INT));
return subresolver;
}
bool
CompositeTraceResolverTest::RunTests (void)
{
bool ok = true;
CallbackTraceSource<double> traceDoubleA;
CallbackTraceSource<double> traceDoubleB;
TraceContext context;
CompositeTraceResolver resolver (context) ;
resolver.Add ("trace-double-a", traceDoubleA,
TraceSourceTest (TraceSourceTest::DOUBLEA));
resolver.Add ("trace-double-b", traceDoubleB,
TraceSourceTest (TraceSourceTest::DOUBLEB));
resolver.Connect ("/*", MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
m_gotDoubleA = false;
m_gotDoubleB = false;
traceDoubleA (0);
if (!m_gotDoubleA || m_gotDoubleB)
{
ok = false;
}
m_gotDoubleA = false;
traceDoubleA (0);
traceDoubleB (0);
if (!m_gotDoubleA || !m_gotDoubleB)
{
ok = false;
}
m_gotDoubleA = false;
m_gotDoubleB = false;
resolver.Disconnect ("/*", MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
m_gotDoubleA = false;
m_gotDoubleB = false;
traceDoubleA (0);
traceDoubleB (0);
if (m_gotDoubleA || m_gotDoubleB)
{
ok = false;
}
resolver.Connect ("/trace-double-a",
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
m_gotDoubleA = false;
m_gotDoubleB = false;
traceDoubleA (0);
traceDoubleB (0);
if (!m_gotDoubleA || m_gotDoubleB)
{
ok = false;
}
resolver.Disconnect ("/trace-double-a",
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
resolver.Connect ("/(trace-double-a)",
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
m_gotDoubleA = false;
m_gotDoubleB = false;
traceDoubleA (0);
traceDoubleB (0);
if (!m_gotDoubleA || m_gotDoubleB)
{
ok = false;
}
resolver.Disconnect ("/trace-double-a",
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
resolver.Connect ("/(trace-double-a|trace-double-b)",
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
m_gotDoubleA = false;
m_gotDoubleB = false;
traceDoubleA (0);
traceDoubleB (0);
if (!m_gotDoubleA || !m_gotDoubleB)
{
ok = false;
}
resolver.Disconnect ("/trace-double-a",
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
m_gotDoubleA = false;
m_gotDoubleB = false;
traceDoubleA (0);
traceDoubleB (0);
if (m_gotDoubleA || !m_gotDoubleB)
{
ok = false;
}
resolver.Disconnect ("/(trace-double-a|trace-double-b)",
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
m_gotDoubleA = false;
m_gotDoubleB = false;
traceDoubleA (0);
traceDoubleB (0);
if (m_gotDoubleA || m_gotDoubleB)
{
ok = false;
}
resolver.Add ("subresolver",
MakeCallback (&CompositeTraceResolverTest::CreateSubResolver, this),
TraceSourceTest (TraceSourceTest::SUBRESOLVER));
resolver.Connect ("/subresolver/trace-int",
MakeCallback (&CompositeTraceResolverTest::TraceInt, this));
m_gotInt = false;
m_traceInt (1);
if (!m_gotInt)
{
ok = false;
}
resolver.Disconnect ("/subresolver/trace-int",
MakeCallback (&CompositeTraceResolverTest::TraceInt, this));
m_gotInt = false;
m_traceInt (1);
if (m_gotInt)
{
ok = false;
}
resolver.Connect ("/*/trace-int",
MakeCallback (&CompositeTraceResolverTest::TraceInt, this));
m_gotInt = false;
m_traceInt (1);
if (!m_gotInt)
{
ok = false;
}
resolver.Disconnect ("/subresolver/trace-int",
MakeCallback (&CompositeTraceResolverTest::TraceInt, this));
m_gotInt = false;
m_traceInt (1);
if (m_gotInt)
{
ok = false;
}
return ok;
}
static CompositeTraceResolverTest g_compositeTraceResolverTest;
}//namespace ns3
#endif /* RUN_SELF_TESTS */

View File

@@ -1,222 +0,0 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#ifndef COMPOSITE_TRACE_RESOLVER_H
#define COMPOSITE_TRACE_RESOLVER_H
#include "ns3/callback.h"
#include "trace-resolver.h"
#include "callback-trace-source.h"
#include "uv-trace-source.h"
#include "sv-trace-source.h"
#include "fv-trace-source.h"
#include "terminal-trace-resolver.h"
namespace ns3 {
/**
* \brief a helper class to aggregate contained TraceResolver and other trace sources.
* \ingroup lowleveltracing
*/
class CompositeTraceResolver : public TraceResolver
{
public:
CompositeTraceResolver (TraceContext const &context);
virtual ~CompositeTraceResolver ();
/**
* \param name name of trace source
* \param trace a callback trace source
* \param context the context associated to this trace source
*
* Add a callback trace source in this resolver. This trace
* source will match the name specified during namespace
* resolution. The TraceContext of this trace source will also
* be automatically extended to contain the input context.
*/
template <typename T1, typename T2,
typename T3, typename T4,
typename T>
void Add (std::string name,
CallbackTraceSource<T1,T2,T3,T4> &trace, T const &context);
/**
* \param name name of trace source
* \param trace a signed variable trace source
* \param context the context associated to this trace source
*
* Add a signed variable trace source in this resolver.
* This trace source will match the name specified during namespace
* resolution. The TraceContext of this trace source will also
* be automatically extended to contain the input context.
*/
template <typename T>
void Add (std::string name,
SVTraceSource<T> &trace, T const &context);
/**
* \param name name of trace source
* \param trace an unsigned variable trace source
* \param context the context associated to this trace source
*
* Add an unsigned variable trace source in this resolver.
* This trace source will match the name specified during namespace
* resolution. The TraceContext of this trace source will also
* be automatically extended to contain the input context.
*/
template <typename T>
void Add (std::string name,
UVTraceSource<T> &trace, T const &context);
/**
* \param name name of trace source
* \param trace a floating-point variable trace source
* \param context the context associated to this trace source
*
* Add a floating-point variable trace source in this resolver.
* This trace source will match the name specified during namespace
* resolution. The TraceContext of this trace source will also
* be automatically extended to contain the input context.
*/
template <typename T>
void Add (std::string name,
FVTraceSource<T> &trace, T const &context);
/**
* \param name name of child trace resolver
* \param createResolver a trace resolver constructor
* \param context the context associated to this entry
*
* Add a child trace resolver to this resolver. This child
* trace resolver will match the name specified during
* namespace resolution. When this happens, the constructor
* will be invoked to create the child trace resolver and
* the associated TraceContext will be automatically extended
* to contain the input context.
*/
template <typename T>
void Add (std::string name,
Callback<TraceResolver *,TraceContext const &> createResolver,
T const &context);
/**
* \param name name of child trace resolver
* \param createResolver a trace resolver constructor
*
* Add a child trace resolver to this resolver. This child
* trace resolver will match the name specified during
* namespace resolution. When this happens, the constructor
* will be invoked to create the child trace resolver.
*/
void Add (std::string name,
Callback<TraceResolver *,TraceContext const &> createResolver);
private:
template <typename SOURCE, typename CONTEXT>
void DoAddTraceSource (std::string name,
SOURCE &traceSource, CONTEXT const &context);
template <typename SOURCE>
static TraceResolver *CreateTerminalTraceResolver (SOURCE *trace,
TraceContext const &context);
void DoAdd (std::string name,
Callback<TraceResolver *,TraceContext const &> createResolver,
TraceContext const &context);
virtual TraceResolverList DoLookup (std::string id) const;
struct CallbackTraceSourceItem
{
std::string name;
Callback<TraceResolver *,TraceContext const &> createResolver;
TraceContext context;
};
typedef std::list<struct CallbackTraceSourceItem> TraceItems;
TraceItems m_items;
};
}//namespace ns3
namespace ns3 {
template <typename SOURCE, typename CONTEXT>
void
CompositeTraceResolver::DoAddTraceSource (std::string name,
SOURCE &traceSource, CONTEXT const &context)
{
TraceContext traceContext = GetContext ();
traceContext.Add (context);
TraceResolver *(*create) (SOURCE *trace, TraceContext const &context);
create = &CompositeTraceResolver::CreateTerminalTraceResolver<SOURCE>;
Callback<TraceResolver *,TraceContext const &> createResolver =
MakeBoundCallback (create, &traceSource);
DoAdd (name, createResolver, traceContext);
}
template <typename SOURCE>
TraceResolver *
CompositeTraceResolver::CreateTerminalTraceResolver (SOURCE *traceSource,
TraceContext const &context)
{
return new TerminalTraceResolver<SOURCE> (*traceSource, context);
}
template <typename T1, typename T2,
typename T3, typename T4,
typename T>
void
CompositeTraceResolver::Add (std::string name,
CallbackTraceSource<T1,T2,T3,T4> &trace,
T const &context)
{
DoAddTraceSource (name, trace, context);
}
template <typename T>
void
CompositeTraceResolver::Add (std::string name,
SVTraceSource<T> &trace, T const &context)
{
DoAddTraceSource (name, trace, context);
}
template <typename T>
void
CompositeTraceResolver::Add (std::string name,
UVTraceSource<T> &trace, T const &context)
{
DoAddTraceSource (name, trace, context);
}
template <typename T>
void
CompositeTraceResolver::Add (std::string name,
FVTraceSource<T> &trace, T const &context)
{
DoAddTraceSource (name, trace, context);
}
template <typename T>
void
CompositeTraceResolver::Add (std::string name,
Callback<TraceResolver *,TraceContext const &> createResolver,
T const &context)
{
TraceContext traceContext = GetContext ();
traceContext.Add (context);
DoAdd (name, createResolver, traceContext);
}
}//namespace ns3
#endif /* COMPOSITE_TRACE_RESOLVER_H */

View File

@@ -1,52 +0,0 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#ifndef EMPTY_TRACE_RESOLVER_H
#define EMPTY_TRACE_RESOLVER_H
#include "trace-resolver.h"
namespace ns3 {
class TraceContext;
/**
* \brief a TraceResolver instance which does not resolve anything.
* \ingroup tracing
*
* Trying to resolve against this class will yield no matches and no
* connections. Returning an instance of this class from a
* CreateTraceResolver method is a hand way of not implementing
* any Tracing code.
*/
class EmptyTraceResolver : public TraceResolver
{
public:
/**
* \param o necessary context for this class.
*
* The only constructor exported by this class.
*/
EmptyTraceResolver (TraceContext const &o);
};
}//namespace ns3
#endif /* EMPTY_TRACE_RESOLVER_H */

View File

@@ -199,6 +199,12 @@ Packet::Deserialize (Buffer buffer)
buffer.RemoveAtStart (metadataDeserialized);
}
std::ostream& operator<< (std::ostream& os, const Packet &packet)
{
packet.Print (os);
return os;
}
} // namespace ns3

View File

@@ -328,6 +328,8 @@ private:
static uint32_t m_globalUid;
};
std::ostream& operator<< (std::ostream& os, const Packet &packet);
/**
* \defgroup packetperf Packet Performance
* The current implementation of the byte buffers and tag list is based

View File

@@ -1,66 +0,0 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#ifndef TERMINAL_TRACE_RESOLVER_H
#define TERMINAL_TRACE_RESOLVER_H
#include "trace-resolver.h"
namespace ns3 {
class TraceContext;
template <typename T>
class TerminalTraceResolver : public TraceResolver
{
public:
TerminalTraceResolver (T &traceSource, TraceContext const &context);
private:
virtual void DoConnect (CallbackBase const &cb);
virtual void DoDisconnect (CallbackBase const &cb);
T &m_traceSource;
};
}//namespace ns3
namespace ns3 {
template <typename T>
TerminalTraceResolver<T>::TerminalTraceResolver (T &traceSource,
TraceContext const &context)
: TraceResolver (context),
m_traceSource (traceSource)
{}
template <typename T>
void
TerminalTraceResolver<T>::DoConnect (CallbackBase const &cb)
{
m_traceSource.AddCallback (cb, GetContext ());
}
template <typename T>
void
TerminalTraceResolver<T>::DoDisconnect (CallbackBase const &cb)
{
m_traceSource.RemoveCallback (cb);
}
}//namespace ns3
#endif /* TERMINAL_TRACE_RESOLVER_H */

View File

@@ -1,104 +0,0 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "trace-resolver.h"
namespace ns3 {
TraceResolver::TraceResolver (TraceContext const &context)
: m_context (context)
{}
TraceResolver::~TraceResolver ()
{}
TraceContext const &
TraceResolver::GetContext (void) const
{
return m_context;
}
void
TraceResolver::Connect (std::string path, CallbackBase const &cb)
{
std::string::size_type cur = 1;
// check that first char is "/"
std::string::size_type next = path.find ("/", cur);
std::string element = std::string (path, cur, next-1);
TraceResolverList resolverList = DoLookup (element);
for (TraceResolverList::iterator i = resolverList.begin (); i != resolverList.end (); i++)
{
TraceResolver *resolver = *i;
if (next == std::string::npos)
{
// we really break the recursion here.
resolver->DoConnect (cb);
}
else
{
std::string subpath = std::string (path, next, std::string::npos);
resolver->Connect (subpath, cb);
}
delete resolver;
}
resolverList.erase (resolverList.begin (), resolverList.end ());
}
void
TraceResolver::Disconnect (std::string path, CallbackBase const &cb)
{
std::string::size_type cur = 1;
// check that first char is "/"
std::string::size_type next = path.find ("/", cur);
std::string element = std::string (path, cur, next-1);
TraceResolverList resolverList = DoLookup (element);
for (TraceResolverList::iterator i = resolverList.begin (); i != resolverList.end (); i++)
{
TraceResolver *resolver = *i;
if (next == std::string::npos)
{
// we really break the recursion here.
resolver->DoDisconnect (cb);
}
else
{
std::string subpath = std::string (path, next, std::string::npos);
resolver->Disconnect (subpath, cb);
}
delete resolver;
}
resolverList.erase (resolverList.begin (), resolverList.end ());
}
TraceResolver::TraceResolverList
TraceResolver::DoLookup (std::string id) const
{
return TraceResolverList ();
}
void
TraceResolver::DoConnect (CallbackBase const &cb)
{}
void
TraceResolver::DoDisconnect (CallbackBase const &cb)
{}
}//namespace ns3

View File

@@ -1,119 +0,0 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#ifndef TRACE_RESOLVER_H
#define TRACE_RESOLVER_H
#include <string>
#include <list>
#include "trace-context.h"
namespace ns3 {
class CallbackBase;
/**
* \brief the base class which is used to incremental perform trace
* namespace resolution.
* \ingroup lowleveltracing
*
* This class provides a public API to the ns3::TraceRoot object:
* - ns3::TraceResolver::Connect
* - ns3::TraceResolver::Disconnect
*
* It also provides an API for its subclasses. Each subclass should
* implement one of:
* - ns3::TraceResolver::DoLookup
* - ns3::TraceResolver::DoConnect and ns3::TraceResolver::DoDisconnect
* Each subclass must also provide an ns3::TraceContext to the TraceResolver
* constructor. Finally, each subclass can access the ns3::TraceContext
* associated to this ns3::TraceResolver through the
* ns3::TraceResolver::GetContext method.
*/
class TraceResolver
{
public:
virtual ~TraceResolver ();
/**
* \param path the namespace path to resolver
* \param cb the callback to connect to the matching namespace
*
* This method is typically invoked by ns3::TraceRoot but advanced
* users could also conceivably call it directly if they want to
* skip the ns3::TraceRoot.
*/
void Connect (std::string path, CallbackBase const &cb);
/**
* \param path the namespace path to resolver
* \param cb the callback to disconnect in the matching namespace
*
* This method is typically invoked by ns3::TraceRoot but advanced
* users could also conceivably call it directly if they want to
* skip the ns3::TraceRoot.
*/
void Disconnect (std::string path, CallbackBase const &cb);
protected:
/**
* \param context the context used to initialize this TraceResolver.
*
* Every subclass must call this constructor
*/
TraceResolver (TraceContext const &context);
/**
* \returns the ns3::TraceContext stored in this ns3::TraceResolver.
*
* Subclasses usually invoke this method to get access to the
* TraceContext stored here to pass it down to the TraceResolver
* constructors invoked from within the DoLookup method.
*/
TraceContext const &GetContext (void) const;
typedef std::list<TraceResolver *> TraceResolverList;
private:
TraceResolver ();
/**
* \param id the id to resolve. This is supposed to be
* one element of the global tracing namespace.
* \returns a list of reslvers which match the input namespace element
*
* A subclass which overrides this method should return a potentially
* empty list of pointers to ns3::TraceResolver instances which match
* the input namespace element. Each of these TraceResolver should be
* instanciated with a TraceContext which holds enough context
* information to identify the type of the TraceResolver.
*/
virtual TraceResolverList DoLookup (std::string id) const;
/**
* \param cb callback to connect
*
* This method is invoked on leaf trace resolvers.
*/
virtual void DoConnect (CallbackBase const &cb);
/**
* \param cb callback to disconnect
*
* This method is invoked on leaf trace resolvers.
*/
virtual void DoDisconnect (CallbackBase const &cb);
TraceContext m_context;
};
}//namespace ns3
#endif /* TRACE_RESOLVER_H */

View File

@@ -1,54 +0,0 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "trace-root.h"
#include "ns3/composite-trace-resolver.h"
#include "ns3/trace-context.h"
namespace ns3 {
void
TraceRoot::Connect (std::string path, CallbackBase const &cb)
{
TraceResolver *resolver = GetComposite ();
resolver->Connect (path, cb);
}
void
TraceRoot::Disconnect (std::string path, CallbackBase const &cb)
{
TraceResolver *resolver = GetComposite ();
resolver->Disconnect (path, cb);
}
void
TraceRoot::Register (std::string name,
Callback<TraceResolver *,TraceContext const &> createResolver)
{
CompositeTraceResolver *resolver = GetComposite ();
resolver->Add (name, createResolver);
}
CompositeTraceResolver *
TraceRoot::GetComposite (void)
{
static CompositeTraceResolver resolver = CompositeTraceResolver (TraceContext ());
return &resolver;
}
} // namespace ns3

View File

@@ -1,335 +0,0 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#ifndef TRACE_ROOT_H
#define TRACE_ROOT_H
#include <string>
#include "ns3/callback.h"
/**
* \defgroup lowleveltracing Low-level tracing
*
* This low-level API is built around a few concepts:
* - There can be any number of trace source objects. Each trace source
* object can generate any number of trace events. The current
* trace source objects are: ns3::CallbackTraceSourceSource, ns3::UVTraceSource,
* ns3::SVTraceSource, and, ns3::FVTraceSource.
* - Each trace source can be connected to any number of trace sinks.
* A trace sink is a ns3::Callback with a very special signature. Its
* first argument is always a ns3::TraceContext.
* - Every trace source is uniquely identified by a ns3::TraceContext. Every
* trace sink can query a ns3::TraceContext for information. This allows
* a trace sink which is connected to multiple trace sources to identify
* from which source each event is coming from.
*
* To define new trace sources, a model author needs to instante one trace source
* object for each kind of tracing event he wants to export. The trace source objects
* currently defined are:
* - ns3::CallbackTraceSourceSource: this trace source can be used to convey any kind of
* trace event to the user. It is a functor, that is, it is a variable
* which behaves like a function which will forward every event to every
* connected trace sink (i.e., ns3::Callback). This trace source takes
* up to four arguments and forwards these 4 arguments together with the
* ns3::TraceContext which identifies this trace source to the connected
* trace sinks.
* - ns3::UVTraceSource: this trace source is used to convey key state variable
* changes to the user. It behaves like a normal integer unsigned variable:
* you can apply every normal arithmetic operator to it. It will forward
* every change in the value of the variable back to every connected trace
* sink by providing a TraceContext, the old value and the new value.
* - ns3::SVTraceSource: this is the signed integer equivalent of
* ns3::UVTraceSource.
* - ns3::FVTraceSource: this is the floating point equivalent of
* ns3::UVTraceSource and ns3::SVTraceSource.
*
* For example, to define a trace source which notifies you of a new packet
* being transmitted, you would have to:
* \code
* class MyModel
* {
* public:
* void Tx (Packet const &p);
* private:
* CallbackTraceSource<Packet const &> m_txTrace;
* };
*
* void
* MyModel::Tx (Packet const &p)
* {
* // trace packet tx event.
* m_txTrace (p);
* // ... send the packet for real.
* }
* \endcode
*
* Once the model author has instantiated these objects and has wired them
* in his simulation code (that is, he calls them wherever he wants to trigger
* a trace event), he needs to make these trace sources available to users
* to allow them to connect any number of trace sources to any number
* of user trace sinks. While it would be possible to make each model
* export directly each of his trace source instances and request users to
* invoke a source->Connect (callback) method to perform the connection
* explicitely, it was felt that this was a bit cumbersome to do.
*
* As such, the ``connection'' between a set of sources and a sink is
* performed through a third-party class, the TraceResolver, which
* can be used to automate the connection of multiple matching trace sources
* to a single sink. This TraceResolver works by defining a hierarchical
* tracing namespace: the root of this namespace is accessed through the
* ns3::TraceRoot class. The namespace is represented as a string made of
* multiple elements, each of which is separated from the other elements
* by the '/' character. A namespace string always starts with a '/'.
*
* By default, the current simulation models provide a '/nodes' tracing root.
* This '/nodes' namespace is structured as follows:
* \code
* /nodes/n/arp
* /nodes/n/udp
* /nodes/n/ipv4
* /tx
* /rx
* /drop
* /interfaces/n/netdevice
* /queue/
* /enque
* /deque
* /drop
* \endcode
*
* The 'n' element which follows the /nodes and /interfaces namespace elements
* identify a specific node and interface through their index within the
* ns3::NodeList and ns3::Ipv4 objects respectively.
*
* To connect a trace sink to a trace source identified by a namespace string,
* a user can call the ns3::TraceRoot::Connect method (the ns3::TraceRoot::Disconnect
* method does the symmetric operation). This connection method can accept
* fully-detailed namespace strings but it can also perform pattern matching
* on the user-provided namespace strings to connect multiple trace sources
* to a single trace sink in a single connection operation.
*
* The syntax of the pattern matching rules are loosely based on regular
* expressions:
* - the '*' character matches every element
* - the (a|b) construct matches element 'a' or 'b'
* - the [ss-ee] construct matches all numerical values which belong
* to the interval which includes ss and ee
*
* For example, the user could use the following to connect a single sink
* to the ipv4 tx, rx, and drop trace events:
*
* \code
* void MyTraceSink (TraceContext const &context, Packet &packet);
* TraceRoot::Connect ("/nodes/ * /ipv4/ *", MakeCallback (&MyTraceSink));
* \endcode
*
* Of course, this code would work only if the signature of the trace sink
* is exactly equal to the signature of all the trace sources which match
* the namespace string (if one of the matching trace source does not match
* exactly, a fatal error will be triggered at runtime during the connection
* process). The ns3::TraceContext extra argument contains
* information on where the trace source is located in the namespace tree.
* In that example, if there are multiple nodes in this scenario, each
* call to the MyTraceSink function would receive a different TraceContext,
* each of which would contain a different NodeList::NodeIndex object.
*
* It is important to understand exactly what an ns3::TraceContext
* is. It is a container for a number of type instances. Each instance of
* a ns3::TraceContext contains one and only one instance of a given type.
* ns3::TraceContext::Add can be called to add a type instance into a
* TraceContext instance and ns3::TraceContext::Get can be called to get
* a copy of a type instance stored into the ns3::TraceContext. If ::Get
* cannot retrieve the requested type, a fatal error is triggered at
* runtime. The values stored into an ns3::TraceContext attached to a
* trace source are automatically determined during the namespace
* resolution process. To retrieve a value from a ns3::TraceContext, the
* code can be as simple as this:
* \code
* void MyTraceSink (TraceContext const &context, Packet &packet)
* {
* NodeList::NodeIndex index;
* context.Get (index);
* std::cout << "node id=" << NodeList::GetNode (index)->GetId () << std::endl;
* }
* \endcode
*
* The hierarchical global namespace described here is not implemented
* in a single central location: it was felt that doing this would make
* it too hard to introduce user-specific models which could hook
* automatically into the overal tracing system. If the tracing
* namespace was implemented in a single central location, every model
* author would have had to modify this central component to make
* his own model available to trace users.
*
* Instead, the handling of the namespace is distributed across every relevant
* model: every model implements only the part of the namespace it is
* really responsible for. To do this, every model is expected
* to provide an instance of a TraceResolver whose
* responsability is to recursively provide access to the trace sources
* defined in its model. Each TraceResolver instance should be a subclass
* of the TraceResolver base class which implements either the DoLookup
* or the DoConnect and DoDisconnect methods. Because implementing these
* methods can be a bit tedious, our tracing framework provides a number
* of helper template classes which should save the model author from
* having to implement his own in most cases:
* - ns3::CompositeTraceResolver: this subclass of ns3::TraceResolver can
* be used to aggregate together multiple trace sources and multiple other
* ns3::TraceResolver instances.
* - ns3::ArrayTraceResolver: this subclass of ns3::TraceResolver can be
* used to match any number of elements within an array where every element
* is identified by its index.
*
* Once you can instantiate your own ns3::TraceResolver object instance, you
* have to hook it up into the global namespace. There are two ways to do this:
* - you can hook your ns3::TraceResolver creation method as a new trace
* root by using the ns3::TraceRoot::Register method
* - you can hook your new ns3::TraceResolver creation method into the
* container of your model. This step will obvsiouly depend on which model
* contains your own model but, if you wrote a new l3 protocol, all you
* would have to do to hook into your container L3Demux class is to implement
* the pure virtual method inherited from the L3Protocol class whose name is
* ns3::L3protocol::CreateTraceResolver.
*
* So, in most cases, exporting a model's trace sources is a matter of
* implementing a method CreateTraceResolver as shown below:
* \code
* class MyModel
* {
* public:
* enum TraceType {
* TX,
* RX,
* ...
* };
* TraceResolver *CreateTraceResolver (TraceContext const &context);
* void Tx (Packet const &p);
* private:
* CallbackTraceSource<Packet const &> m_txTrace;
* };
*
* TraceResolver *
* MyModel::CreateTraceResolver (TraceContext const &context)
* {
* CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
* resolver->Add ("tx", m_txTrace, MyModel::TX);
* return resolver;
* }
* void
* MyModel::Tx (Packet const &p)
* {
* m_txTrace (p);
* }
* \endcode
*
* If you really want to have fun and implement your own ns3::TraceResolver
* subclass, you need to understand the basic Connection and Disconnection
* algorithm. The code of that algorithm is wholy contained in the
* ns3::TraceResolver::Connect and ns3::TraceResolver::Disconnect methods.
* The idea is that we recursively parse the input namespace string by removing
* the first namespace element. This element is 'resolved' is calling
* the ns3::TraceResolver::DoLookup method which returns a list of
* TraceResolver instances. Each of the returned TraceResolver instance is
* then given what is left of the namespace by calling ns3::TraceResolver::Connect
* until the last namespace element is processed. At this point, we invoke
* the ns3::TraceResolver::DoConnect or ns3::TraceResolver::DoDisconnect
* methods to break the recursion. A good way to understand this algorithm
* is to trace its behavior. Let's say that you want to connect to
* '/nodes/ * /ipv4/interfaces/ * /netdevice/queue/ *'. It would generate
* the following call traces:
*
* \code
* TraceRoot::Connect ("/nodes/ * /ipv4/interfaces/ * /netdevice/queue/ *", callback);
* traceContext = TraceContext ();
* rootResolver = CompositeTraceResolver (traceContext);
* rootResolver->Connect ("/nodes/ * /ipv4/interfaces/ * /netdevice/queue/ *", callback);
* resolver = CompositeTraceResolver::DoLookup ("nodes");
* return NodeList::CreateTraceResolver (GetContext ());
* return ArrayTraceResolver (context);
* resolver->Connect ("/ * /ipv4/interfaces/ * /netdevice/queue/ *", callback);
* ArrayTraceResolver::DoLookup ("*");
* for (i = 0; i < n_nodes; i++)
* resolver = nodes[i]->CreateTraceResolver (GetContext ());
* return CompositeTraceResolver (context);
* resolvers.add (resolver);
* return resolvers;
* for resolver in (resolvers)
* resolver->Connect ("/ipv4/interfaces/ * /netdevice/queue/ *", callback);
* CompositeTraceResolver::DoLookup ("ipv4");
* resolver = ipv4->CreateTraceResolver (GetContext ());
* return CompositeTraceResolver (context);
* return resolver;
* resolver->Connect ("/interfaces/ * /netdevice/queue/ *", callback);
* CompositeTraceResolver::DoLookup ("interfaces");
* resolver = ArrayTraceResolver (GetContext ());
* resolver->Connect ("/ * /netdevice/queue/ *", callback);
* ArrayTraceResolver::DoLookup ("*");
* for (i = 0; i < n_interfaces; i++)
* resolver = interfaces[i]->CreateTraceResolver (GetContext ());
* return CompositeTraceResolver ()
* resolvers.add (resolver);
* return resolvers;
* resolver->Connect ("/netdevice/queue/ *", callback);
* CompositeTraceResolver::DoLookup ("netdevice");
* resolver = NetDevice::CreateTraceResolver (GetContext ());
* return CompositeTraceResolver ();
* return resolver;
* resolver->Connect ("/queue/ *", callback);
* CompositeTraceResolver::DoLookup ("queue");
* resolver = Queue::CreateTraceResolver (GetContext ());
* return CompositeTraceResolver ();
* return resolver
* resolver->Connect ("*", callback);
* CompositeTraceResolver::DoLookup ("*");
* for match in (matches)
* resolver = TerminalTraceResolver ("match");
* resolvers.add (resolver)
* return resolvers;
* for resolver in (resolvers)
* TerminalTraceResolver->DoConnect (callback);
* \endcode
*/
namespace ns3 {
class CompositeTraceResolver;
class TraceResolver;
class TraceContext;
class CallbackBase;
/**
* \brief The main class used to access tracing functionality for
* a user.
*
* \ingroup lowleveltracing
*/
class TraceRoot
{
public:
static void Connect (std::string path, CallbackBase const &cb);
static void Disconnect (std::string path, CallbackBase const &cb);
static void Register (std::string name,
Callback<TraceResolver *,TraceContext const &> createResolver);
private:
static CompositeTraceResolver *GetComposite (void);
};
}// namespace ns3
#endif /* TRACE_ROOT_H */

View File

@@ -12,14 +12,6 @@ def build(bld):
'tags.cc',
'tag-registry.cc',
'pcap-writer.cc',
'variable-tracer-test.cc',
'trace-context.cc',
'trace-context-element.cc',
'trace-resolver.cc',
'callback-trace-source.cc',
'empty-trace-resolver.cc',
'composite-trace-resolver.cc',
'trace-root.cc',
'data-rate.cc',
]
@@ -35,18 +27,6 @@ def build(bld):
'packet.h',
'packet-printer.h',
'packet-metadata.h',
'uv-trace-source.h',
'sv-trace-source.h',
'fv-trace-source.h',
'pcap-writer.h',
'callback-trace-source.h',
'trace-context.h',
'trace-context-element.h',
'trace-resolver.h',
'empty-trace-resolver.h',
'composite-trace-resolver.h',
'array-trace-resolver.h',
'trace-root.h',
'terminal-trace-resolver.h',
'data-rate.h',
]

View File

@@ -0,0 +1,205 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#ifndef ARRAY_TRACE_RESOLVER_H
#define ARRAY_TRACE_RESOLVER_H
#include <stdint.h>
#include <string>
#include "callback.h"
#include "trace-resolver.h"
#include "object.h"
namespace ns3 {
/**
* \brief a helper class to offer trace resolution for an array of objects.
* \ingroup tracing
*
* \class ArrayTraceResolver
*
* An ArrayTraceResolver is a resolver which can match any input integer
* against an element in an array. The array is accessed using a
* pair iterators. Each element of the array is expected
* to be a subclass of the Object base class.
*
* When the Connect method is called, this trace resolver will
* automatically store in the TraceContext of each resolved object
* its index through an object of type INDEX specified during the
* instanciation of the ArrayTraceResolver template.
*/
template <typename INDEX>
class ArrayTraceResolver : public TraceResolver
{
public:
ArrayTraceResolver ();
~ArrayTraceResolver ();
/**
* \param begin an iterator which points to the start of the array.
* \param end an iterator which points to the end of the array.
*/
template <typename T>
void SetIterators (T begin, T end);
// inherited from TraceResolver
virtual void Connect (std::string path, CallbackBase const &cb, const TraceContext &context);
virtual void Disconnect (std::string path, CallbackBase const &cb);
virtual void CollectSources (std::string path, const TraceContext &context,
SourceCollection *collection);
virtual void TraceAll (std::ostream &os, const TraceContext &context);
private:
class IteratorBase
{
public:
virtual ~IteratorBase () {}
virtual void Next (void) = 0;
virtual bool HasNext (void) = 0;
virtual Ptr<Object> Get (void) = 0;
virtual void Rewind (void) = 0;
};
IteratorBase *m_iter;
};
}//namespace ns3
// implementation
namespace ns3 {
template <typename INDEX>
ArrayTraceResolver<INDEX>::ArrayTraceResolver ()
: m_iter (0)
{}
template <typename INDEX>
ArrayTraceResolver<INDEX>::~ArrayTraceResolver ()
{
delete m_iter;
}
template <typename INDEX>
template <typename T>
void
ArrayTraceResolver<INDEX>::SetIterators (T begin, T end)
{
class Iterator : public IteratorBase
{
public:
Iterator (T begin, T end)
: m_begin (begin), m_end (end), m_cur (begin)
{}
virtual void Next (void)
{m_cur++;}
virtual bool HasNext (void)
{return m_cur != m_end;}
virtual Ptr<Object> Get (void)
{return *m_cur;}
virtual void Rewind (void)
{m_cur = m_begin;}
private:
T m_begin;
T m_end;
T m_cur;
};
delete m_iter;
m_iter = new Iterator (begin, end);
}
template <typename INDEX>
void
ArrayTraceResolver<INDEX>::Connect (std::string path, CallbackBase const &cb, const TraceContext &context)
{
if (path == "")
{
return;
}
std::string id = GetElement (path);
std::string subpath = GetSubpath (path);
if (id == "*")
{
uint32_t j = 0;
for (m_iter->Rewind (); m_iter->HasNext (); m_iter->Next ())
{
TraceContext tmp = context;
INDEX index = j;
tmp.AddElement (index);
Ptr<Object> obj = m_iter->Get ();
obj->GetTraceResolver ()->Connect (subpath, cb, tmp);
j++;
}
}
}
template <typename INDEX>
void
ArrayTraceResolver<INDEX>::Disconnect (std::string path, CallbackBase const &cb)
{
if (path == "")
{
return;
}
std::string id = GetElement (path);
std::string subpath = GetSubpath (path);
if (id == "*")
{
for (m_iter->Rewind (); m_iter->HasNext (); m_iter->Next ())
{
Ptr<Object> obj = m_iter->Get ();
obj->TraceDisconnect (subpath, cb);
}
}
}
template <typename INDEX>
void
ArrayTraceResolver<INDEX>::CollectSources (std::string path, const TraceContext &context,
SourceCollection *collection)
{
path.append ("/[0-n]");
uint32_t j = 0;
for (m_iter->Rewind (); m_iter->HasNext (); m_iter->Next ())
{
TraceContext tmp = context;
INDEX index = j;
tmp.AddElement (index);
Ptr<Object> obj = m_iter->Get ();
obj->GetTraceResolver ()->CollectSources (path, tmp, collection);
j++;
}
}
template <typename INDEX>
void
ArrayTraceResolver<INDEX>::TraceAll (std::ostream &os, const TraceContext &context)
{
uint32_t j = 0;
for (m_iter->Rewind (); m_iter->HasNext (); m_iter->Next ())
{
TraceContext tmp = context;
INDEX index = j;
tmp.AddElement (index);
Ptr<Object> obj = m_iter->Get ();
obj->GetTraceResolver ()->TraceAll (os, tmp);
j++;
}
}
}//namespace ns3
#endif /* ARRAY_TRACE_RESOLVER_H */

View File

@@ -57,6 +57,21 @@ void *Test10 (bool *a, int const & b)
return a;
}
void TestFZero (void) {}
void TestFOne (int) {}
void TestFTwo (int, int) {}
void TestFThree (int, int, int) {}
void TestFFour (int, int, int, int) {}
void TestFFive (int, int, int, int, int) {}
void TestFSix (int, int, int, int, int, int) {}
void TestFROne (int &) {}
void TestFRTwo (int &, int &) {}
void TestFRThree (int &, int &, int &) {}
void TestFRFour (int &, int &, int &, int &) {}
void TestFRFive (int &, int &, int &, int &, int &) {}
void TestFRSix (int &, int &, int &, int &, int &, int &) {}
class CallbackTest : public ns3::Test {
private:
bool m_test1;
@@ -73,6 +88,22 @@ public:
void Test3 (double a);
int Test4 (double a, int b);
void Test8 (Callback<void, int> callback);
void TestZero (void) {}
void TestOne (int) {}
void TestTwo (int, int) {}
void TestThree (int, int, int) {}
void TestFour (int, int, int, int) {}
void TestFive (int, int, int, int, int) {}
void TestSix (int, int, int, int, int, int) {}
void TestCZero (void) const {}
void TestCOne (int) const {}
void TestCTwo (int, int) const {}
void TestCThree (int, int, int) const {}
void TestCFour (int, int, int, int) const {}
void TestCFive (int, int, int, int, int) const {}
void TestCSix (int, int, int, int, int, int) const {}
};
CallbackTest::CallbackTest ()
@@ -110,6 +141,7 @@ CallbackTest::Test8 (Callback<void,int> callback)
{
callback (3);
}
bool
CallbackTest::IsWrong (void)
{
@@ -216,6 +248,53 @@ CallbackTest::RunTests (void)
MakeBoundCallback (&Test9, &v);
MakeBoundCallback (&Test10, &v);
MakeCallback (&CallbackTest::TestZero, this);
MakeCallback (&CallbackTest::TestOne, this);
MakeCallback (&CallbackTest::TestTwo, this);
MakeCallback (&CallbackTest::TestThree, this);
MakeCallback (&CallbackTest::TestFour, this);
MakeCallback (&CallbackTest::TestFive, this);
MakeCallback (&CallbackTest::TestSix, this);
MakeCallback (&CallbackTest::TestCZero, this);
MakeCallback (&CallbackTest::TestCOne, this);
MakeCallback (&CallbackTest::TestCTwo, this);
MakeCallback (&CallbackTest::TestCThree, this);
MakeCallback (&CallbackTest::TestCFour, this);
MakeCallback (&CallbackTest::TestCFive, this);
MakeCallback (&CallbackTest::TestCSix, this);
MakeCallback (&TestFZero);
MakeCallback (&TestFOne);
MakeCallback (&TestFTwo);
MakeCallback (&TestFThree);
MakeCallback (&TestFFour);
MakeCallback (&TestFFive);
MakeCallback (&TestFSix);
MakeCallback (&TestFROne);
MakeCallback (&TestFRTwo);
MakeCallback (&TestFRThree);
MakeCallback (&TestFRFour);
MakeCallback (&TestFRFive);
MakeCallback (&TestFRSix);
MakeBoundCallback (&TestFOne, 1);
MakeBoundCallback (&TestFTwo, 1);
MakeBoundCallback (&TestFThree, 1);
MakeBoundCallback (&TestFFour, 1);
MakeBoundCallback (&TestFFive, 1);
MakeBoundCallback (&TestFROne, 1);
MakeBoundCallback (&TestFRTwo, 1);
MakeBoundCallback (&TestFRThree, 1);
MakeBoundCallback (&TestFRFour, 1);
MakeBoundCallback (&TestFRFive, 1);
return ok;
}

View File

@@ -19,7 +19,10 @@
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "callback-trace-source.h"
#include "ns3/test.h"
#ifdef RUN_SELF_TESTS
#include "test.h"
namespace ns3 {
@@ -55,7 +58,7 @@ CallbackTraceSourceTest::CbTwo (TraceContext const &context, uint8_t a, double b
bool
CallbackTraceSourceTest::RunTests (void)
{
bool ok = true;
bool result = true;
TraceContext ctx;
CallbackTraceSource<uint8_t,double> trace;
@@ -64,32 +67,35 @@ CallbackTraceSourceTest::RunTests (void)
m_one = false;
m_two = false;
trace (1, 2);
if (!m_one || !m_two)
{
ok = false;
}
NS_TEST_ASSERT (m_one);
NS_TEST_ASSERT (m_two);
trace.RemoveCallback (MakeCallback (&CallbackTraceSourceTest::CbOne, this));
m_one = false;
m_two = false;
trace (1, 2);
if (m_one || !m_two)
{
ok = false;
}
NS_TEST_ASSERT (!m_one);
NS_TEST_ASSERT (m_two);
trace.RemoveCallback (MakeCallback (&CallbackTraceSourceTest::CbTwo, this));
m_one = false;
m_two = false;
trace (1, 2);
if (m_one || m_two)
{
ok = false;
}
NS_TEST_ASSERT (!m_one);
NS_TEST_ASSERT (!m_two);
return ok;
trace.AddCallback (MakeCallback (&CallbackTraceSourceTest::CbOne, this), ctx);
trace.AddCallback (MakeCallback (&CallbackTraceSourceTest::CbTwo, this), ctx);
m_one = false;
m_two = false;
trace (1, 2);
NS_TEST_ASSERT (m_one);
NS_TEST_ASSERT (m_two);
return result;
}
CallbackTraceSourceTest g_callbackTraceTest;
}//namespace ns3
#endif /* RUN_SELF_TESTS */

View File

@@ -0,0 +1,251 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2005,2006,2007 INRIA
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#ifndef CALLBACK_TRACE_H
#define CALLBACK_TRACE_H
#include <list>
#include "callback.h"
#include "fatal-error.h"
#include "trace-context.h"
#include "trace-source.h"
namespace ns3 {
/**
* \brief log arbitrary number of parameters to a matching ns3::Callback
* \ingroup tracing
*
* Whenever operator () is invoked on this class, the call and its arguments
* are forwarded to the internal matching ns3::Callback.
*/
template<typename T1 = empty, typename T2 = empty,
typename T3 = empty, typename T4 = empty>
class CallbackTraceSource : public TraceSource {
public:
CallbackTraceSource ();
virtual void AddCallback (CallbackBase const & callback, TraceContext const & context);
virtual void RemoveCallback (CallbackBase const & callback);
virtual void ConnectPrinter (std::ostream &os, const TraceContext &context);
void operator() (void) const;
void operator() (T1 a1) const;
void operator() (T1 a1, T2 a2) const;
void operator() (T1 a1, T2 a2, T3 a3) const;
void operator() (T1 a1, T2 a2, T3 a3, T4 a4) const;
private:
typedef std::list<Callback<void,TraceContext const &,T1,T2,T3,T4> > CallbackList;
TraceContext m_context;
CallbackList m_callbackList;
};
}; // namespace ns3
// implementation below.
namespace ns3 {
namespace internal {
template<typename T1, typename T2,
typename T3, typename T4>
class TraceSinkPrint;
template<typename T1, typename T2,
typename T3, typename T4>
class TraceSinkPrint
{
public:
static Callback<void,const TraceContext &,T1,T2,T3,T4> Make (std::ostream &os)
{
return ns3::MakeBoundCallback (&DoPrint, &os);
}
private:
static void DoPrint (std::ostream *os, const TraceContext &context, T1 a1, T2 a2, T3 a3, T4 a4)
{
*os << "context=\"" << context << "\" arg1=\"" << a1 << "\" arg2=\"" << a2 << "\" arg3=\"" << a3 << "\" arg4=\"" << a4 << "\"" << std::endl;
}
};
template<typename T1, typename T2,
typename T3>
class TraceSinkPrint<T1,T2,T3,empty>
{
public:
static Callback<void,const TraceContext &,T1,T2,T3> Make (std::ostream &os)
{
return ns3::MakeBoundCallback (&DoPrint, &os);
}
private:
static void DoPrint (std::ostream *os, const TraceContext &context, T1 a1, T2 a2, T3 a3)
{
*os << "context=\"" << context << "\" arg1=\"" << a1 << "\" arg2=\"" << a2 << "\" arg3=\"" << a3 << "\"" << std::endl;
}
};
template<typename T1, typename T2>
class TraceSinkPrint<T1,T2,empty,empty>
{
public:
static Callback<void,const TraceContext &,T1,T2> Make (std::ostream &os)
{
return ns3::MakeBoundCallback (&DoPrint, &os);
}
private:
static void DoPrint (std::ostream *os, const TraceContext &context, T1 a1, T2 a2)
{
*os << "context=\"" << context << "\" arg1=\"" << a1 << "\" arg2=\"" << a2 << "\"" << std::endl;
}
};
template<typename T1>
class TraceSinkPrint<T1,empty,empty,empty>
{
public:
static Callback<void,const TraceContext &,T1> Make (std::ostream &os)
{
return ns3::MakeBoundCallback (&DoPrint, &os);
}
private:
static void DoPrint (std::ostream *os, const TraceContext &context, T1 a1)
{
*os << "context=\"" << context << "\" arg1=\"" << a1 << "\"" << std::endl;
}
};
template <>
class TraceSinkPrint<empty,empty,empty,empty>
{
public:
static Callback<void,const TraceContext &> Make (std::ostream &os)
{
return ns3::MakeBoundCallback (&DoPrint, &os);
}
private:
static void DoPrint (std::ostream *os, const TraceContext &context)
{
*os << "context=\"" << context << std::endl;
}
};
} // namespace internal
template<typename T1, typename T2,
typename T3, typename T4>
CallbackTraceSource<T1,T2,T3,T4>::CallbackTraceSource ()
: m_callbackList ()
{}
template<typename T1, typename T2,
typename T3, typename T4>
void
CallbackTraceSource<T1,T2,T3,T4>::AddCallback (CallbackBase const & callback,
TraceContext const &context)
{
Callback<void,TraceContext const &,T1,T2,T3,T4> cb;
cb.Assign (callback);
m_context.Union (context);
m_callbackList.push_back (cb);
}
template<typename T1, typename T2,
typename T3, typename T4>
void
CallbackTraceSource<T1,T2,T3,T4>::RemoveCallback (CallbackBase const & callback)
{
for (typename CallbackList::iterator i = m_callbackList.begin ();
i != m_callbackList.end (); /* empty */)
{
if ((*i).IsEqual (callback))
{
i = m_callbackList.erase (i);
}
else
{
i++;
}
}
}
template<typename T1, typename T2,
typename T3, typename T4>
void
CallbackTraceSource<T1,T2,T3,T4>::ConnectPrinter (std::ostream &os, const TraceContext &context)
{
AddCallback (ns3::internal::TraceSinkPrint<T1,T2,T3,T4>::Make (os), context);
}
template<typename T1, typename T2,
typename T3, typename T4>
void
CallbackTraceSource<T1,T2,T3,T4>::operator() (void) const
{
for (typename CallbackList::const_iterator i = m_callbackList.begin ();
i != m_callbackList.end (); i++)
{
(*i) (m_context);
}
}
template<typename T1, typename T2,
typename T3, typename T4>
void
CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1) const
{
for (typename CallbackList::const_iterator i = m_callbackList.begin ();
i != m_callbackList.end (); i++)
{
(*i) (m_context, a1);
}
}
template<typename T1, typename T2,
typename T3, typename T4>
void
CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1, T2 a2) const
{
for (typename CallbackList::const_iterator i = m_callbackList.begin ();
i != m_callbackList.end (); i++)
{
(*i) (m_context, a1, a2);
}
}
template<typename T1, typename T2,
typename T3, typename T4>
void
CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1, T2 a2, T3 a3) const
{
for (typename CallbackList::const_iterator i = m_callbackList.begin ();
i != m_callbackList.end (); i++)
{
(*i) (m_context, a1, a2, a3);
}
}
template<typename T1, typename T2,
typename T3, typename T4>
void
CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1, T2 a2, T3 a3, T4 a4) const
{
for (typename CallbackList::const_iterator i = m_callbackList.begin ();
i != m_callbackList.end (); i++)
{
(*i) (m_context, a1, a2, a3, a4);
}
}
}//namespace ns3
#endif /* CALLBACK_TRACE_H */

View File

@@ -25,6 +25,7 @@
#include "ptr.h"
#include "fatal-error.h"
#include "empty.h"
#include "type-traits.h"
namespace ns3 {
@@ -89,55 +90,62 @@ private:
};
// declare the CallbackImpl class
template <typename R, typename T1, typename T2, typename T3, typename T4, typename T5>
template <typename R, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
class CallbackImpl;
// define CallbackImpl for 0 params
template <typename R>
class CallbackImpl<R,empty,empty,empty,empty,empty> : public CallbackImplBase {
class CallbackImpl<R,empty,empty,empty,empty,empty,empty> : public CallbackImplBase {
public:
virtual ~CallbackImpl () {}
virtual R operator() (void) = 0;
};
// define CallbackImpl for 1 params
template <typename R, typename T1>
class CallbackImpl<R,T1,empty,empty,empty,empty> : public CallbackImplBase {
class CallbackImpl<R,T1,empty,empty,empty,empty,empty> : public CallbackImplBase {
public:
virtual ~CallbackImpl () {}
virtual R operator() (T1) = 0;
};
// define CallbackImpl for 2 params
template <typename R, typename T1, typename T2>
class CallbackImpl<R,T1,T2,empty,empty,empty> : public CallbackImplBase {
class CallbackImpl<R,T1,T2,empty,empty,empty,empty> : public CallbackImplBase {
public:
virtual ~CallbackImpl () {}
virtual R operator() (T1, T2) = 0;
};
// define CallbackImpl for 3 params
template <typename R, typename T1, typename T2, typename T3>
class CallbackImpl<R,T1,T2,T3,empty,empty> : public CallbackImplBase {
class CallbackImpl<R,T1,T2,T3,empty,empty,empty> : public CallbackImplBase {
public:
virtual ~CallbackImpl () {}
virtual R operator() (T1, T2, T3) = 0;
};
// define CallbackImpl for 4 params
template <typename R, typename T1, typename T2, typename T3, typename T4>
class CallbackImpl<R,T1,T2,T3,T4,empty> : public CallbackImplBase {
class CallbackImpl<R,T1,T2,T3,T4,empty,empty> : public CallbackImplBase {
public:
virtual ~CallbackImpl () {}
virtual R operator() (T1, T2, T3, T4) = 0;
};
// define CallbackImpl for 5 params
template <typename R, typename T1, typename T2, typename T3, typename T4, typename T5>
class CallbackImpl : public CallbackImplBase {
class CallbackImpl<R,T1,T2,T3,T4,T5,empty> : public CallbackImplBase {
public:
virtual ~CallbackImpl () {}
virtual R operator() (T1, T2, T3, T4, T5) = 0;
};
// define CallbackImpl for 6 params
template <typename R, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
class CallbackImpl : public CallbackImplBase {
public:
virtual ~CallbackImpl () {}
virtual R operator() (T1, T2, T3, T4, T5, T6) = 0;
};
// an impl for Functors:
template <typename T, typename R, typename T1, typename T2, typename T3, typename T4,typename T5>
class FunctorCallbackImpl : public CallbackImpl<R,T1,T2,T3,T4,T5> {
template <typename T, typename R, typename T1, typename T2, typename T3, typename T4,typename T5, typename T6>
class FunctorCallbackImpl : public CallbackImpl<R,T1,T2,T3,T4,T5,T6> {
public:
FunctorCallbackImpl (T const &functor)
: m_functor (functor) {}
@@ -160,9 +168,12 @@ public:
R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5) {
return m_functor (a1,a2,a3,a4,a5);
}
R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6) {
return m_functor (a1,a2,a3,a4,a5,a6);
}
virtual bool IsEqual (CallbackImplBase const *other) const {
FunctorCallbackImpl<T,R,T1,T2,T3,T4,T5> const *otherDerived =
dynamic_cast<FunctorCallbackImpl<T,R,T1,T2,T3,T4,T5> const *> (other);
FunctorCallbackImpl<T,R,T1,T2,T3,T4,T5,T6> const *otherDerived =
dynamic_cast<FunctorCallbackImpl<T,R,T1,T2,T3,T4,T5,T6> const *> (other);
if (otherDerived == 0)
{
return false;
@@ -178,8 +189,8 @@ private:
};
// an impl for pointer to member functions
template <typename OBJ_PTR, typename MEM_PTR, typename R, typename T1, typename T2, typename T3, typename T4, typename T5>
class MemPtrCallbackImpl : public CallbackImpl<R,T1,T2,T3,T4,T5> {
template <typename OBJ_PTR, typename MEM_PTR, typename R, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
class MemPtrCallbackImpl : public CallbackImpl<R,T1,T2,T3,T4,T5,T6> {
public:
MemPtrCallbackImpl (OBJ_PTR const&objPtr, MEM_PTR mem_ptr)
: m_objPtr (objPtr), m_memPtr (mem_ptr) {}
@@ -202,9 +213,12 @@ public:
R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5) {
return ((CallbackTraits<OBJ_PTR>::GetReference (m_objPtr)).*m_memPtr) (a1, a2, a3, a4, a5);
}
R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6) {
return ((CallbackTraits<OBJ_PTR>::GetReference (m_objPtr)).*m_memPtr) (a1, a2, a3, a4, a5, a6);
}
virtual bool IsEqual (CallbackImplBase const *other) const {
MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5> const *otherDerived =
dynamic_cast<MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5> const *> (other);
MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5,T6> const *otherDerived =
dynamic_cast<MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5,T6> const *> (other);
if (otherDerived == 0)
{
return false;
@@ -260,22 +274,22 @@ public:
template<typename R,
typename T1 = empty, typename T2 = empty,
typename T3 = empty, typename T4 = empty,
typename T5 = empty>
typename T5 = empty, typename T6 = empty>
class Callback : public CallbackBase {
public:
// There are two dummy args below to ensure that this constructor is
// always properly disambiguited by the c++ compiler
template <typename FUNCTOR>
Callback (FUNCTOR const &functor, bool, bool)
: m_impl (Create<FunctorCallbackImpl<FUNCTOR,R,T1,T2,T3,T4,T5> > (functor))
: m_impl (Create<FunctorCallbackImpl<FUNCTOR,R,T1,T2,T3,T4,T5,T6> > (functor))
{}
template <typename OBJ_PTR, typename MEM_PTR>
Callback (OBJ_PTR const &objPtr, MEM_PTR mem_ptr)
: m_impl (Create<MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5> > (objPtr, mem_ptr))
: m_impl (Create<MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5,T6> > (objPtr, mem_ptr))
{}
Callback (Ptr<CallbackImpl<R,T1,T2,T3,T4,T5> > const &impl)
Callback (Ptr<CallbackImpl<R,T1,T2,T3,T4,T5,T6> > const &impl)
: m_impl (impl)
{}
@@ -305,14 +319,17 @@ public:
R operator() (T1 a1, T2 a2, T3 a3, T4 a4,T5 a5) const {
return (*(PeekImpl ())) (a1,a2,a3,a4,a5);
}
R operator() (T1 a1, T2 a2, T3 a3, T4 a4,T5 a5,T6 a6) const {
return (*(PeekImpl ())) (a1,a2,a3,a4,a5,a6);
}
bool IsEqual (CallbackBase const &other) {
bool IsEqual (CallbackBase const &other) const {
return PeekImpl ()->IsEqual (other.PeekImpl ());
}
bool CheckType (CallbackBase const& other) {
bool CheckType (CallbackBase const& other) const {
CallbackImplBase *otherBase = other.PeekImpl ();
if (dynamic_cast<CallbackImpl<R,T1,T2,T3,T4,T5> *> (otherBase) != 0)
if (dynamic_cast<CallbackImpl<R,T1,T2,T3,T4,T5,T6> *> (otherBase) != 0)
{
return true;
}
@@ -328,27 +345,27 @@ public:
" got=" << typeid (other).name () <<
", expected=" << typeid (*this).name ());
}
const Callback<R, T1,T2,T3,T4,T5> *goodType = static_cast<const Callback<R,T1,T2,T3,T4,T5> *> (&other);
const Callback<R, T1,T2,T3,T4,T5,T6> *goodType = static_cast<const Callback<R,T1,T2,T3,T4,T5,T6> *> (&other);
*this = *goodType;
}
void Assign (Ptr<CallbackImplBase> other) {
CallbackImpl<R,T1,T2,T3,T4,T5> *impl = dynamic_cast<CallbackImpl<R,T1,T2,T3,T4,T5> *> (PeekPointer (other));
CallbackImpl<R,T1,T2,T3,T4,T5,T6> *impl = dynamic_cast<CallbackImpl<R,T1,T2,T3,T4,T5,T6> *> (PeekPointer (other));
if (other == 0)
{
NS_FATAL_ERROR ("Incompatible types. (feed to \"c++filt -t\")"
" got=" << typeid (other).name () <<
", expected=" << typeid (*impl).name ());
}
*this = Callback<R,T1,T2,T3,T4,T5> (impl);
*this = Callback<R,T1,T2,T3,T4,T5,T6> (impl);
}
virtual Ptr<CallbackImplBase>GetImpl (void) const {
return m_impl;
}
private:
virtual CallbackImpl<R,T1,T2,T3,T4,T5> *PeekImpl (void) const {
virtual CallbackImpl<R,T1,T2,T3,T4,T5,T6> *PeekImpl (void) const {
return PeekPointer (m_impl);
}
Ptr<CallbackImpl<R,T1,T2,T3,T4,T5> > m_impl;
Ptr<CallbackImpl<R,T1,T2,T3,T4,T5,T6> > m_impl;
};
/**
@@ -369,7 +386,7 @@ Callback<R> MakeCallback (R (T::*memPtr) (void), OBJ objPtr) {
return Callback<R> (objPtr, memPtr);
}
template <typename T, typename OBJ, typename R>
Callback<R> MakeCallback (R (T::*mem_ptr) () const, OBJ const objPtr) {
Callback<R> MakeCallback (R (T::*mem_ptr) () const, OBJ objPtr) {
return Callback<R> (objPtr, mem_ptr);
}
/**
@@ -381,11 +398,11 @@ Callback<R> MakeCallback (R (T::*mem_ptr) () const, OBJ const objPtr) {
* and potentially return a value.
*/
template <typename T, typename OBJ, typename R, typename T1>
Callback<R,T1> MakeCallback (R (T::*mem_ptr) (T1), OBJ *const objPtr) {
Callback<R,T1> MakeCallback (R (T::*mem_ptr) (T1), OBJ objPtr) {
return Callback<R,T1> (objPtr, mem_ptr);
}
template <typename T, typename OBJ, typename R, typename T1>
Callback<R,T1> MakeCallback (R (T::*mem_ptr) (T1) const, OBJ const *const objPtr) {
Callback<R,T1> MakeCallback (R (T::*mem_ptr) (T1) const, OBJ objPtr) {
return Callback<R,T1> (objPtr, mem_ptr);
}
/**
@@ -397,11 +414,11 @@ Callback<R,T1> MakeCallback (R (T::*mem_ptr) (T1) const, OBJ const *const objPtr
* and potentially return a value.
*/
template <typename T, typename OBJ, typename R, typename T1, typename T2>
Callback<R,T1,T2> MakeCallback (R (T::*mem_ptr) (T1,T2), OBJ *const objPtr) {
Callback<R,T1,T2> MakeCallback (R (T::*mem_ptr) (T1,T2), OBJ objPtr) {
return Callback<R,T1,T2> (objPtr, mem_ptr);
}
template <typename T, typename OBJ, typename R, typename T1, typename T2>
Callback<R,T1,T2> MakeCallback (R (T::*mem_ptr) (T1,T2) const, OBJ const*const objPtr) {
Callback<R,T1,T2> MakeCallback (R (T::*mem_ptr) (T1,T2) const, OBJ objPtr) {
return Callback<R,T1,T2> (objPtr, mem_ptr);
}
/**
@@ -413,11 +430,11 @@ Callback<R,T1,T2> MakeCallback (R (T::*mem_ptr) (T1,T2) const, OBJ const*const o
* and potentially return a value.
*/
template <typename T, typename OBJ, typename R, typename T1,typename T2, typename T3>
Callback<R,T1,T2,T3> MakeCallback (R (T::*mem_ptr) (T1,T2,T3), OBJ *const objPtr) {
Callback<R,T1,T2,T3> MakeCallback (R (T::*mem_ptr) (T1,T2,T3), OBJ objPtr) {
return Callback<R,T1,T2,T3> (objPtr, mem_ptr);
}
template <typename T, typename OBJ, typename R, typename T1,typename T2, typename T3>
Callback<R,T1,T2,T3> MakeCallback (R (T::*mem_ptr) (T1,T2,T3) const, OBJ const*const objPtr) {
Callback<R,T1,T2,T3> MakeCallback (R (T::*mem_ptr) (T1,T2,T3) const, OBJ objPtr) {
return Callback<R,T1,T2,T3> (objPtr, mem_ptr);
}
/**
@@ -429,11 +446,11 @@ Callback<R,T1,T2,T3> MakeCallback (R (T::*mem_ptr) (T1,T2,T3) const, OBJ const*c
* and potentially return a value.
*/
template <typename T, typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4>
Callback<R,T1,T2,T3,T4> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4), OBJ *const objPtr) {
Callback<R,T1,T2,T3,T4> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4), OBJ objPtr) {
return Callback<R,T1,T2,T3,T4> (objPtr, mem_ptr);
}
template <typename T, typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4>
Callback<R,T1,T2,T3,T4> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4) const, OBJ const*const objPtr) {
Callback<R,T1,T2,T3,T4> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4) const, OBJ objPtr) {
return Callback<R,T1,T2,T3,T4> (objPtr, mem_ptr);
}
/**
@@ -445,13 +462,29 @@ Callback<R,T1,T2,T3,T4> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4) const, OBJ c
* and potentially return a value.
*/
template <typename T, typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4,typename T5>
Callback<R,T1,T2,T3,T4,T5> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ *const objPtr) {
Callback<R,T1,T2,T3,T4,T5> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ objPtr) {
return Callback<R,T1,T2,T3,T4,T5> (objPtr, mem_ptr);
}
template <typename T, typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4,typename T5>
Callback<R,T1,T2,T3,T4,T5> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5) const, OBJ const*const objPtr) {
Callback<R,T1,T2,T3,T4,T5> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5) const, OBJ objPtr) {
return Callback<R,T1,T2,T3,T4,T5> (objPtr, mem_ptr);
}
/**
* \ingroup MakeCallback
* \param mem_ptr class method member pointer
* \param objPtr class instance
* \return a wrapper Callback
* Build Callbacks for class method members which takes five arguments
* and potentially return a value.
*/
template <typename T, typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4,typename T5,typename T6>
Callback<R,T1,T2,T3,T4,T5,T6> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5,T6), OBJ objPtr) {
return Callback<R,T1,T2,T3,T4,T5,T6> (objPtr, mem_ptr);
}
template <typename T, typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4,typename T5, typename T6>
Callback<R,T1,T2,T3,T4,T5,T6> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5,T6) const, OBJ objPtr) {
return Callback<R,T1,T2,T3,T4,T5,T6> (objPtr, mem_ptr);
}
/**
* \ingroup MakeCallback
@@ -519,6 +552,17 @@ template <typename R, typename T1, typename T2,typename T3,typename T4,typename
Callback<R,T1,T2,T3,T4,T5> MakeCallback (R (*fnPtr) (T1,T2,T3,T4,T5)) {
return Callback<R,T1,T2,T3,T4,T5> (fnPtr, true, true);
}
/**
* \ingroup MakeCallback
* \param fnPtr function pointer
* \return a wrapper Callback
* Build Callbacks for functions which takes five arguments
* and potentially return a value.
*/
template <typename R, typename T1, typename T2,typename T3,typename T4,typename T5,typename T6>
Callback<R,T1,T2,T3,T4,T5,T6> MakeCallback (R (*fnPtr) (T1,T2,T3,T4,T5,T6)) {
return Callback<R,T1,T2,T3,T4,T5,T6> (fnPtr, true, true);
}
@@ -587,6 +631,17 @@ template <typename R, typename T1, typename T2,typename T3,typename T4,typename
Callback<R,T1,T2,T3,T4,T5> MakeNullCallback (void) {
return Callback<R,T1,T2,T3,T4,T5> ();
}
/**
* \ingroup MakeCallback
* \overload Callback<R> MakeNullCallback (void)
* \return a wrapper Callback
* Build a null callback which takes five arguments
* and potentially return a value.
*/
template <typename R, typename T1, typename T2,typename T3,typename T4,typename T5,typename T6>
Callback<R,T1,T2,T3,T4,T5,T6> MakeNullCallback (void) {
return Callback<R,T1,T2,T3,T4,T5,T6> ();
}
/*
@@ -596,9 +651,10 @@ Callback<R,T1,T2,T3,T4,T5> MakeNullCallback (void) {
*/
// an impl for Bound Functors:
template <typename T, typename R, typename TX, typename T1, typename T2, typename T3, typename T4,typename T5>
class BoundFunctorCallbackImpl : public CallbackImpl<R,T1,T2,T3,T4,T5> {
class BoundFunctorCallbackImpl : public CallbackImpl<R,T1,T2,T3,T4,T5,empty> {
public:
BoundFunctorCallbackImpl (T const &functor, TX a)
template <typename FUNCTOR, typename ARG>
BoundFunctorCallbackImpl (FUNCTOR functor, ARG a)
: m_functor (functor), m_a (a) {}
virtual ~BoundFunctorCallbackImpl () {}
R operator() (void) {
@@ -635,38 +691,48 @@ public:
}
private:
T m_functor;
TX m_a;
typename TypeTraits<TX>::ReferencedType m_a;
};
template <typename R, typename TX>
Callback<R> MakeBoundCallback (R (*fnPtr) (TX), TX a) {
Ptr<CallbackImpl<R,empty,empty,empty,empty,empty> > impl =
template <typename R, typename TX, typename ARG>
Callback<R> MakeBoundCallback (R (*fnPtr) (TX), ARG a) {
Ptr<CallbackImpl<R,empty,empty,empty,empty,empty,empty> > impl =
Create<BoundFunctorCallbackImpl<R (*) (TX),R,TX,empty,empty,empty,empty,empty> >(fnPtr, a);
return Callback<R> (impl);
}
template <typename R, typename TX, typename T1>
Callback<R,T1> MakeBoundCallback (R (*fnPtr) (TX,T1), TX a) {
Ptr<CallbackImpl<R,T1,empty,empty,empty,empty> > impl =
template <typename R, typename TX, typename ARG,
typename T1>
Callback<R,T1> MakeBoundCallback (R (*fnPtr) (TX,T1), ARG a) {
Ptr<CallbackImpl<R,T1,empty,empty,empty,empty,empty> > impl =
Create<BoundFunctorCallbackImpl<R (*) (TX,T1),R,TX,T1,empty,empty,empty,empty> > (fnPtr, a);
return Callback<R,T1> (impl);
}
template <typename R, typename TX, typename T1, typename T2>
Callback<R,T1,T2> MakeBoundCallback (R (*fnPtr) (TX,T1,T2), TX a) {
Ptr<CallbackImpl<R,T1,T2,empty,empty,empty> > impl =
template <typename R, typename TX, typename ARG,
typename T1, typename T2>
Callback<R,T1,T2> MakeBoundCallback (R (*fnPtr) (TX,T1,T2), ARG a) {
Ptr<CallbackImpl<R,T1,T2,empty,empty,empty,empty> > impl =
Create<BoundFunctorCallbackImpl<R (*) (TX,T1,T2),R,TX,T1,T2,empty,empty,empty> > (fnPtr, a);
return Callback<R,T1,T2> (impl);
}
template <typename R, typename TX, typename T1, typename T2,typename T3,typename T4>
Callback<R,T1,T2,T3,T4> MakeBoundCallback (R (*fnPtr) (TX,T1,T2,T3,T4), TX a) {
Ptr<CallbackImpl<R,T1,T2,T3,T4,empty> > impl =
template <typename R, typename TX, typename ARG,
typename T1, typename T2,typename T3>
Callback<R,T1,T2,T3> MakeBoundCallback (R (*fnPtr) (TX,T1,T2,T3), ARG a) {
Ptr<CallbackImpl<R,T1,T2,T3,empty,empty,empty> > impl =
Create<BoundFunctorCallbackImpl<R (*) (TX,T1,T2,T3),R,TX,T1,T2,T3,empty,empty> > (fnPtr, a);
return Callback<R,T1,T2,T3> (impl);
}
template <typename R, typename TX, typename ARG,
typename T1, typename T2,typename T3,typename T4>
Callback<R,T1,T2,T3,T4> MakeBoundCallback (R (*fnPtr) (TX,T1,T2,T3,T4), ARG a) {
Ptr<CallbackImpl<R,T1,T2,T3,T4,empty,empty> > impl =
Create<BoundFunctorCallbackImpl<R (*) (TX,T1,T2,T3,T4),R,TX,T1,T2,T3,T4,empty> > (fnPtr, a);
return Callback<R,T1,T2,T3,T4> (impl);
}
template <typename R, typename TX, typename T1, typename T2,typename T3,typename T4,typename T5>
Callback<R,T1,T2,T3,T4,T5> MakeBoundCallback (R (*fnPtr) (TX,T1,T2,T3,T4,T5), TX a) {
Ptr<CallbackImpl<R,T1,T2,T3,T4,T5> > impl =
template <typename R, typename TX, typename ARG,
typename T1, typename T2,typename T3,typename T4,typename T5>
Callback<R,T1,T2,T3,T4,T5> MakeBoundCallback (R (*fnPtr) (TX,T1,T2,T3,T4,T5), ARG a) {
Ptr<CallbackImpl<R,T1,T2,T3,T4,T5,empty> > impl =
Create<BoundFunctorCallbackImpl<R (*) (TX,T1,T2,T3,T4,T5),R,TX,T1,T2,T3,T4,T5> > (fnPtr, a);
return Callback<R,T1,T2,T3,T4,T5> (impl);
}

View File

@@ -0,0 +1,595 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "composite-trace-resolver.h"
#include "debug.h"
NS_DEBUG_COMPONENT_DEFINE ("CompositeTraceResolver");
namespace ns3 {
CompositeTraceResolver::CompositeTraceResolver ()
{}
CompositeTraceResolver::~CompositeTraceResolver ()
{
for (TraceItems::iterator i = m_items.begin (); i != m_items.end (); i++)
{
delete *i;
}
m_items.clear ();
}
void
CompositeTraceResolver::AddItem (ResolveItem *item)
{
m_items.push_back (item);
}
void
CompositeTraceResolver::Add (std::string name,
Callback<Ptr<TraceResolver> > createResolver)
{
class MakerResolveItem : public ResolveItem
{
public:
virtual void Connect (std::string subpath, const CallbackBase &cb, const TraceContext &context)
{maker ()->Connect (subpath, cb, context);}
virtual void Disconnect (std::string subpath, const CallbackBase &cb)
{maker ()->Disconnect (subpath, cb);}
virtual void CollectSources (std::string path, const TraceContext &context,
SourceCollection *collection)
{
path.append ("/");
path.append (this->name);
TraceContext ctx = context;
ctx.Union (this->context);
this->maker ()->CollectSources (path, ctx, collection);
}
virtual void TraceAll (std::ostream &os, const TraceContext &context)
{
TraceContext ctx = context;
ctx.Union (this->context);
this->maker ()->TraceAll (os, ctx);
}
Callback<Ptr<TraceResolver> > maker;
} *item = new MakerResolveItem ();
item->name = name;
item->context = TraceContext ();
item->maker = createResolver;
AddItem (item);
}
void
CompositeTraceResolver::AddSource (std::string name,
const TraceDoc &doc,
const TraceSource &trace)
{
DoAddSource (name, doc, trace, TraceContext ());
}
void
CompositeTraceResolver::DoAddSource (std::string name,
const TraceDoc &doc,
const TraceSource &trace,
const TraceContext &context)
{
class SourceResolveItem : public ResolveItem
{
public:
virtual void Connect (std::string subpath, const CallbackBase &cb, const TraceContext &context)
{if (subpath == "") {trace->AddCallback (cb, context);}}
virtual void Disconnect (std::string subpath, const CallbackBase &cb)
{if (subpath == "") {trace->RemoveCallback (cb);}}
virtual void CollectSources (std::string path, const TraceContext &context,
SourceCollection *collection)
{
path.append ("/");
path.append (this->name);
TraceContext ctx = context;
ctx.Union (this->context);
collection->AddUnique (path, ctx, this->doc);
}
virtual void TraceAll (std::ostream &os, const TraceContext &context)
{
TraceContext ctx = context;
ctx.Union (this->context);
this->trace->ConnectPrinter (os, ctx);
}
TraceSource *trace;
TraceDoc doc;
} *item = new SourceResolveItem ();
item->name = name;
item->context = context;
item->trace = const_cast<TraceSource *> (&trace);
item->doc = doc;
AddItem (item);
}
void
CompositeTraceResolver::AddComposite (std::string name, Ptr<Object> composite)
{
DoAddComposite (name, composite, TraceContext ());
}
void
CompositeTraceResolver::DoAddComposite (std::string name, Ptr<Object> composite, const TraceContext &context)
{
class CompositeResolveItem : public ResolveItem
{
public:
virtual void Connect (std::string subpath, const CallbackBase &cb, const TraceContext &context)
{composite->GetTraceResolver ()->Connect (subpath, cb, context);}
virtual void Disconnect (std::string subpath, const CallbackBase &cb)
{composite->TraceDisconnect (subpath, cb);}
virtual void CollectSources (std::string path, const TraceContext &context,
SourceCollection *collection)
{
path.append ("/");
path.append (this->name);
TraceContext ctx = context;
ctx.Union (this->context);
this->composite->GetTraceResolver ()->CollectSources (path, ctx, collection);
}
virtual void TraceAll (std::ostream &os, const TraceContext &context)
{
TraceContext ctx = context;
ctx.Union (this->context);
this->composite->GetTraceResolver ()->TraceAll (os, ctx);
}
Ptr<Object> composite;
} *item = new CompositeResolveItem ();
item->name = name;
item->context = context;
item->composite = composite;
AddItem (item);
}
void
CompositeTraceResolver::SetParentResolver (Ptr<TraceResolver> resolver)
{
m_parent = resolver;
}
void
CompositeTraceResolver::Connect (std::string path, CallbackBase const &cb, const TraceContext &context)
{
NS_DEBUG ("connect path="<<path);
class ConnectOperation : public Operation
{
public:
ConnectOperation (const CallbackBase &cb, const TraceContext &context)
: m_cb (cb), m_context (context)
{}
virtual void Do (std::string subpath, ResolveItem *item) const
{
NS_DEBUG ("connect to path="<<subpath<<" name="<<item->name);
TraceContext context = m_context;
context.Union (item->context);
item->Connect (subpath, m_cb, context);
}
virtual void DoParent (std::string path, Ptr<TraceResolver> parent) const
{
if (parent != 0)
{
parent->Connect (path, m_cb, m_context);
}
}
private:
const CallbackBase &m_cb;
const TraceContext &m_context;
} operation = ConnectOperation (cb, context);
DoRecursiveOperation (path, operation);
}
void
CompositeTraceResolver::DoRecursiveOperation (std::string path,
const Operation &operation)
{
if (path == "")
{
return;
}
std::string id = GetElement (path);
std::string subpath = GetSubpath (path);
if (id == "*")
{
for (TraceItems::const_iterator i = m_items.begin (); i != m_items.end (); i++)
{
operation.Do (subpath, *i);
}
operation.DoParent (path, m_parent);
return;
}
std::string::size_type start, end;
start = id.find_first_of ("(", 0);
end = id.find_first_of (")", 0);
if (start != 0 || end != (id.size ()-1))
{
for (TraceItems::const_iterator i = m_items.begin (); i != m_items.end (); i++)
{
if ((*i)->name == id)
{
operation.Do (subpath, *i);
operation.DoParent (path, m_parent);
return;
}
}
}
std::list<std::string> names;
std::string alternatives = std::string (id, start+1, end-1);
std::string::size_type next_pos, cur_pos;
next_pos = 0;
cur_pos = 0;
while (true)
{
std::string element;
next_pos = alternatives.find ("|", cur_pos);
if (next_pos == std::string::npos)
{
element = std::string (alternatives, cur_pos, alternatives.size ());
names.push_back (element);
break;
}
element = std::string (alternatives, cur_pos, next_pos);
names.push_back (element);
cur_pos = next_pos + 1;
}
for (std::list<std::string>::const_iterator i = names.begin (); i != names.end (); i++)
{
for (TraceItems::const_iterator j = m_items.begin (); j != m_items.end (); j++)
{
if ((*j)->name == *i)
{
operation.Do (subpath, *j);
break;
}
}
}
operation.DoParent (path, m_parent);
}
void
CompositeTraceResolver::Disconnect (std::string path, CallbackBase const &cb)
{
NS_DEBUG ("disconnect path="<<path);
class DisconnectOperation : public Operation
{
public:
DisconnectOperation (const CallbackBase &cb)
: m_cb (cb)
{}
virtual void Do (std::string subpath, ResolveItem *item) const
{
NS_DEBUG ("disconnect from path="<<subpath<<" name="<<item->name);
item->Disconnect (subpath, m_cb);
}
virtual void DoParent (std::string path, Ptr<TraceResolver> parent) const
{
if (parent != 0)
{
parent->Disconnect (path, m_cb);
}
}
private:
const CallbackBase &m_cb;
} operation = DisconnectOperation (cb);
DoRecursiveOperation (path, operation);
}
void
CompositeTraceResolver::CollectSources (std::string path, const TraceContext &context,
SourceCollection *collection)
{
for (TraceItems::const_iterator i = m_items.begin (); i != m_items.end (); i++)
{
NS_DEBUG ("print " << (*i)->name);
(*i)->CollectSources (path, context, collection);
}
if (m_parent != 0)
{
m_parent->CollectSources (path, context, collection);
}
}
void
CompositeTraceResolver::TraceAll (std::ostream &os, const TraceContext &context)
{
for (TraceItems::const_iterator i = m_items.begin (); i != m_items.end (); i++)
{
NS_DEBUG ("print " << (*i)->name);
(*i)->TraceAll (os, context);
}
if (m_parent != 0)
{
m_parent->TraceAll (os, context);
}
}
}//namespace ns3
#ifdef RUN_SELF_TESTS
#include "test.h"
#include "trace-context-element.h"
namespace ns3 {
class TraceSourceTest : public TraceContextElement
{
public:
enum Sources {
DOUBLEA,
DOUBLEB,
UINT16_T
};
static uint16_t GetUid (void)
{static uint16_t uid = AllocateUid<TraceSourceTest> ("TraceSourceTest"); return uid;}
void Print (std::ostream &os)
{os << "tracesource=";
if (m_sources == DOUBLEA) {os << "doubleA";}
else if (m_sources == DOUBLEB) {os << "doubleB";}
else if (m_sources == UINT16_T) {os << "uint16_t";}
}
std::string GetTypeName (void) {return "ns3::TraceSourceTest";}
TraceSourceTest () : m_sources (TraceSourceTest::DOUBLEA) {}
TraceSourceTest (enum Sources sources) :m_sources (sources) {}
bool IsDoubleA (void) const {return m_sources == TraceSourceTest::DOUBLEA;}
bool IsDoubleB (void) const {return m_sources == TraceSourceTest::DOUBLEB;}
bool IsUint16 (void) const {return m_sources == TraceSourceTest::UINT16_T;}
private:
enum TraceSourceTest::Sources m_sources;
};
class SubTraceSourceTest : public TraceContextElement
{
public:
enum Sources {
INT,
};
static uint16_t GetUid (void)
{static uint16_t uid = AllocateUid<SubTraceSourceTest> ("SubTraceSourceTest"); return uid;}
void Print (std::ostream &os)
{os << "subtracesource=int";}
std::string GetTypeName (void) const {return "ns3::SubTraceSourceTest";}
SubTraceSourceTest () : m_sources (SubTraceSourceTest::INT) {}
SubTraceSourceTest (enum Sources sources) : m_sources (sources) {}
private:
enum Sources m_sources;
};
class CompositeTraceResolverTest : public Test
{
public:
CompositeTraceResolverTest ();
virtual ~CompositeTraceResolverTest ();
virtual bool RunTests (void);
private:
void TraceDouble (TraceContext const &context, double v);
void TraceInt (TraceContext const &context, int v);
Ptr<TraceResolver> CreateSubResolver ();
bool m_gotDoubleA;
bool m_gotDoubleB;
CallbackTraceSource<int> m_traceInt;
bool m_gotInt;
};
CompositeTraceResolverTest::CompositeTraceResolverTest ()
: Test ("CompositeTraceResolver")
{}
CompositeTraceResolverTest::~CompositeTraceResolverTest ()
{}
void
CompositeTraceResolverTest::TraceDouble (TraceContext const &context, double v)
{
TraceSourceTest source;
context.GetElement (source);
if (source.IsDoubleA ())
{
m_gotDoubleA = true;
}
else if (source.IsDoubleB ())
{
m_gotDoubleB = true;
}
else
{
NS_FATAL_ERROR ("should not get any other trace source in this sink");
}
}
void
CompositeTraceResolverTest::TraceInt (TraceContext const &context, int v)
{
m_gotInt = true;
}
Ptr<TraceResolver>
CompositeTraceResolverTest::CreateSubResolver (void)
{
Ptr<CompositeTraceResolver> subresolver = Create<CompositeTraceResolver> ();
subresolver->AddSource ("trace-int", TraceDoc ("test source"), m_traceInt,
SubTraceSourceTest (SubTraceSourceTest::INT));
return subresolver;
}
bool
CompositeTraceResolverTest::RunTests (void)
{
bool ok = true;
CallbackTraceSource<double> traceDoubleA;
CallbackTraceSource<double> traceDoubleB;
TraceContext context;
CompositeTraceResolver resolver;
resolver.AddSource ("trace-double-a", TraceDoc ("test source"), traceDoubleA,
TraceSourceTest (TraceSourceTest::DOUBLEA));
resolver.AddSource ("trace-double-b", TraceDoc ("test source"), traceDoubleB,
TraceSourceTest (TraceSourceTest::DOUBLEB));
resolver.Connect ("/*", MakeCallback (&CompositeTraceResolverTest::TraceDouble, this), TraceContext ());
m_gotDoubleA = false;
m_gotDoubleB = false;
traceDoubleA (0);
if (!m_gotDoubleA || m_gotDoubleB)
{
ok = false;
}
m_gotDoubleA = false;
traceDoubleA (0);
traceDoubleB (0);
if (!m_gotDoubleA || !m_gotDoubleB)
{
ok = false;
}
m_gotDoubleA = false;
m_gotDoubleB = false;
resolver.Disconnect ("/*", MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
m_gotDoubleA = false;
m_gotDoubleB = false;
traceDoubleA (0);
traceDoubleB (0);
if (m_gotDoubleA || m_gotDoubleB)
{
ok = false;
}
resolver.Connect ("/trace-double-a",
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this), TraceContext ());
m_gotDoubleA = false;
m_gotDoubleB = false;
traceDoubleA (0);
traceDoubleB (0);
if (!m_gotDoubleA || m_gotDoubleB)
{
ok = false;
}
resolver.Disconnect ("/trace-double-a",
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
resolver.Connect ("/(trace-double-a)",
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this), TraceContext ());
m_gotDoubleA = false;
m_gotDoubleB = false;
traceDoubleA (0);
traceDoubleB (0);
if (!m_gotDoubleA || m_gotDoubleB)
{
ok = false;
}
resolver.Disconnect ("/trace-double-a",
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
resolver.Connect ("/(trace-double-a|trace-double-b)",
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this), TraceContext ());
m_gotDoubleA = false;
m_gotDoubleB = false;
traceDoubleA (0);
traceDoubleB (0);
if (!m_gotDoubleA || !m_gotDoubleB)
{
ok = false;
}
resolver.Disconnect ("/trace-double-a",
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
m_gotDoubleA = false;
m_gotDoubleB = false;
traceDoubleA (0);
traceDoubleB (0);
if (m_gotDoubleA || !m_gotDoubleB)
{
ok = false;
}
resolver.Disconnect ("/(trace-double-a|trace-double-b)",
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
m_gotDoubleA = false;
m_gotDoubleB = false;
traceDoubleA (0);
traceDoubleB (0);
if (m_gotDoubleA || m_gotDoubleB)
{
ok = false;
}
resolver.Add ("subresolver",
MakeCallback (&CompositeTraceResolverTest::CreateSubResolver, this));
resolver.Connect ("/subresolver/trace-int",
MakeCallback (&CompositeTraceResolverTest::TraceInt, this), TraceContext ());
m_gotInt = false;
m_traceInt (1);
if (!m_gotInt)
{
ok = false;
}
resolver.Disconnect ("/subresolver/trace-int",
MakeCallback (&CompositeTraceResolverTest::TraceInt, this));
m_gotInt = false;
m_traceInt (1);
if (m_gotInt)
{
ok = false;
}
resolver.Connect ("/*/trace-int",
MakeCallback (&CompositeTraceResolverTest::TraceInt, this), TraceContext ());
m_gotInt = false;
m_traceInt (1);
if (!m_gotInt)
{
ok = false;
}
resolver.Disconnect ("/subresolver/trace-int",
MakeCallback (&CompositeTraceResolverTest::TraceInt, this));
m_gotInt = false;
m_traceInt (1);
if (m_gotInt)
{
ok = false;
}
SVTraceSource<uint16_t> source;
resolver.AddSource ("uint16_t", TraceDoc ("test source"), source, TraceSourceTest (TraceSourceTest::UINT16_T));
return ok;
}
static CompositeTraceResolverTest g_compositeTraceResolverTest;
}//namespace ns3
#endif /* RUN_SELF_TESTS */

View File

@@ -0,0 +1,233 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#ifndef COMPOSITE_TRACE_RESOLVER_H
#define COMPOSITE_TRACE_RESOLVER_H
#include <vector>
#include "callback.h"
#include "ptr.h"
#include "trace-resolver.h"
#include "callback-trace-source.h"
#include "uv-trace-source.h"
#include "sv-trace-source.h"
#include "fv-trace-source.h"
#include "array-trace-resolver.h"
#include "trace-doc.h"
namespace ns3 {
/**
* \brief a helper class to aggregate contained TraceResolver and other trace sources.
* \ingroup tracing
*/
class CompositeTraceResolver : public TraceResolver
{
public:
CompositeTraceResolver ();
virtual ~CompositeTraceResolver ();
/**
* \param name name of trace source
* \param doc the documentation associated to this trace source
* \param trace a callback trace source
* \param context the context associated to this trace source
*
* Add a callback trace source in this resolver. This trace
* source will match the name specified during namespace
* resolution. The TraceContext of this trace source will also
* be automatically extended to contain the input context.
*/
template <typename T>
void AddSource (std::string name, const TraceDoc &doc,
const TraceSource &trace, T const &context);
/**
* \param name name of trace source
* \param doc the documentation associated to this trace source
* \param trace a callback trace source
*
* Add a callback trace source in this resolver. This trace
* source will match the name specified during namespace
* resolution.
*/
void AddSource (std::string name,
const TraceDoc &doc,
const TraceSource &trace);
/**
* \param name the name of the composite element
* \param composite the composite object
*
* The input composite object will be used to resolve a connection
* of a disconnection attempt if its name matches the trace path.
*
*/
void AddComposite (std::string name, Ptr<Object> composite);
/**
* \param name the name of the composite element
* \param composite the composite object
* \param contextElement the context element associated to the composite
*
* The input composite object will be used to resolve a connection
* of a disconnection attempt if its name matches the trace path.
* The contextElement will be appended to the TraceContext during connection.
*/
template <typename T>
void AddComposite (std::string name, Ptr<Object> composite, const T &contextElement);
/**
* \param name the name of the array
* \param begin an iterator which points to the first element of the array
* \param end an iterator which points to the last element of the array
* \param index an object which can store the index of an element in the
* array. In practice, this object should support a constructor
* whose single argument is an array index.
*/
template <typename ITERATOR, typename INDEX>
void AddArray (std::string name,
ITERATOR begin, ITERATOR end, INDEX index);
/**
* \param parent the parent trace resolver
*
* The parent trace resolver is the trace resolver returned by the
* GetTraceResolver method of the base class of the caller. It is
* used during connection and disconnection to chain up the connect
* and disconnect calls to the parent.
*/
void SetParentResolver (Ptr<TraceResolver> parent);
private:
virtual void Connect (std::string path, CallbackBase const &cb, const TraceContext &context);
virtual void Disconnect (std::string path, CallbackBase const &cb);
virtual void CollectSources (std::string path, const TraceContext &context,
SourceCollection *collection);
virtual void TraceAll (std::ostream &os, const TraceContext &context);
friend class CompositeTraceResolverTest;
class ResolveItem
{
public:
virtual ~ResolveItem () {}
virtual void Connect (std::string subpath, const CallbackBase &cb, const TraceContext &context) = 0;
virtual void Disconnect (std::string subpath, const CallbackBase &cb) = 0;
virtual void CollectSources (std::string path, const TraceContext &context,
SourceCollection *collection) = 0;
virtual void TraceAll (std::ostream &os, const TraceContext &context) = 0;
std::string name;
TraceContext context;
};
typedef std::vector<ResolveItem *> TraceItems;
class Operation
{
public:
virtual ~Operation () {}
virtual void Do (std::string subpath, ResolveItem *item) const = 0;
virtual void DoParent (std::string path, Ptr<TraceResolver> parent) const = 0;
};
void AddItem (ResolveItem *item);
void DoRecursiveOperation (std::string path,
const Operation &operation);
void DoRecursiveOperationForParent (std::string path,
const Operation &operation);
void DoAddComposite (std::string name, Ptr<Object> composite, const TraceContext &context);
void DoAddSource (std::string name,
const TraceDoc &doc,
const TraceSource &trace,
const TraceContext &context);
void Add (std::string name,
Callback<Ptr<TraceResolver> > createResolver);
CompositeTraceResolver::TraceItems m_items;
Ptr<TraceResolver> m_parent;
};
}//namespace ns3
namespace ns3 {
template <typename T>
void
CompositeTraceResolver::AddSource (std::string name,
const TraceDoc &doc,
const TraceSource &trace,
T const &context)
{
TraceContext ctx;
ctx.AddElement (context);
DoAddSource (name, doc, trace, ctx);
}
template <typename ITERATOR, typename INDEX>
void
CompositeTraceResolver::AddArray (std::string name,
ITERATOR begin, ITERATOR end, INDEX index)
{
class ArrayResolveItem : public ResolveItem
{
public:
virtual void Connect (std::string subpath, const CallbackBase &cb, const TraceContext &context)
{array->Connect (subpath, cb, context);}
virtual void Disconnect (std::string subpath, const CallbackBase &cb)
{array->Disconnect (subpath, cb);}
virtual void CollectSources (std::string path, const TraceContext &context,
SourceCollection *collection)
{
path.append ("/");
path.append (this->name);
TraceContext ctx = context;
ctx.Union (this->context);
array->CollectSources (path, ctx, collection);
}
virtual void TraceAll (std::ostream &os, const TraceContext &context)
{
TraceContext ctx = context;
ctx.Union (this->context);
array->TraceAll (os, ctx);
}
Ptr<ArrayTraceResolver<INDEX> > array;
} *item = new ArrayResolveItem ();
item->name = name;
item->context = TraceContext ();
item->array = Create<ArrayTraceResolver<INDEX> > ();
item->array->SetIterators (begin, end);
AddItem (item);
}
template <typename T>
void
CompositeTraceResolver::AddComposite (std::string name, Ptr<Object> composite, const T &contextElement)
{
TraceContext context;
context.AddElement (contextElement);
DoAddComposite (name, composite, context);
}
}//namespace ns3
#endif /* COMPOSITE_TRACE_RESOLVER_H */

View File

@@ -23,11 +23,12 @@
#define F_VARIABLE_TRACER_H
#include "callback-trace-source.h"
#include "trace-source.h"
#include <stdint.h>
namespace ns3 {
class FVTraceSourceBase {
class FVTraceSourceBase : public TraceSource {
public:
typedef CallbackTraceSource<double, double> ChangeNotifyCallback;
@@ -39,12 +40,15 @@ public:
~FVTraceSourceBase () {}
void AddCallback (CallbackBase const & callback, TraceContext const & context) {
virtual void AddCallback (CallbackBase const & callback, TraceContext const & context) {
m_callback.AddCallback (callback, context);
}
void RemoveCallback (CallbackBase const & callback) {
virtual void RemoveCallback (CallbackBase const & callback) {
m_callback.RemoveCallback (callback);
}
virtual void ConnectPrinter (std::ostream &os, const TraceContext &context) {
m_callback.ConnectPrinter (os, context);
}
protected:
void notify (double oldVal, double newVal) {
if (oldVal != newVal)

View File

@@ -22,8 +22,12 @@
#include "assert.h"
#include "singleton.h"
#include "uid-manager.h"
#include "trace-resolver.h"
#include "debug.h"
#include <vector>
NS_DEBUG_COMPONENT_DEFINE ("Object");
namespace {
class IidManager : public ns3::UidManager
@@ -34,6 +38,7 @@ class IidTree
public:
void SetParent (uint16_t child, const uint16_t *parent);
uint16_t LookupParent (uint16_t child);
private:
std::vector<const uint16_t *> m_parents;
};
@@ -55,6 +60,68 @@ IidTree::LookupParent (uint16_t child)
namespace ns3 {
class InterfaceIdTraceResolver : public TraceResolver
{
public:
InterfaceIdTraceResolver (Ptr<const Object> aggregate);
virtual void Connect (std::string path, CallbackBase const &cb, const TraceContext &context);
virtual void Disconnect (std::string path, CallbackBase const &cb);
virtual void CollectSources (std::string path, const TraceContext &context,
SourceCollection *collection);
virtual void TraceAll (std::ostream &os, const TraceContext &context);
private:
Ptr<const Object> ParseForInterface (std::string path);
Ptr<const Object> m_aggregate;
};
InterfaceIdTraceResolver::InterfaceIdTraceResolver (Ptr<const Object> aggregate)
: m_aggregate (aggregate)
{}
Ptr<const Object>
InterfaceIdTraceResolver::ParseForInterface (std::string path)
{
std::string element = GetElement (path);
std::string::size_type dollar_pos = element.find ("$");
if (dollar_pos != 0)
{
return 0;
}
std::string interfaceName = element.substr (1, std::string::npos);
InterfaceId interfaceId = InterfaceId::LookupByName (interfaceName);
Ptr<Object> interface = m_aggregate->QueryInterface<Object> (interfaceId);
return interface;
}
void
InterfaceIdTraceResolver::Connect (std::string path, CallbackBase const &cb, const TraceContext &context)
{
Ptr<const Object> interface = ParseForInterface (path);
if (interface != 0)
{
interface->GetTraceResolver ()->Connect (GetSubpath (path), cb, context);
}
}
void
InterfaceIdTraceResolver::Disconnect (std::string path, CallbackBase const &cb)
{
Ptr<const Object> interface = ParseForInterface (path);
if (interface != 0)
{
interface->TraceDisconnect (GetSubpath (path), cb);
}
}
void
InterfaceIdTraceResolver::CollectSources (std::string path, const TraceContext &context,
SourceCollection *collection)
{
m_aggregate->DoCollectSources (path, context, collection);
}
void
InterfaceIdTraceResolver::TraceAll (std::ostream &os, const TraceContext &context)
{
m_aggregate->DoTraceAll (os, context);
}
InterfaceId::InterfaceId (uint16_t iid)
: m_iid (iid)
{}
@@ -72,6 +139,12 @@ InterfaceId::LookupParent (InterfaceId iid)
{
return Singleton<IidTree>::Get ()->LookupParent (iid.m_iid);
}
std::string
InterfaceId::GetName (void) const
{
std::string name = Singleton<IidManager>::Get ()->LookupByUid (m_iid);
return name;
}
bool operator == (const InterfaceId &a, const InterfaceId &b)
{
@@ -109,6 +182,7 @@ Object::Object ()
: m_count (1),
m_iid (Object::iid),
m_disposed (false),
m_collecting (false),
m_next (this)
{}
Object::~Object ()
@@ -163,6 +237,17 @@ Object::AddInterface (Ptr<Object> o)
NS_ASSERT (o->Check ());
}
void
Object::TraceConnect (std::string path, const CallbackBase &cb) const
{
GetTraceResolver ()->Connect (path, cb, TraceContext ());
}
void
Object::TraceDisconnect (std::string path, const CallbackBase &cb) const
{
GetTraceResolver ()->Disconnect (path, cb);
}
void
Object::SetInterfaceId (InterfaceId iid)
{
@@ -176,6 +261,14 @@ Object::DoDispose (void)
NS_ASSERT (!m_disposed);
}
Ptr<TraceResolver>
Object::GetTraceResolver (void) const
{
Ptr<InterfaceIdTraceResolver> resolver =
Create<InterfaceIdTraceResolver> (this);
return resolver;
}
bool
Object::Check (void) const
{
@@ -209,12 +302,77 @@ Object::MaybeDelete (void) const
} while (current != end);
}
void
Object::DoCollectSources (std::string path, const TraceContext &context,
TraceResolver::SourceCollection *collection) const
{
const Object *current;
current = this;
do {
if (current->m_collecting)
{
return;
}
current = current->m_next;
} while (current != this);
m_collecting = true;
current = this->m_next;
while (current != this)
{
NS_ASSERT (current != 0);
NS_DEBUG ("collect current=" << current);
InterfaceId cur = current->m_iid;
while (cur != Object::iid)
{
std::string name = cur.GetName ();
std::string fullpath = path;
fullpath.append ("/$");
fullpath.append (name);
NS_DEBUG ("collect: " << fullpath);
current->GetTraceResolver ()->CollectSources (fullpath, context, collection);
cur = InterfaceId::LookupParent (cur);
}
current = current->m_next;
}
m_collecting = false;
}
void
Object::DoTraceAll (std::ostream &os, const TraceContext &context) const
{
const Object *current;
current = this;
do {
if (current->m_collecting)
{
return;
}
current = current->m_next;
} while (current != this);
m_collecting = true;
current = this->m_next;
while (current != this)
{
NS_ASSERT (current != 0);
current->GetTraceResolver ()->TraceAll (os, context);
current = current->m_next;
}
m_collecting = false;
}
} // namespace ns3
#ifdef RUN_SELF_TESTS
#include "test.h"
#include "sv-trace-source.h"
#include "composite-trace-resolver.h"
namespace {
@@ -226,7 +384,18 @@ public:
{
SetInterfaceId (BaseA::iid);
}
void BaseGenerateTrace (int16_t v)
{ m_source = v; }
virtual void Dispose (void) {}
virtual ns3::Ptr<ns3::TraceResolver> GetTraceResolver (void) const
{
ns3::Ptr<ns3::CompositeTraceResolver> resolver =
ns3::Create<ns3::CompositeTraceResolver> ();
resolver->AddSource ("basea-x", ns3::TraceDoc ("test source"), m_source);
resolver->SetParentResolver (Object::GetTraceResolver ());
return resolver;
}
ns3::SVTraceSource<int16_t> m_source;
};
class DerivedA : public BaseA
@@ -237,9 +406,20 @@ public:
{
SetInterfaceId (DerivedA::iid);
}
void DerivedGenerateTrace (int16_t v)
{ m_sourceDerived = v; }
virtual void Dispose (void) {
BaseA::Dispose ();
}
virtual ns3::Ptr<ns3::TraceResolver> GetTraceResolver (void) const
{
ns3::Ptr<ns3::CompositeTraceResolver> resolver =
ns3::Create<ns3::CompositeTraceResolver> ();
resolver->AddSource ("deriveda-x", ns3::TraceDoc ("test source"), m_sourceDerived);
resolver->SetParentResolver (BaseA::GetTraceResolver ());
return resolver;
}
ns3::SVTraceSource<int16_t> m_sourceDerived;
};
const ns3::InterfaceId BaseA::iid =
@@ -255,7 +435,18 @@ public:
{
SetInterfaceId (BaseB::iid);
}
void BaseGenerateTrace (int16_t v)
{ m_source = v; }
virtual void Dispose (void) {}
virtual ns3::Ptr<ns3::TraceResolver> GetTraceResolver (void) const
{
ns3::Ptr<ns3::CompositeTraceResolver> resolver =
ns3::Create<ns3::CompositeTraceResolver> ();
resolver->AddSource ("baseb-x", ns3::TraceDoc ("test source"), m_source);
resolver->SetParentResolver (Object::GetTraceResolver ());
return resolver;
}
ns3::SVTraceSource<int16_t> m_source;
};
class DerivedB : public BaseB
@@ -266,9 +457,20 @@ public:
{
SetInterfaceId (DerivedB::iid);
}
void DerivedGenerateTrace (int16_t v)
{ m_sourceDerived = v; }
virtual void Dispose (void) {
BaseB::Dispose ();
}
virtual ns3::Ptr<ns3::TraceResolver> GetTraceResolver (void) const
{
ns3::Ptr<ns3::CompositeTraceResolver> resolver =
ns3::Create<ns3::CompositeTraceResolver> ();
resolver->AddSource ("derivedb-x", ns3::TraceDoc ("test source"), m_sourceDerived);
resolver->SetParentResolver (BaseB::GetTraceResolver ());
return resolver;
}
ns3::SVTraceSource<int16_t> m_sourceDerived;
};
const ns3::InterfaceId BaseB::iid =
@@ -285,120 +487,82 @@ class ObjectTest : public Test
public:
ObjectTest ();
virtual bool RunTests (void);
private:
void BaseATrace (const TraceContext &context, int64_t oldValue, int64_t newValue);
void DerivedATrace (const TraceContext &context, int64_t oldValue, int64_t newValue);
void BaseBTrace (const TraceContext &context, int64_t oldValue, int64_t newValue);
void DerivedBTrace (const TraceContext &context, int64_t oldValue, int64_t newValue);
bool m_baseATrace;
bool m_derivedATrace;
bool m_baseBTrace;
bool m_derivedBTrace;
};
ObjectTest::ObjectTest ()
: Test ("Object")
{}
void
ObjectTest::BaseATrace (const TraceContext &context, int64_t oldValue, int64_t newValue)
{
m_baseATrace = true;
}
void
ObjectTest::DerivedATrace (const TraceContext &context, int64_t oldValue, int64_t newValue)
{
m_derivedATrace = true;
}
void
ObjectTest::BaseBTrace (const TraceContext &context, int64_t oldValue, int64_t newValue)
{
m_baseBTrace = true;
}
void
ObjectTest::DerivedBTrace (const TraceContext &context, int64_t oldValue, int64_t newValue)
{
m_derivedBTrace = true;
}
bool
ObjectTest::RunTests (void)
{
bool ok = true;
bool result = true;
Ptr<BaseA> baseA = Create<BaseA> ();
if (baseA->QueryInterface<BaseA> (BaseA::iid) != baseA)
{
ok = false;
}
if (baseA->QueryInterface<BaseA> (DerivedA::iid) != 0)
{
ok = false;
}
if (baseA->QueryInterface<DerivedA> (DerivedA::iid) != 0)
{
ok = false;
}
NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<BaseA> (BaseA::iid), baseA);
NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<BaseA> (DerivedA::iid), 0);
NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<DerivedA> (DerivedA::iid), 0);
baseA = Create<DerivedA> (10);
if (baseA->QueryInterface<BaseA> (BaseA::iid) != baseA)
{
ok = false;
}
if (baseA->QueryInterface<BaseA> (DerivedA::iid) != baseA)
{
ok = false;
}
if (baseA->QueryInterface<DerivedA> (DerivedA::iid) == 0)
{
ok = false;
}
NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<BaseA> (BaseA::iid), baseA);
NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<BaseA> (DerivedA::iid), baseA);
NS_TEST_ASSERT_UNEQUAL (baseA->QueryInterface<DerivedA> (DerivedA::iid), 0);
baseA = Create<BaseA> ();
Ptr<BaseB> baseB = Create<BaseB> ();
Ptr<BaseB> baseBCopy = baseB;
baseA->AddInterface (baseB);
if (baseA->QueryInterface<BaseA> (BaseA::iid) == 0)
{
ok = false;
}
if (baseA->QueryInterface<DerivedA> (DerivedA::iid) != 0)
{
ok = false;
}
if (baseA->QueryInterface<BaseB> (BaseB::iid) == 0)
{
ok = false;
}
if (baseA->QueryInterface<DerivedB> (DerivedB::iid) != 0)
{
ok = false;
}
if (baseB->QueryInterface<BaseB> (BaseB::iid) == 0)
{
ok = false;
}
if (baseB->QueryInterface<DerivedB> (DerivedB::iid) != 0)
{
ok = false;
}
if (baseB->QueryInterface<BaseA> (BaseA::iid) == 0)
{
ok = false;
}
if (baseB->QueryInterface<DerivedA> (DerivedA::iid) != 0)
{
ok = false;
}
if (baseBCopy->QueryInterface<BaseA> (BaseA::iid) == 0)
{
ok = false;
}
NS_TEST_ASSERT_UNEQUAL (baseA->QueryInterface<BaseA> (BaseA::iid), 0);
NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<DerivedA> (DerivedA::iid), 0);
NS_TEST_ASSERT_UNEQUAL (baseA->QueryInterface<BaseB> (BaseB::iid), 0);
NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<DerivedB> (DerivedB::iid), 0);
NS_TEST_ASSERT_UNEQUAL (baseB->QueryInterface<BaseB> (BaseB::iid), 0);
NS_TEST_ASSERT_EQUAL (baseB->QueryInterface<DerivedB> (DerivedB::iid), 0);
NS_TEST_ASSERT_UNEQUAL (baseB->QueryInterface<BaseA> (BaseA::iid), 0);
NS_TEST_ASSERT_EQUAL (baseB->QueryInterface<DerivedA> (DerivedA::iid), 0);
NS_TEST_ASSERT_UNEQUAL (baseBCopy->QueryInterface<BaseA> (BaseA::iid), 0);
baseA = Create<DerivedA> (1);
baseB = Create<DerivedB> (1);
baseBCopy = baseB;
baseA->AddInterface (baseB);
if (baseA->QueryInterface<DerivedB> (DerivedB::iid) == 0)
{
ok = false;
}
if (baseA->QueryInterface<BaseB> (BaseB::iid) == 0)
{
ok = false;
}
if (baseB->QueryInterface<DerivedA> (DerivedA::iid) == 0)
{
ok = false;
}
if (baseB->QueryInterface<BaseA> (BaseA::iid) == 0)
{
ok = false;
}
if (baseBCopy->QueryInterface<DerivedA> (DerivedA::iid) == 0)
{
ok = false;
}
if (baseBCopy->QueryInterface<BaseA> (BaseA::iid) == 0)
{
ok = false;
}
if (baseB->QueryInterface<DerivedB> (DerivedB::iid) == 0)
{
ok = false;
}
if (baseB->QueryInterface<BaseB> (BaseB::iid) == 0)
{
ok = false;
}
NS_TEST_ASSERT_UNEQUAL (baseA->QueryInterface<DerivedB> (DerivedB::iid), 0);
NS_TEST_ASSERT_UNEQUAL (baseA->QueryInterface<BaseB> (BaseB::iid), 0);
NS_TEST_ASSERT_UNEQUAL (baseB->QueryInterface<DerivedA> (DerivedA::iid), 0);
NS_TEST_ASSERT_UNEQUAL (baseB->QueryInterface<BaseA> (BaseA::iid), 0);
NS_TEST_ASSERT_UNEQUAL (baseBCopy->QueryInterface<DerivedA> (DerivedA::iid), 0);
NS_TEST_ASSERT_UNEQUAL (baseBCopy->QueryInterface<BaseA> (BaseA::iid), 0);
NS_TEST_ASSERT_UNEQUAL (baseB->QueryInterface<DerivedB> (DerivedB::iid), 0);
NS_TEST_ASSERT_UNEQUAL (baseB->QueryInterface<BaseB> (BaseB::iid), 0)
baseA = Create<BaseA> ();
baseB = Create<BaseB> ();
@@ -406,7 +570,76 @@ ObjectTest::RunTests (void)
baseA = 0;
baseA = baseB->QueryInterface<BaseA> (BaseA::iid);
return ok;
baseA = Create<BaseA> ();
baseA->TraceConnect ("/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
m_baseATrace = false;
baseA->BaseGenerateTrace (1);
NS_TEST_ASSERT (m_baseATrace);
baseA->TraceDisconnect ("/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
baseB = Create<BaseB> ();
baseB->TraceConnect ("/baseb-x", MakeCallback (&ObjectTest::BaseBTrace, this));
m_baseBTrace = false;
baseB->BaseGenerateTrace (2);
NS_TEST_ASSERT (m_baseBTrace);
baseB->TraceDisconnect ("/baseb-x", MakeCallback (&ObjectTest::BaseBTrace, this));
baseA->AddInterface (baseB);
baseA->TraceConnect ("/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
m_baseATrace = false;
baseA->BaseGenerateTrace (3);
NS_TEST_ASSERT (m_baseATrace);
baseA->TraceDisconnect ("/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
baseA->TraceConnect ("/$BaseB/baseb-x", MakeCallback (&ObjectTest::BaseBTrace, this));
m_baseBTrace = false;
baseB->BaseGenerateTrace (4);
NS_TEST_ASSERT (m_baseBTrace);
baseA->TraceDisconnect ("/$BaseB/baseb-x", MakeCallback (&ObjectTest::BaseBTrace, this));
m_baseBTrace = false;
baseB->BaseGenerateTrace (5);
NS_TEST_ASSERT (!m_baseBTrace);
baseB->TraceConnect ("/$BaseA/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
m_baseATrace = false;
baseA->BaseGenerateTrace (6);
NS_TEST_ASSERT (m_baseATrace);
baseB->TraceDisconnect ("/$BaseA/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
baseA->TraceConnect ("/$BaseA/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
m_baseATrace = false;
baseA->BaseGenerateTrace (7);
NS_TEST_ASSERT (m_baseATrace);
baseA->TraceDisconnect ("/$BaseA/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
Ptr<DerivedA> derivedA;
derivedA = Create<DerivedA> (1);
baseB = Create<BaseB> ();
derivedA->AddInterface (baseB);
baseB->TraceConnect ("/$DerivedA/deriveda-x", MakeCallback (&ObjectTest::DerivedATrace, this));
baseB->TraceConnect ("/$DerivedA/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
m_derivedATrace = false;
m_baseATrace = false;
derivedA->DerivedGenerateTrace (8);
derivedA->BaseGenerateTrace (9);
NS_TEST_ASSERT (m_derivedATrace);
NS_TEST_ASSERT (m_baseATrace);
baseB->TraceDisconnect ("/$DerivedA/deriveda-x", MakeCallback (&ObjectTest::BaseATrace, this));
baseB->TraceDisconnect ("/$DerivedA/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
baseB->TraceConnect ("/$DerivedA/*", MakeCallback (&ObjectTest::DerivedATrace, this));
m_derivedATrace = false;
derivedA->DerivedGenerateTrace (10);
NS_TEST_ASSERT (m_derivedATrace);
// here, we have connected the derived trace sink to all
// trace sources, including the base trace source.
m_derivedATrace = false;
derivedA->BaseGenerateTrace (11);
NS_TEST_ASSERT (m_derivedATrace);
baseB->TraceDisconnect ("/$DerivedA/*", MakeCallback (&ObjectTest::BaseATrace, this));
return result;
}
static ObjectTest g_interfaceObjectTests;

View File

@@ -24,9 +24,13 @@
#include <stdint.h>
#include <string>
#include "ptr.h"
#include "trace-resolver.h"
namespace ns3 {
class TraceContext;
class CallbackBase;
/**
* \brief a unique identifier for an interface.
*
@@ -56,6 +60,11 @@ public:
* id is not a valid interface id.
*/
static InterfaceId LookupParent (InterfaceId iid);
/**
* \returns the name of this interface.
*/
std::string GetName (void) const;
~InterfaceId ();
private:
InterfaceId (uint16_t iid);
@@ -131,6 +140,30 @@ public:
* on one to get the other, and vice-versa.
*/
void AddInterface (Ptr<Object> other);
/**
* \param path the path to match for the callback
* \param cb callback to connect
*
* Connect the input callback to all trace sources which
* match the input path.
*
*/
void TraceConnect (std::string path, const CallbackBase &cb) const;
/**
* \param path the path to match for the callback
* \param cb callback to disconnect
*
* Disconnect the input callback from all trace sources which
* match the input path.
*/
void TraceDisconnect (std::string path, const CallbackBase &cb) const;
/**
* \returns the trace resolver associated to this object.
*
* This method should be rarely called by users.
*/
virtual Ptr<TraceResolver> GetTraceResolver (void) const;
protected:
/**
* \param iid an InterfaceId
@@ -147,12 +180,17 @@ protected:
*/
virtual void DoDispose (void);
private:
friend class InterfaceIdTraceResolver;
Ptr<Object> DoQueryInterface (InterfaceId iid) const;
void DoCollectSources (std::string path, const TraceContext &context,
TraceResolver::SourceCollection *collection) const;
void DoTraceAll (std::ostream &os, const TraceContext &context) const;
bool Check (void) const;
void MaybeDelete (void) const;
mutable uint32_t m_count;
InterfaceId m_iid;
bool m_disposed;
mutable bool m_collecting;
Object *m_next;
};

View File

@@ -19,7 +19,7 @@
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "random-variable-default-value.h"
#include "ns3/debug.h"
#include "debug.h"
NS_DEBUG_COMPONENT_DEFINE ("RandomVariableDefaultValue");

View File

@@ -19,7 +19,7 @@
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "stream-tracer.h"
#include "ns3/test.h"
#include "test.h"
#include <iostream>
#ifdef RUN_SELF_TESTS

View File

@@ -23,11 +23,12 @@
#define SV_TRACE_SOURCE_H
#include "callback-trace-source.h"
#include "trace-source.h"
#include <stdint.h>
namespace ns3 {
class SVTraceSourceBase {
class SVTraceSourceBase : public TraceSource {
public:
typedef CallbackTraceSource<int64_t, int64_t> ChangeNotifyCallback;
@@ -37,14 +38,17 @@ public:
return *this;
}
~SVTraceSourceBase () {}
virtual ~SVTraceSourceBase () {}
void AddCallback (CallbackBase const & callback, TraceContext const & context) {
virtual void AddCallback (CallbackBase const & callback, TraceContext const & context) {
m_callback.AddCallback (callback, context);
}
void RemoveCallback (CallbackBase const & callback) {
virtual void RemoveCallback (CallbackBase const & callback) {
m_callback.RemoveCallback (callback);
}
virtual void ConnectPrinter (std::ostream &os, const TraceContext &context) {
m_callback.ConnectPrinter (os, context);
}
protected:
void Notify (int64_t oldVal, int64_t newVal) {
if (oldVal != newVal)
@@ -62,7 +66,7 @@ class UVTraceSource;
/**
* \brief trace variables of type "signed integer"
* \ingroup lowleveltracing
* \ingroup tracing
*
* This template class implements a POD type: it
* behaves like any other variable of type "signed integer"
@@ -74,7 +78,7 @@ class UVTraceSource;
* ns3::UVTraceSource<int32_t> :
\code
#include <stdint.h>
#include "ns3/sv-trace-source.h"
#include "sv-trace-source.h"
ns3::SVTraceSource<uint16_t> var;
\endcode

View File

@@ -118,6 +118,23 @@ private:
<< ", got " << (got) << std::endl; \
result = false; \
}
/**
* Convenience macro to check that a value returned by a test is what
* is expected. Note: this macro assumes a 'bool result = true'
* declaration exists in the test function body, and that the function
* returns that value.
*
* \param got value obtained from the test
* \param expected value that the test is expected to return
*/
#define NS_TEST_ASSERT_UNEQUAL(got, expected) \
if ((got) == (expected)) \
{ \
Failure () << __FILE__ << ":" <<__LINE__ \
<< ": did not want " << (expected) \
<< ", got " << (got) << std::endl; \
result = false; \
}
/**
* Convenience macro to check an assertion is held during an unit
* test. Note: this macro assumes a 'bool result = true' declaration

View File

@@ -2,6 +2,13 @@
namespace ns3 {
std::string
ElementRegistry::GetTypeName (uint16_t uid)
{
InfoVector *vec = GetInfoVector ();
struct Info info = (*vec)[uid - 1];
return info.getTypeName ();
}
uint32_t
ElementRegistry::GetSize (uint16_t uid)
{

View File

@@ -37,6 +37,8 @@ namespace ns3 {
* This method takes a c++ output stream and argument and is
* expected to write an ascii string describing its content
* in this output stream.
* - a public GetTypeName method which returns the fully-qualified
* c++ type name of this subclass as a string.
*
* A typical subclass should look like this:
* \code
@@ -48,6 +50,7 @@ namespace ns3 {
* MyContext ();
* ~MyContext ();
* void Print (std::ostream &os) const;
* std::string GetTypeName (void) const;
*
* // the user-specific API to manipulate the context.
* void SetData (uint8_t data);
@@ -71,6 +74,12 @@ namespace ns3 {
* {
* os << "mycontext=" << (uint32_t) m_myContextData;
* }
* std::string
* MyContext::GetTypeName (void) const
* {
* // return a fully-qualified c++ type name
* return "MyContext";
* }
* void
* MyContext::SetData (uint8_t data)
* {
@@ -115,19 +124,24 @@ public:
static uint32_t GetSize (uint16_t uid);
static void Print (uint16_t uid, uint8_t *instance, std::ostream &os);
static std::string GetTypeName (uint16_t uid);
static void Destroy (uint16_t uid, uint8_t *instance);
private:
typedef std::string (*GetTypeNameCb) (void);
typedef void (*PrintCb) (uint8_t *instance, std::ostream &os);
typedef void (*DestroyCb) (uint8_t *instance);
struct Info {
uint32_t size;
std::string uidString;
GetTypeNameCb getTypeName;
PrintCb print;
DestroyCb destroy;
};
typedef std::vector<struct Info> InfoVector;
static InfoVector *GetInfoVector (void);
template <typename T>
static std::string DoGetTypeName (void);
template <typename T>
static void DoPrint (uint8_t *instance, std::ostream &os);
template <typename T>
static void DoDestroy (uint8_t *instance);
@@ -143,6 +157,13 @@ ElementRegistry::DoPrint (uint8_t *instance, std::ostream &os)
obj.Print (os);
}
template <typename T>
std::string
ElementRegistry::DoGetTypeName (void)
{
static T obj;
return obj.GetTypeName ();
}
template <typename T>
void
ElementRegistry::DoDestroy (uint8_t *instance)
{
@@ -169,6 +190,7 @@ ElementRegistry::AllocateUid (std::string name)
struct Info info;
info.size = sizeof (T);
info.uidString = name;
info.getTypeName = &ElementRegistry::DoGetTypeName<T>;
info.print = &ElementRegistry::DoPrint<T>;
info.destroy = &ElementRegistry::DoDestroy<T>;
vec->push_back (info);

View File

@@ -20,10 +20,56 @@
*/
#include "trace-context.h"
#include "trace-context-element.h"
#include "ns3/assert.h"
#include "assert.h"
namespace ns3 {
TraceContext::Iterator::Iterator ()
: m_buffer (0),
m_size (0),
m_current (0)
{}
TraceContext::Iterator::Iterator (uint8_t *buffer, uint16_t size)
: m_buffer (buffer),
m_size (size),
m_current (0)
{
m_uid = m_buffer[m_current];
}
bool
TraceContext::Iterator::IsLast (void) const
{
if (m_buffer == 0 || m_uid == 0 || m_current >= m_size)
{
return true;
}
return false;
}
void
TraceContext::Iterator::Next (void)
{
if (m_buffer == 0)
{
return;
}
if (m_uid == 0)
{
return;
}
else
{
uint8_t size = ElementRegistry::GetSize (m_uid);
m_current += 1 + size;
}
m_uid = m_buffer[m_current];
}
std::string
TraceContext::Iterator::Get (void) const
{
std::string name = ElementRegistry::GetTypeName (m_uid);
return name;
}
TraceContext::TraceContext ()
: m_data (0)
{}
@@ -68,7 +114,7 @@ TraceContext::~TraceContext ()
}
void
TraceContext::Add (TraceContext const &o)
TraceContext::Union (TraceContext const &o)
{
if (o.m_data == 0)
{
@@ -230,10 +276,93 @@ TraceContext::Print (std::ostream &os) const
}
} while (true);
}
TraceContext::Iterator
TraceContext::Begin (void) const
{
if (m_data == 0)
{
return Iterator ();
}
return Iterator (m_data->data, m_data->size);
}
void
TraceContext::PrintAvailable (std::ostream &os, std::string separator) const
{
if (m_data == 0)
{
return;
}
uint8_t currentUid;
uint16_t i = 0;
do {
currentUid = m_data->data[i];
uint8_t size = ElementRegistry::GetSize (currentUid);
os << ElementRegistry::GetTypeName (currentUid);
i += 1 + size;
if (i < m_data->size && currentUid != 0)
{
os << separator;
}
else
{
break;
}
} while (true);
}
bool
TraceContext::IsSimilar (const TraceContext &o) const
{
if (m_data == 0 && o.m_data == 0)
{
return true;
}
if ((m_data != 0 && o.m_data == 0) ||
(m_data == 0 && o.m_data != 0))
{
return false;
}
uint8_t myCurrentUid;
uint16_t myI = 0;
uint8_t otherCurrentUid;
uint16_t otherI = 0;
myCurrentUid = m_data->data[myI];
otherCurrentUid = o.m_data->data[otherI];
while (myCurrentUid == otherCurrentUid &&
myCurrentUid != 0 &&
otherCurrentUid != 0 &&
myI < m_data->size &&
otherI < o.m_data->size)
{
uint8_t mySize = ElementRegistry::GetSize (myCurrentUid);
uint8_t otherSize = ElementRegistry::GetSize (otherCurrentUid);
myI += 1 + mySize;
otherI += 1 + otherSize;
myCurrentUid = m_data->data[myI];
otherCurrentUid = o.m_data->data[otherI];
}
if (myCurrentUid == 0 && otherCurrentUid == 0)
{
return true;
}
else
{
return false;
}
}
std::ostream& operator<< (std::ostream& os, const TraceContext &context)
{
context.Print (os);
return os;
}
}//namespace ns3
#include "ns3/test.h"
#include "test.h"
#include <sstream>
namespace ns3 {
@@ -242,8 +371,8 @@ template <int N>
class Ctx : public TraceContextElement
{
public:
static uint16_t GetUid (void) {static uint16_t uid = AllocateUid<Ctx<N> > (GetName ()); return uid;}
static std::string GetName (void) {std::ostringstream oss; oss << "Ctx" << N; return oss.str ();}
static uint16_t GetUid (void) {static uint16_t uid = AllocateUid<Ctx<N> > (GetTypeName ()); return uid;}
static std::string GetTypeName (void) {std::ostringstream oss; oss << "Ctx" << N; return oss.str ();}
Ctx () : m_v (0) {}
Ctx (int v) : m_v (v) {}
void Print (std::ostream &os) {os << N;}
@@ -278,31 +407,31 @@ TraceContextTest::RunTests (void)
{
ok = false;
}
ctx.Add (v0);
ctx.Add (v0);
ctx.AddElement (v0);
ctx.AddElement (v0);
if (ctx.SafeAdd (v01))
{
ok = false;
}
ctx.Get (v0);
ctx.Add (v1);
ctx.Get (v1);
ctx.Get (v0);
ctx.Get (v1);
ctx.GetElement (v0);
ctx.AddElement (v1);
ctx.GetElement (v1);
ctx.GetElement (v0);
ctx.GetElement (v1);
TraceContext copy = ctx;
ctx.Get (v0);
ctx.Get (v1);
copy.Get (v0);
copy.Get (v1);
copy.Add (v2);
copy.Get (v0);
copy.Get (v1);
copy.Get (v2);
ctx.Add (v3);
ctx.Get (v0);
ctx.Get (v1);
ctx.Get (v3);
ctx.GetElement (v0);
ctx.GetElement (v1);
copy.GetElement (v0);
copy.GetElement (v1);
copy.AddElement (v2);
copy.GetElement (v0);
copy.GetElement (v1);
copy.GetElement (v2);
ctx.AddElement (v3);
ctx.GetElement (v0);
ctx.GetElement (v1);
ctx.GetElement (v3);
if (ctx.SafeGet (v2))
{
@@ -312,14 +441,14 @@ TraceContextTest::RunTests (void)
{
ok = false;
}
ctx.Add (copy);
ctx.Get (v2);
ctx.Union (copy);
ctx.GetElement (v2);
if (copy.SafeGet (v3))
{
ok = false;
}
copy.Add (ctx);
copy.Get (v3);
copy.Union (ctx);
copy.GetElement (v3);
return ok;
}

View File

@@ -23,26 +23,28 @@
#include <stdint.h>
#include <vector>
#include "ns3/fatal-error.h"
#include "fatal-error.h"
#include "trace-context-element.h"
namespace ns3 {
/**
* \brief Provide context to trace sources
* \ingroup lowleveltracing
* \ingroup tracing
*
* Instances of this class are used to hold context
* for each trace source. Each instance holds a list of
* 'contexts'. Trace sinks can lookup these contexts
* TraceContextElement. Trace sinks can lookup these contexts
* from this list with the ns3::TraceContext::Get method.
* They can also ask the TraceContext for the list of
* TraceContextElements it contains with the PrintAvailable method.
*
* This class is implemented
* using Copy On Write which means that copying unmodified
* versions of this class is very cheap. However, modifying
* the content of this class through a call
* to ns3::TraceContext::Add will trigger a costly memory
* reallocation if needed.
* to ns3::TraceContext::AddElement or ns3::TraceContext::Union
* will trigger a costly memory reallocation if needed.
*/
class TraceContext
{
@@ -54,32 +56,73 @@ public:
/**
* \param context add context to list of trace contexts.
*
* A copy of the input context is appended at the end of the list
* stored in this TraceContext.
*/
template <typename T>
void Add (T const &context);
void AddElement (T const &context);
/**
* \param o the other context
*
* Perform the Union operation (in the sense of set theory) on the
* two input lists of elements. This method is used in the
* ns3::CallbackTraceSourceSource class when multiple sinks are connected
* ns3::CallbackTraceSource class when multiple sinks are connected
* to a single source to ensure that the source does not need
* to store a single TraceContext instance per connected sink.
* Instead, all sinks share the same TraceContext.
*/
void Add (TraceContext const &o);
void Union (TraceContext const &o);
/**
* \param context context to get from this list of trace contexts.
*
* This method cannot fail. If the requested trace context is not
* stored in this TraceContext, then, the program will halt.
* \returns true if the requested trace context element was found
* in this TraceContext, false otherwise.
*/
template <typename T>
void Get (T &context) const;
bool GetElement (T &context) const;
/**
* \param os a c++ STL output stream
*
* Iterate over the list of TraceContextElement stored in this
* TraceContext and invoke each of their Print method.
*/
void Print (std::ostream &os) const;
/**
* \param os a c++ STL output stream
* \param separator the separator inserted between each TraceContextElement typename.
*
* Print the typename of each TraceContextElement stored in this TraceContext.
*/
void PrintAvailable (std::ostream &os, std::string separator) const;
class Iterator
{
public:
void Next (void);
bool IsLast (void) const;
std::string Get (void) const;
private:
friend class TraceContext;
Iterator ();
Iterator (uint8_t *buffer, uint16_t index);
uint8_t *m_buffer;
uint16_t m_size;
uint16_t m_current;
uint8_t m_uid;
};
Iterator Begin (void) const;
/**
* \param o another trace context
* \returns true if the input trace context contains exactly the same set of
* TraceContextElement instances, false otherwise.
*
* This method does not test for equality: the content of each matching
* TraceContextElement could be different. It merely checks that both
* trace contexts contain the same types of TraceContextElements.
*/
bool IsSimilar (const TraceContext &o) const;
private:
friend class TraceContextTest;
// used exclusively for testing code.
@@ -99,13 +142,15 @@ private:
} * m_data;
};
std::ostream& operator<< (std::ostream& os, const TraceContext &context);
}//namespace ns3
namespace ns3 {
template <typename T>
void
TraceContext::Add (T const &context)
TraceContext::AddElement (T const &context)
{
const TraceContextElement *parent;
// if the following assignment fails, it is because the input
@@ -119,8 +164,8 @@ TraceContext::Add (T const &context)
}
}
template <typename T>
void
TraceContext::Get (T &context) const
bool
TraceContext::GetElement (T &context) const
{
TraceContextElement *parent;
// if the following assignment fails, it is because the input
@@ -128,10 +173,7 @@ TraceContext::Get (T &context) const
parent = &context;
uint8_t *data = (uint8_t *) &context;
bool found = DoGet (T::GetUid (), data);
if (!found)
{
NS_FATAL_ERROR ("Type not stored in TraceContext");
}
return found;
}
template <typename T>
bool

74
src/core/trace-doc.cc Normal file
View File

@@ -0,0 +1,74 @@
#include "trace-doc.h"
namespace ns3 {
TraceDoc::TraceDoc ()
: m_help ("empty help")
{}
TraceDoc::TraceDoc (std::string help)
: m_help (help)
{}
TraceDoc::TraceDoc (std::string help,
std::string arg0Type,
std::string arg0Help)
: m_help (help)
{
m_argVector.push_back (std::make_pair (arg0Type, arg0Help));
}
TraceDoc::TraceDoc (std::string help,
std::string arg0Type,
std::string arg0Help,
std::string arg1Type,
std::string arg1Help)
: m_help (help)
{
m_argVector.push_back (std::make_pair (arg0Type, arg0Help));
m_argVector.push_back (std::make_pair (arg1Type, arg1Help));
}
TraceDoc::TraceDoc (std::string help,
std::string arg0Type,
std::string arg0Help,
std::string arg1Type,
std::string arg1Help,
std::string arg2Type,
std::string arg2Help)
: m_help (help)
{
m_argVector.push_back (std::make_pair (arg0Type, arg0Help));
m_argVector.push_back (std::make_pair (arg1Type, arg1Help));
m_argVector.push_back (std::make_pair (arg2Type, arg2Help));
}
TraceDoc::TraceDoc (std::string help,
std::string arg0Type,
std::string arg0Help,
std::string arg1Type,
std::string arg1Help,
std::string arg2Type,
std::string arg2Help,
std::string arg3Type,
std::string arg3Help)
: m_help (help)
{
m_argVector.push_back (std::make_pair (arg0Type, arg0Help));
m_argVector.push_back (std::make_pair (arg1Type, arg1Help));
m_argVector.push_back (std::make_pair (arg2Type, arg2Help));
m_argVector.push_back (std::make_pair (arg3Type, arg3Help));
}
std::string
TraceDoc::GetHelp (void) const
{
return m_help;
}
TraceDoc::Iterator
TraceDoc::ArgsBegin (void) const
{
return m_argVector.begin ();
}
TraceDoc::Iterator
TraceDoc::ArgsEnd (void) const
{
return m_argVector.end ();
}
} // namespace ns3

50
src/core/trace-doc.h Normal file
View File

@@ -0,0 +1,50 @@
#ifndef TRACE_DOC_H
#define TRACE_DOC_H
#include <vector>
#include <string>
namespace ns3 {
class TraceDoc
{
typedef std::vector<std::pair<std::string,std::string> > ArgVector;
public:
typedef ArgVector::const_iterator Iterator;
TraceDoc ();
TraceDoc (std::string help);
TraceDoc (std::string help,
std::string arg0Type,
std::string arg0Help);
TraceDoc (std::string help,
std::string arg0Type,
std::string arg0Help,
std::string arg1Type,
std::string arg1Help);
TraceDoc (std::string help,
std::string arg0Type,
std::string arg0Help,
std::string arg1Type,
std::string arg1Help,
std::string arg2Type,
std::string arg2Help);
TraceDoc (std::string help,
std::string arg0Type,
std::string arg0Help,
std::string arg1Type,
std::string arg1Help,
std::string arg2Type,
std::string arg2Help,
std::string arg3Type,
std::string arg3Help);
std::string GetHelp (void) const;
Iterator ArgsBegin (void) const;
Iterator ArgsEnd (void) const;
private:
ArgVector m_argVector;
std::string m_help;
};
} // namespace ns3
#endif /* TRACE_DOC_H */

107
src/core/trace-resolver.cc Normal file
View File

@@ -0,0 +1,107 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "trace-resolver.h"
#include "debug.h"
NS_DEBUG_COMPONENT_DEFINE ("TraceResolver");
namespace ns3 {
TraceResolver::TraceResolver ()
: m_count (1)
{}
TraceResolver::~TraceResolver ()
{}
void
TraceResolver::Ref (void)
{
m_count++;
}
void
TraceResolver::Unref (void)
{
m_count--;
if (m_count == 0)
{
NS_DEBUG ("delete "<<this);
delete this;
}
}
std::string
TraceResolver::GetElement (std::string path)
{
std::string::size_type cur = 1;
// check that first char is "/"
std::string::size_type next = path.find ("/", cur);
std::string id = std::string (path, cur, next-1);
return id;
}
std::string
TraceResolver::GetSubpath (std::string path)
{
std::string::size_type cur = 1;
// check that first char is "/"
std::string::size_type next = path.find ("/", cur);
std::string subpath;
if (next != std::string::npos)
{
subpath = std::string (path, next, std::string::npos);
}
else
{
subpath = "";
}
return subpath;
}
void
TraceResolver::SourceCollection::AddUnique (std::string path,
const TraceContext &context,
const TraceDoc &doc)
{
for (SourceVector::const_iterator i = m_sources.begin (); i != m_sources.end (); i++)
{
if (i->path == path &&
context.IsSimilar (i->context))
{
return;
}
}
struct Source source;
source.path = path;
source.context = context;
source.doc = doc;
m_sources.push_back (source);
}
TraceResolver::SourceCollection::Iterator
TraceResolver::SourceCollection::Begin (void) const
{
return m_sources.begin ();
}
TraceResolver::SourceCollection::Iterator
TraceResolver::SourceCollection::End (void) const
{
return m_sources.end ();
}
}//namespace ns3

128
src/core/trace-resolver.h Normal file
View File

@@ -0,0 +1,128 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#ifndef TRACE_RESOLVER_H
#define TRACE_RESOLVER_H
#include <string>
#include <list>
#include "trace-context.h"
#include "trace-doc.h"
namespace ns3 {
class CallbackBase;
/**
* \brief the base class which is used to recursively perform trace
* namespace resolution.
* \ingroup tracing
*
* Although users could conceivably implement their own trace resolver
* subclasses, doing so is complicated so, it is recommended to use
* the default implementation ns3::CompositeTraceResolver instead.
*/
class TraceResolver
{
public:
TraceResolver ();
virtual ~TraceResolver ();
void Ref (void);
void Unref (void);
/**
* \param path the namespace path to resolver
* \param cb the callback to connect to the matching namespace
* \param context the context in which to store the trace context
*
* First, extract the leading path element from the input path, and
* match this leading patch element against any terminal trace source
* contained in this trace resolver.
* Second, recursively resolve the rest of the path using other
* objects if there are any.
* If there is any TraceContextElement associated to one of the matching
* elements, it should be added to the input TraceContext.
*/
virtual void Connect (std::string path, CallbackBase const &cb, const TraceContext &context) = 0;
/**
* \param path the namespace path to resolver
* \param cb the callback to disconnect in the matching namespace
*
* This method should behave as Connect.
*/
virtual void Disconnect (std::string path, CallbackBase const &cb) = 0;
class SourceCollection
{
public:
struct Source
{
std::string path;
TraceContext context;
TraceDoc doc;
};
typedef std::vector<struct Source>::const_iterator Iterator;
void AddUnique (std::string path,
const TraceContext &context,
const TraceDoc &doc);
Iterator Begin (void) const;
Iterator End (void) const;
private:
typedef std::vector<struct Source> SourceVector;
SourceVector m_sources;
};
/**
* \param path the path to the current recursive level.
* \param context the trace context associated to the current recursive level
* \param collection the collection in which to gather every trace source found.
*
* This method is invoked recursively until all trace sources have been
* stored in the output SourceCollection argument.
*/
virtual void CollectSources (std::string path, const TraceContext &context,
SourceCollection *collection) = 0;
virtual void TraceAll (std::ostream &os, const TraceContext &context) = 0;
protected:
/**
* \param path a namespace path
* \returns the initial element of the path.
*
* If the input path is "/foo/...", the return
* value is "foo".
*/
std::string GetElement (std::string path);
/**
* \param path a namespace path
* \returns the subpath.
*
* If the input path is "/foo/bar/...", the return
* value is "/bar/...".
*/
std::string GetSubpath (std::string path);
private:
uint32_t m_count;
};
}//namespace ns3
#endif /* TRACE_RESOLVER_H */

View File

@@ -1,7 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -18,8 +17,15 @@
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "empty-trace-resolver.h"
#include "trace-source.h"
#include "trace-context.h"
ns3::EmptyTraceResolver::EmptyTraceResolver (TraceContext const &context)
: TraceResolver (context)
{}
namespace ns3 {
void
TraceSource::AddCallback (CallbackBase const & callback)
{
AddCallback (callback, TraceContext ());
}
} // namespace ns3

61
src/core/trace-source.h Normal file
View File

@@ -0,0 +1,61 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#ifndef TRACE_SOURCE_H
#define TRACE_SOURCE_H
#include <ostream>
namespace ns3 {
class CallbackBase;
class TraceContext;
/**
* \brief the base class for all trace sources
*
* Every trace source which wishes to be connectable and disconnectable with
* the TraceResolver system should derive from this base class and implement
* all three methods below.
*/
class TraceSource
{
public:
virtual ~TraceSource () {}
/**
* \param callback the callback to connect to this trace source
* \param context the context associated to the input callback which should be passed
* back to the user.
*/
virtual void AddCallback (CallbackBase const & callback, TraceContext const & context) = 0;
/**
* \param callback the callback to connect to this trace source
*/
void AddCallback (CallbackBase const & callback);
/**
* \param callback the callback to disconnect from this trace source
*/
virtual void RemoveCallback (CallbackBase const & callback) = 0;
virtual void ConnectPrinter (std::ostream &os, TraceContext const &context) = 0;
};
} // namespace ns3
#endif /* TRACE_SOURCE_H */

View File

@@ -19,8 +19,8 @@
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "uid-manager.h"
#include "ns3/fatal-error.h"
#include "ns3/assert.h"
#include "fatal-error.h"
#include "assert.h"
namespace ns3 {

View File

@@ -23,11 +23,12 @@
#define UV_TRACE_SOURCE_H
#include "callback-trace-source.h"
#include "trace-source.h"
#include <stdint.h>
namespace ns3 {
class UVTraceSourceBase {
class UVTraceSourceBase : public TraceSource {
public:
typedef CallbackTraceSource<uint64_t, uint64_t> ChangeNotifyCallback;
@@ -42,11 +43,14 @@ public:
}
~UVTraceSourceBase () {}
void AddCallback (CallbackBase const & callback, TraceContext const & context) {
virtual void AddCallback (CallbackBase const & callback, TraceContext const & context) {
m_callback.AddCallback (callback, context);
}
void RemoveCallback (CallbackBase const & callback) {
m_callback.RemoveCallback (callback);
virtual void RemoveCallback (CallbackBase const & callback) {
m_callback.RemoveCallback (callback);
}
virtual void ConnectPrinter (std::ostream &os, const TraceContext &context) {
m_callback.ConnectPrinter (os, context);
}
protected:
@@ -66,7 +70,7 @@ class SVTraceSource;
/**
* \brief trace variables of type "unsigned integer"
* \ingroup lowleveltracing
* \ingroup tracing
*
* This template class implements a POD type: it
* behaves like any other variable of type "unsigned integer"
@@ -78,7 +82,7 @@ class SVTraceSource;
* ns3::UVTraceSource<uint32_t> :
\code
#include <stdint.h>
#include "ns3/uv-trace-source.h"
#include "uv-trace-source.h"
ns3::UVTraceSource<uint32_t> var;
\endcode

View File

@@ -22,8 +22,8 @@
#include "uv-trace-source.h"
#include "sv-trace-source.h"
#include "trace-context.h"
#include "ns3/test.h"
#include "ns3/callback.h"
#include "test.h"
#include "callback.h"
namespace ns3 {

View File

@@ -42,6 +42,14 @@ def build(bld):
'type-name.cc',
'component-manager.cc',
'random-variable-default-value.cc',
'variable-tracer-test.cc',
'trace-context.cc',
'trace-context-element.cc',
'trace-resolver.cc',
'callback-trace-source.cc',
'composite-trace-resolver.cc',
'trace-doc.cc',
'trace-source.cc',
]
if sys.platform == 'win32':
@@ -73,5 +81,16 @@ def build(bld):
'component-manager.h',
'type-traits.h',
'random-variable-default-value.h',
'trace-source.h',
'uv-trace-source.h',
'sv-trace-source.h',
'fv-trace-source.h',
'callback-trace-source.h',
'trace-context.h',
'trace-context-element.h',
'trace-resolver.h',
'composite-trace-resolver.h',
'array-trace-resolver.h',
'trace-doc.h',
]

View File

@@ -59,6 +59,16 @@ CsmaTraceType::GetUid (void)
static uint16_t uid = AllocateUid<CsmaTraceType> ("CsmaTraceType");
return uid;
}
std::string
CsmaTraceType::GetTypeName (void) const
{
return "ns3::CsmaTraceType";
}
enum CsmaTraceType::Type
CsmaTraceType::Get (void) const
{
return m_type;
}
CsmaNetDevice::CsmaNetDevice (Ptr<Node> node)
@@ -452,20 +462,23 @@ CsmaNetDevice::TransmitReadyEvent (void)
}
}
TraceResolver *
CsmaNetDevice::DoCreateTraceResolver (TraceContext const &context)
Ptr<TraceResolver>
CsmaNetDevice::GetTraceResolver (void) const
{
CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
resolver->Add ("queue",
MakeCallback (&Queue::CreateTraceResolver,
PeekPointer (m_queue)));
resolver->Add ("rx",
m_rxTrace,
CsmaTraceType (CsmaTraceType::RX));
resolver->Add ("drop",
m_dropTrace,
CsmaTraceType (CsmaTraceType::DROP));
return resolver;
Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
resolver->AddComposite ("queue", m_queue);
resolver->AddSource ("rx",
TraceDoc ("receive MAC packet",
"const Packet &", "packet received"),
m_rxTrace,
CsmaTraceType (CsmaTraceType::RX));
resolver->AddSource ("drop",
TraceDoc ("drop MAC packet",
"const Packet &", "packet dropped"),
m_dropTrace,
CsmaTraceType (CsmaTraceType::DROP));
resolver->SetParentResolver (NetDevice::GetTraceResolver ());
return resolver;
}
bool

View File

@@ -41,6 +41,9 @@ namespace ns3 {
class Queue;
class CsmaChannel;
/**
* \brief hold in a TraceContext the type of trace source from a CsmaNetDevice
*/
class CsmaTraceType : public TraceContextElement
{
public:
@@ -52,6 +55,11 @@ public:
CsmaTraceType ();
void Print (std::ostream &os) const;
static uint16_t GetUid (void);
std::string GetTypeName (void) const;
/**
* \returns the type of the trace source which generated an event.
*/
enum Type Get (void) const;
private:
enum Type m_type;
};
@@ -206,6 +214,13 @@ enum CsmaEncapsulationMode {
protected:
virtual bool DoNeedsArp (void) const;
virtual void DoDispose (void);
/**
* Create a Trace Resolver for events in the net device.
* (NOT TESTED)
* @see class TraceResolver
*/
virtual Ptr<TraceResolver> GetTraceResolver (void) const;
/**
* Get a copy of the attached Queue.
*
@@ -321,12 +336,6 @@ private:
* @see TransmitStart ()
*/
void TransmitReadyEvent (void);
/**
* Create a Trace Resolver for events in the net device.
* (NOT TESTED)
* @see class TraceResolver
*/
virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context);
/**
* Aborts the transmission of the current packet

View File

@@ -53,6 +53,11 @@ PointToPointTraceType::GetUid (void)
static uint16_t uid = AllocateUid<PointToPointTraceType> ("PointToPointTraceType");
return uid;
}
std::string
PointToPointTraceType::GetTypeName (void) const
{
return "ns3::PointToPointTraceType";
}
PointToPointNetDevice::PointToPointNetDevice (Ptr<Node> node,
@@ -189,15 +194,17 @@ void PointToPointNetDevice::TransmitComplete (void)
TransmitStart(p);
}
TraceResolver* PointToPointNetDevice::DoCreateTraceResolver (
TraceContext const &context)
Ptr<TraceResolver>
PointToPointNetDevice::GetTraceResolver (void) const
{
CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
resolver->Add ("queue",
MakeCallback (&Queue::CreateTraceResolver, PeekPointer (m_queue)));
resolver->Add ("rx",
m_rxTrace,
PointToPointTraceType ());
Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
resolver->AddComposite ("queue", m_queue);
resolver->AddSource ("rx",
TraceDoc ("receive MAC packet",
"const Packet &", "packet received"),
m_rxTrace,
PointToPointTraceType ());
resolver->SetParentResolver (NetDevice::GetTraceResolver ());
return resolver;
}

View File

@@ -38,12 +38,16 @@ namespace ns3 {
class Queue;
class PointToPointChannel;
/**
* \brief hold in a TraceContext the type of trace source from a PointToPointNetDevice
*/
class PointToPointTraceType : public TraceContextElement
{
public:
PointToPointTraceType ();
void Print (std::ostream &os) const;
static uint16_t GetUid (void);
std::string GetTypeName (void) const;
};
/**
@@ -152,6 +156,12 @@ public:
*/
void Receive (Packet& p);
protected:
/**
* Create a Trace Resolver for events in the net device.
*
* @see class TraceResolver
*/
virtual Ptr<TraceResolver> GetTraceResolver (void) const;
virtual void DoDispose (void);
/**
* Get a copy of the attached Queue.
@@ -237,12 +247,6 @@ private:
*
*/
void TransmitComplete(void);
/**
* Create a Trace Resolver for events in the net device.
*
* @see class TraceResolver
*/
virtual TraceResolver* DoCreateTraceResolver (TraceContext const &context);
virtual bool DoNeedsArp (void) const;
/**
* Enumeration of the states of the transmit machine of the net device.

View File

@@ -19,16 +19,16 @@
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "ns3/assert.h"
#include "ns3/packet.h"
#include "ns3/simulator.h"
#include "arp-cache.h"
#include "arp-header.h"
#include "ipv4-interface.h"
namespace ns3 {
ArpCache::ArpCache (Ptr<NetDevice> device, Ipv4Interface *interface)
ArpCache::ArpCache (Ptr<NetDevice> device, Ptr<Ipv4Interface> interface)
: m_device (device),
m_interface (interface),
m_aliveTimeout (Seconds (120)),
@@ -47,7 +47,7 @@ ArpCache::GetDevice (void) const
return m_device;
}
Ipv4Interface *
Ptr<Ipv4Interface>
ArpCache::GetInterface (void) const
{
return m_interface;

View File

@@ -48,7 +48,7 @@ public:
* \param device The hardware NetDevice associated with this ARP chache
* \param interface the Ipv4Interface associated with this ARP chache
*/
ArpCache (Ptr<NetDevice> device, Ipv4Interface *interface);
ArpCache (Ptr<NetDevice> device, Ptr<Ipv4Interface> interface);
~ArpCache ();
/**
* \return The NetDevice that this ARP cache is associated with
@@ -57,7 +57,7 @@ public:
/**
* \return the Ipv4Interface that this ARP cache is associated with
*/
Ipv4Interface *GetInterface (void) const;
Ptr<Ipv4Interface> GetInterface (void) const;
void SetAliveTimeout (Time aliveTimeout);
void SetDeadTimeout (Time deadTimeout);
@@ -152,7 +152,7 @@ private:
typedef sgi::hash_map<Ipv4Address, ArpCache::Entry *, Ipv4AddressHash>::iterator CacheI;
Ptr<NetDevice> m_device;
Ipv4Interface *m_interface;
Ptr<Ipv4Interface> m_interface;
Time m_aliveTimeout;
Time m_deadTimeout;
Time m_waitReplyTimeout;

View File

@@ -40,16 +40,15 @@ ArpIpv4Interface::ArpIpv4Interface (Ptr<Node> node, Ptr<NetDevice> device)
ArpIpv4Interface::~ArpIpv4Interface ()
{}
TraceResolver *
ArpIpv4Interface::DoCreateTraceResolver (TraceContext const &context)
Ptr<TraceResolver>
ArpIpv4Interface::GetTraceResolver (void) const
{
CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
if (GetDevice () != 0)
{
resolver->Add ("netdevice",
MakeCallback (&NetDevice::CreateTraceResolver, PeekPointer (GetDevice ())));
resolver->AddComposite ("netdevice", GetDevice ());
}
resolver->SetParentResolver (Ipv4Interface::GetTraceResolver ());
return resolver;
}

View File

@@ -42,9 +42,10 @@ class ArpIpv4Interface : public Ipv4Interface
ArpIpv4Interface (Ptr<Node> node, Ptr<NetDevice> device);
virtual ~ArpIpv4Interface ();
private:
protected:
virtual Ptr<TraceResolver> GetTraceResolver (void) const;
private:
virtual void SendTo (Packet p, Ipv4Address dest);
virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context);
Ptr<Node> m_node;
};

View File

@@ -20,7 +20,6 @@
*/
#include "ns3/packet.h"
#include "ns3/debug.h"
#include "ns3/empty-trace-resolver.h"
#include "ns3/node.h"
#include "ns3/net-device.h"
@@ -58,12 +57,6 @@ ArpL3Protocol::DoDispose (void)
Object::DoDispose ();
}
TraceResolver *
ArpL3Protocol::CreateTraceResolver (TraceContext const &context)
{
return new EmptyTraceResolver (context);
}
ArpCache *
ArpL3Protocol::FindCache (Ptr<NetDevice> device)
{
@@ -75,7 +68,7 @@ ArpL3Protocol::FindCache (Ptr<NetDevice> device)
}
}
Ptr<Ipv4L3Protocol> ipv4 = m_node->QueryInterface<Ipv4L3Protocol> (Ipv4L3Protocol::iid);
Ipv4Interface *interface = ipv4->FindInterfaceForDevice (device);
Ptr<Ipv4Interface> interface = ipv4->FindInterfaceForDevice (device);
ArpCache * cache = new ArpCache (device, interface);
NS_ASSERT (device->IsBroadcast ());
device->SetLinkChangeCallback (MakeCallback (&ArpCache::Flush, cache));

View File

@@ -48,8 +48,6 @@ public:
*/
ArpL3Protocol (Ptr<Node> node);
virtual ~ArpL3Protocol ();
virtual TraceResolver *CreateTraceResolver (TraceContext const &context);
/**
* \brief Recieve a packet
*/

View File

@@ -21,9 +21,9 @@
#include "ascii-trace.h"
#include "ns3/trace-context.h"
#include "ns3/trace-root.h"
#include "ns3/simulator.h"
#include "ns3/node.h"
#include "ns3/node-list.h"
#include "ns3/packet.h"
#include "ns3/queue.h"
@@ -41,19 +41,19 @@ void
AsciiTrace::TraceAllQueues (void)
{
Packet::EnableMetadata ();
TraceRoot::Connect ("/nodes/*/devices/*/queue/enqueue",
NodeList::Connect ("/nodes/*/devices/*/queue/enqueue",
MakeCallback (&AsciiTrace::LogDevQueueEnqueue, this));
TraceRoot::Connect ("/nodes/*/devices/*/queue/dequeue",
NodeList::Connect ("/nodes/*/devices/*/queue/dequeue",
MakeCallback (&AsciiTrace::LogDevQueueDequeue, this));
TraceRoot::Connect ("/nodes/*/devices/*/queue/drop",
NodeList::Connect ("/nodes/*/devices/*/queue/drop",
MakeCallback (&AsciiTrace::LogDevQueueDrop, this));
}
void
AsciiTrace::TraceAllNetDeviceRx (void)
{
Packet::EnableMetadata ();
TraceRoot::Connect ("/nodes/*/devices/*/rx",
MakeCallback (&AsciiTrace::LogDevRx, this));
NodeList::Connect ("/nodes/*/devices/*/rx",
MakeCallback (&AsciiTrace::LogDevRx, this));
}
void

View File

@@ -74,13 +74,14 @@ InternetNode::Construct (void)
Object::AddInterface (ipv4L4Demux);
}
void
InternetNode::DoFillTraceResolver (CompositeTraceResolver &resolver)
Ptr<TraceResolver>
InternetNode::GetTraceResolver () const
{
Node::DoFillTraceResolver (resolver);
Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
Ptr<Ipv4L3Protocol> ipv4 = QueryInterface<Ipv4L3Protocol> (Ipv4L3Protocol::iid);
resolver.Add ("ipv4",
MakeCallback (&Ipv4L3Protocol::CreateTraceResolver, PeekPointer (ipv4)));
resolver->AddComposite ("ipv4", ipv4);
resolver->SetParentResolver (Node::GetTraceResolver ());
return resolver;
}
void

View File

@@ -42,8 +42,8 @@ public:
protected:
virtual void DoDispose(void);
virtual Ptr<TraceResolver> GetTraceResolver (void) const;
private:
virtual void DoFillTraceResolver (CompositeTraceResolver &resolver);
bool ReceiveFromDevice (Ptr<NetDevice> device, const Packet &p, uint16_t protocolNumber) const;
void Construct (void);
};

View File

@@ -22,6 +22,7 @@
#include "ipv4-interface.h"
#include "ns3/ipv4-address.h"
#include "ns3/net-device.h"
#include "ns3/trace-resolver.h"
namespace ns3 {
@@ -39,18 +40,19 @@ Ipv4Interface::Ipv4Interface (Ptr<NetDevice> nd)
Ipv4Interface::~Ipv4Interface ()
{}
void
Ipv4Interface::DoDispose (void)
{
m_netdevice = 0;
Object::DoDispose ();
}
Ptr<NetDevice>
Ipv4Interface::GetDevice (void) const
{
return m_netdevice;
}
TraceResolver *
Ipv4Interface::CreateTraceResolver (TraceContext const &context)
{
return DoCreateTraceResolver (context);
}
void
Ipv4Interface::SetAddress (Ipv4Address a)
{

View File

@@ -26,6 +26,7 @@
#include <list>
#include "ns3/ipv4-address.h"
#include "ns3/ptr.h"
#include "ns3/object.h"
namespace ns3 {
@@ -60,9 +61,8 @@ class TraceContext;
*
* Subclasses must implement the two methods:
* - Ipv4Interface::SendTo
* - Ipv4Interface::DoCreateTraceResolver
*/
class Ipv4Interface
class Ipv4Interface : public Object
{
public:
/**
@@ -73,17 +73,6 @@ public:
Ipv4Interface (Ptr<NetDevice> nd);
virtual ~Ipv4Interface();
/**
* \param context the trace context to use to construct the
* TraceResolver to return
* \returns a TraceResolver which can resolve all traces
* performed in this object. The caller must
* delete the returned object.
*
* This method will delegate the work to the private DoCreateTraceResolver
* method which is supposed to be implemented by subclasses.
*/
TraceResolver *CreateTraceResolver (TraceContext const &context);
/**
* \returns the underlying NetDevice. This method can return
* zero if this interface has no associated NetDevice.
@@ -150,10 +139,10 @@ public:
*/
void Send(Packet p, Ipv4Address dest);
private:
protected:
virtual void DoDispose (void);
private:
virtual void SendTo (Packet p, Ipv4Address dest) = 0;
virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context) = 0;
Ptr<NetDevice> m_netdevice;
bool m_ifup;
Ipv4Address m_address;

View File

@@ -22,7 +22,6 @@
#include "ns3/packet.h"
#include "ns3/debug.h"
#include "ns3/composite-trace-resolver.h"
#include "ns3/array-trace-resolver.h"
#include "ns3/callback.h"
#include "ns3/ipv4-address.h"
#include "ns3/ipv4-route.h"
@@ -88,30 +87,40 @@ Ipv4L3ProtocolTraceContextElement::GetUid (void)
static uint16_t uid = AllocateUid<Ipv4L3ProtocolTraceContextElement> ("Ipv4L3ProtocolTraceContextElement");
return uid;
}
std::string
Ipv4L3ProtocolTraceContextElement::GetTypeName (void) const
{
return "ns3::Ipv4L3ProtocolTraceContextElement";
}
Ipv4l3ProtocolInterfaceIndex::Ipv4l3ProtocolInterfaceIndex ()
Ipv4L3ProtocolInterfaceIndex::Ipv4L3ProtocolInterfaceIndex ()
: m_index (0)
{}
Ipv4l3ProtocolInterfaceIndex::Ipv4l3ProtocolInterfaceIndex (uint32_t index)
Ipv4L3ProtocolInterfaceIndex::Ipv4L3ProtocolInterfaceIndex (uint32_t index)
: m_index (index)
{}
uint32_t
Ipv4l3ProtocolInterfaceIndex::Get (void) const
Ipv4L3ProtocolInterfaceIndex::Get (void) const
{
return m_index;
}
void
Ipv4l3ProtocolInterfaceIndex::Print (std::ostream &os) const
Ipv4L3ProtocolInterfaceIndex::Print (std::ostream &os) const
{
os << "ipv4-interface=" << m_index;
}
uint16_t
Ipv4l3ProtocolInterfaceIndex::GetUid (void)
Ipv4L3ProtocolInterfaceIndex::GetUid (void)
{
static uint16_t uid = AllocateUid<Ipv4l3ProtocolInterfaceIndex> ("Ipv4l3ProtocolInterfaceIndex");
static uint16_t uid = AllocateUid<Ipv4L3ProtocolInterfaceIndex> ("Ipv4L3ProtocolInterfaceIndex");
return uid;
}
std::string
Ipv4L3ProtocolInterfaceIndex::GetTypeName (void) const
{
return "ns3::Ipv4L3ProtocolInterfaceIndex";
}
Ipv4L3Protocol::Ipv4L3Protocol(Ptr<Node> node)
@@ -131,10 +140,6 @@ Ipv4L3Protocol::~Ipv4L3Protocol ()
void
Ipv4L3Protocol::DoDispose (void)
{
for (Ipv4InterfaceList::iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++)
{
delete (*i);
}
m_interfaces.clear ();
m_node = 0;
m_staticRouting->Dispose ();
@@ -145,7 +150,7 @@ Ipv4L3Protocol::DoDispose (void)
void
Ipv4L3Protocol::SetupLoopback (void)
{
Ipv4LoopbackInterface * interface = new Ipv4LoopbackInterface (m_node);
Ptr<Ipv4LoopbackInterface> interface = Create<Ipv4LoopbackInterface> (m_node);
interface->SetAddress (Ipv4Address::GetLoopback ());
interface->SetNetworkMask (Ipv4Mask::GetLoopback ());
uint32_t index = AddIpv4Interface (interface);
@@ -153,26 +158,27 @@ Ipv4L3Protocol::SetupLoopback (void)
interface->SetUp ();
}
TraceResolver *
Ipv4L3Protocol::CreateTraceResolver (TraceContext const &context)
Ptr<TraceResolver>
Ipv4L3Protocol::GetTraceResolver (void) const
{
CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
resolver->Add ("tx", m_txTrace, Ipv4L3ProtocolTraceContextElement(Ipv4L3ProtocolTraceContextElement::TX));
resolver->Add ("rx", m_rxTrace, Ipv4L3ProtocolTraceContextElement(Ipv4L3ProtocolTraceContextElement::RX));
resolver->Add ("drop", m_dropTrace, Ipv4L3ProtocolTraceContextElement (Ipv4L3ProtocolTraceContextElement::DROP));
resolver->Add ("interfaces",
MakeCallback (&Ipv4L3Protocol::InterfacesCreateTraceResolver, this));
return resolver;
}
TraceResolver *
Ipv4L3Protocol::InterfacesCreateTraceResolver (TraceContext const &context) const
{
ArrayTraceResolver<Ipv4Interface *, Ipv4l3ProtocolInterfaceIndex> *resolver =
new ArrayTraceResolver<Ipv4Interface *,Ipv4l3ProtocolInterfaceIndex>
(context,
MakeCallback (&Ipv4L3Protocol::GetNInterfaces, this),
MakeCallback (&Ipv4L3Protocol::GetInterface, this));
Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
resolver->AddSource ("tx",
TraceDoc ("send ipv4 packet to outgoing interface",
"const Packet &", "packet sent",
"uint32_t", "index of output ipv4 interface"),
m_txTrace, Ipv4L3ProtocolTraceContextElement(Ipv4L3ProtocolTraceContextElement::TX));
resolver->AddSource ("rx",
TraceDoc ("receive ipv4 packet from incoming interface",
"const Packet &", "packet received",
"uint32_t", "index of input ipv4 interface"),
m_rxTrace, Ipv4L3ProtocolTraceContextElement(Ipv4L3ProtocolTraceContextElement::RX));
resolver->AddSource ("drop",
TraceDoc ("drop ipv4 packet",
"const Packet &", "packet dropped"),
m_dropTrace, Ipv4L3ProtocolTraceContextElement (Ipv4L3ProtocolTraceContextElement::DROP));
resolver->AddArray ("interfaces",
m_interfaces.begin (), m_interfaces.end (),
Ipv4L3ProtocolInterfaceIndex ());
return resolver;
}
@@ -265,18 +271,18 @@ Ipv4L3Protocol::RemoveRoute (uint32_t index)
uint32_t
Ipv4L3Protocol::AddInterface (Ptr<NetDevice> device)
{
Ipv4Interface *interface = new ArpIpv4Interface (m_node, device);
Ptr<Ipv4Interface> interface = Create<ArpIpv4Interface> (m_node, device);
return AddIpv4Interface (interface);
}
uint32_t
Ipv4L3Protocol::AddIpv4Interface (Ipv4Interface *interface)
Ipv4L3Protocol::AddIpv4Interface (Ptr<Ipv4Interface>interface)
{
uint32_t index = m_nInterfaces;
m_interfaces.push_back (interface);
m_nInterfaces++;
return index;
}
Ipv4Interface *
Ptr<Ipv4Interface>
Ipv4L3Protocol::GetInterface (uint32_t index) const
{
uint32_t tmp = 0;
@@ -296,7 +302,7 @@ Ipv4L3Protocol::GetNInterfaces (void) const
return m_nInterfaces;
}
Ipv4Interface *
Ptr<Ipv4Interface>
Ipv4L3Protocol::FindInterfaceForDevice (Ptr<const NetDevice> device)
{
for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++)
@@ -364,7 +370,7 @@ Ipv4L3Protocol::Send (Packet const &packet,
for (Ipv4InterfaceList::iterator ifaceIter = m_interfaces.begin ();
ifaceIter != m_interfaces.end (); ifaceIter++, ifaceIndex++)
{
Ipv4Interface *outInterface = *ifaceIter;
Ptr<Ipv4Interface> outInterface = *ifaceIter;
Packet packetCopy = packet;
NS_ASSERT (packetCopy.GetSize () <= outInterface->GetMtu ());
@@ -401,7 +407,7 @@ Ipv4L3Protocol::SendRealOut (bool found,
return;
}
packet.AddHeader (ipHeader);
Ipv4Interface *outInterface = GetInterface (route.GetInterface ());
Ptr<Ipv4Interface> outInterface = GetInterface (route.GetInterface ());
NS_ASSERT (packet.GetSize () <= outInterface->GetMtu ());
m_txTrace (packet, route.GetInterface ());
if (route.IsGateway ())
@@ -431,7 +437,7 @@ Ipv4L3Protocol::Forwarding (Packet const &packet, Ipv4Header &ipHeader, Ptr<NetD
for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin ();
i != m_interfaces.end (); i++)
{
Ipv4Interface *interface = *i;
Ptr<Ipv4Interface> interface = *i;
if (interface->GetDevice () == device)
{
if (ipHeader.GetDestination ().IsEqual (interface->GetBroadcast ()))
@@ -481,43 +487,43 @@ Ipv4L3Protocol::ForwardUp (Packet p, Ipv4Header const&ip)
void
Ipv4L3Protocol::SetAddress (uint32_t i, Ipv4Address address)
{
Ipv4Interface *interface = GetInterface (i);
Ptr<Ipv4Interface> interface = GetInterface (i);
interface->SetAddress (address);
}
void
Ipv4L3Protocol::SetNetworkMask (uint32_t i, Ipv4Mask mask)
{
Ipv4Interface *interface = GetInterface (i);
Ptr<Ipv4Interface> interface = GetInterface (i);
interface->SetNetworkMask (mask);
}
Ipv4Mask
Ipv4L3Protocol::GetNetworkMask (uint32_t i) const
{
Ipv4Interface *interface = GetInterface (i);
Ptr<Ipv4Interface> interface = GetInterface (i);
return interface->GetNetworkMask ();
}
Ipv4Address
Ipv4L3Protocol::GetAddress (uint32_t i) const
{
Ipv4Interface *interface = GetInterface (i);
Ptr<Ipv4Interface> interface = GetInterface (i);
return interface->GetAddress ();
}
uint16_t
Ipv4L3Protocol::GetMtu (uint32_t i) const
{
Ipv4Interface *interface = GetInterface (i);
Ptr<Ipv4Interface> interface = GetInterface (i);
return interface->GetMtu ();
}
bool
Ipv4L3Protocol::IsUp (uint32_t i) const
{
Ipv4Interface *interface = GetInterface (i);
Ptr<Ipv4Interface> interface = GetInterface (i);
return interface->IsUp ();
}
void
Ipv4L3Protocol::SetUp (uint32_t i)
{
Ipv4Interface *interface = GetInterface (i);
Ptr<Ipv4Interface> interface = GetInterface (i);
interface->SetUp ();
// If interface address and network mask have been set, add a route
@@ -533,7 +539,7 @@ Ipv4L3Protocol::SetUp (uint32_t i)
void
Ipv4L3Protocol::SetDown (uint32_t ifaceIndex)
{
Ipv4Interface *interface = GetInterface (ifaceIndex);
Ptr<Ipv4Interface> interface = GetInterface (ifaceIndex);
interface->SetDown ();
// Remove all routes that are going through this interface

View File

@@ -44,6 +44,9 @@ class Node;
class TraceResolver;
class TraceContext;
/**
* \brief hold in a TraceContext the type of trace source used by this Ipv4L3Protocol
*/
class Ipv4L3ProtocolTraceContextElement : public TraceContextElement
{
public:
@@ -54,23 +57,40 @@ public:
};
Ipv4L3ProtocolTraceContextElement ();
Ipv4L3ProtocolTraceContextElement (enum Type type);
/**
* \returns true if this is a tx event, false otherwise.
*/
bool IsTx (void) const;
/**
* \returns true if this is a rx event, false otherwise.
*/
bool IsRx (void) const;
/**
* \returns true if this is a drop event, false otherwise.
*/
bool IsDrop (void) const;
void Print (std::ostream &os) const;
static uint16_t GetUid (void);
std::string GetTypeName (void) const;
private:
enum Type m_type;
};
class Ipv4l3ProtocolInterfaceIndex : public TraceContextElement
/**
* \brief hold in a TraceContext the index of an Ipv4Interface within the ipv4 stack of a Node
*/
class Ipv4L3ProtocolInterfaceIndex : public TraceContextElement
{
public:
Ipv4l3ProtocolInterfaceIndex ();
Ipv4l3ProtocolInterfaceIndex (uint32_t index);
Ipv4L3ProtocolInterfaceIndex ();
Ipv4L3ProtocolInterfaceIndex (uint32_t index);
/**
* \returns the index of the Ipv4Interface within a Node.
*/
uint32_t Get (void) const;
void Print (std::ostream &os) const;
static uint16_t GetUid (void);
std::string GetTypeName (void) const;
private:
uint32_t m_index;
};
@@ -85,15 +105,6 @@ public:
Ipv4L3Protocol(Ptr<Node> node);
virtual ~Ipv4L3Protocol ();
/**
* \param context the trace context to use to construct the
* TraceResolver to return
* \returns a TraceResolver which can resolve all traces
* performed in this object. The caller must
* delete the returned object.
*/
virtual TraceResolver *CreateTraceResolver (TraceContext const &context);
/**
* \param ttl default ttl to use
*
@@ -109,7 +120,7 @@ public:
* Try to find an Ipv4Interface whose NetDevice is equal to
* the input NetDevice.
*/
Ipv4Interface *FindInterfaceForDevice (Ptr<const NetDevice> device);
Ptr<Ipv4Interface> FindInterfaceForDevice (Ptr<const NetDevice> device);
/**
* Lower layer calls this method after calling L3Demux::Lookup
@@ -159,7 +170,7 @@ public:
void RemoveRoute (uint32_t i);
uint32_t AddInterface (Ptr<NetDevice> device);
Ipv4Interface * GetInterface (uint32_t i) const;
Ptr<Ipv4Interface> GetInterface (uint32_t i) const;
uint32_t GetNInterfaces (void) const;
@@ -178,6 +189,7 @@ public:
protected:
virtual void DoDispose (void);
virtual Ptr<TraceResolver> GetTraceResolver (void) const;
private:
@@ -187,11 +199,10 @@ private:
Ipv4Header const &ipHeader);
bool Forwarding (Packet const &packet, Ipv4Header &ipHeader, Ptr<NetDevice> device);
void ForwardUp (Packet p, Ipv4Header const&ip);
uint32_t AddIpv4Interface (Ipv4Interface *interface);
uint32_t AddIpv4Interface (Ptr<Ipv4Interface> interface);
void SetupLoopback (void);
TraceResolver *InterfacesCreateTraceResolver (TraceContext const &context) const;
typedef std::list<Ipv4Interface*> Ipv4InterfaceList;
typedef std::list<Ptr<Ipv4Interface> > Ipv4InterfaceList;
typedef std::list< std::pair< int, Ptr<Ipv4RoutingProtocol> > > Ipv4RoutingProtocolList;
Ipv4InterfaceList m_interfaces;

View File

@@ -54,6 +54,11 @@ Ipv4L4ProtocolTraceContextElement::GetUid (void)
static uint16_t uid = AllocateUid<Ipv4L4ProtocolTraceContextElement> ("Ipv4L4ProtocolTraceContextElement");
return uid;
}
std::string
Ipv4L4ProtocolTraceContextElement::GetTypeName (void) const
{
return "ns3::Ipv4L4ProtocolTraceContextElement";
}
Ipv4L4Demux::Ipv4L4Demux (Ptr<Node> node)
@@ -78,21 +83,19 @@ Ipv4L4Demux::DoDispose (void)
Object::DoDispose ();
}
TraceResolver *
Ipv4L4Demux::CreateTraceResolver (TraceContext const &context)
Ptr<TraceResolver>
Ipv4L4Demux::GetTraceResolver (void) const
{
CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
for (L4List_t::const_iterator i = m_protocols.begin(); i != m_protocols.end(); ++i)
{
Ptr<Ipv4L4Protocol> protocol = *i;
std::string protValue;
std::ostringstream oss (protValue);
oss << (*i)->GetProtocolNumber ();
std::ostringstream oss;
oss << (unsigned int) (*i)->GetProtocolNumber ();
Ipv4L4ProtocolTraceContextElement protocolNumber = (*i)->GetProtocolNumber ();
resolver->Add (protValue,
MakeCallback (&Ipv4L4Protocol::CreateTraceResolver, PeekPointer (protocol)),
protocolNumber);
resolver->AddComposite (oss.str (), protocol, protocolNumber);
}
resolver->SetParentResolver (Object::GetTraceResolver ());
return resolver;
}
void

View File

@@ -37,14 +37,21 @@ class Node;
class TraceResolver;
class TraceContext;
/**
* \brief hold in a TraceContext the protocol number of a L4 Protocol
*/
class Ipv4L4ProtocolTraceContextElement : public TraceContextElement
{
public:
Ipv4L4ProtocolTraceContextElement ();
Ipv4L4ProtocolTraceContextElement (int protocolNumber);
/**
* \returns the protocol number as registered in the Ipv4L4Demux.
*/
int Get (void) const;
void Print (std::ostream &os) const;
static uint16_t GetUid (void);
std::string GetTypeName (void) const;
private:
int m_protocolNumber;
};
@@ -59,14 +66,6 @@ public:
Ipv4L4Demux (Ptr<Node> node);
virtual ~Ipv4L4Demux();
/**
* \param context the trace context to use to construct the
* TraceResolver to return
* \returns a TraceResolver which can resolve all traces
* performed in this object. The caller must
* delete the returned object.
*/
TraceResolver *CreateTraceResolver (TraceContext const &context);
/**
* \param protocol a template for the protocol to add to this L4 Demux.
* \returns the L4Protocol effectively added.
@@ -95,8 +94,10 @@ public:
* returned from the Ipv4L4Protocol::Insert method.
*/
void Remove (Ptr<Ipv4L4Protocol> protocol);
private:
protected:
Ptr<TraceResolver> GetTraceResolver (void) const;
virtual void DoDispose (void);
private:
typedef std::list<Ptr<Ipv4L4Protocol> > L4List_t;
L4List_t m_protocols;
Ptr<Node> m_node;

View File

@@ -37,10 +37,6 @@ class TraceContext;
/**
* \brief L4 Protocol base class
*
* All subclasses must implement:
* - Ipv4L4Protocol::Copy
* - Ipv4L4Protocol::CreateTraceResolver
*
* If you want to implement a new L4 protocol, all you have to do is
* implement a subclass of this base class and add it to an L4Demux.
*/
@@ -59,8 +55,6 @@ public:
*/
int GetVersion() const;
virtual TraceResolver *CreateTraceResolver (TraceContext const &context) = 0;
/**
* \param p packet to forward up
* \param source source address of packet received

View File

@@ -19,7 +19,6 @@
* Authors:
* Mathieu Lacage <mathieu.lacage@sophia.inria.fr>,
*/
#include "ns3/empty-trace-resolver.h"
#include "ns3/net-device.h"
#include "ns3/node.h"
#include "ns3/eui48-address.h"
@@ -34,13 +33,6 @@ Ipv4LoopbackInterface::Ipv4LoopbackInterface (Ptr<Node> node)
{}
Ipv4LoopbackInterface::~Ipv4LoopbackInterface ()
{}
TraceResolver *
Ipv4LoopbackInterface::DoCreateTraceResolver (TraceContext const &context)
{
return new EmptyTraceResolver (context);
}
void
Ipv4LoopbackInterface::SendTo (Packet packet, Ipv4Address dest)
{

View File

@@ -43,7 +43,6 @@ class Ipv4LoopbackInterface : public Ipv4Interface
private:
virtual void SendTo (Packet p, Ipv4Address dest);
virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context);
Ptr<Node> m_node;
};

View File

@@ -22,7 +22,7 @@
#include <sstream>
#include "ns3/trace-root.h"
#include "ns3/node-list.h"
#include "ns3/trace-context.h"
#include "ns3/callback.h"
#include "ns3/pcap-writer.h"
@@ -50,8 +50,8 @@ PcapTrace::~PcapTrace ()
void
PcapTrace::TraceAllIp (void)
{
TraceRoot::Connect ("/nodes/*/ipv4/(tx|rx)",
MakeCallback (&PcapTrace::LogIp, this));
NodeList::Connect ("/nodes/*/ipv4/(tx|rx)",
MakeCallback (&PcapTrace::LogIp, this));
}
PcapWriter *
@@ -83,7 +83,7 @@ void
PcapTrace::LogIp (TraceContext const &context, Packet const &p, uint32_t interfaceIndex)
{
NodeListIndex nodeIndex;
context.Get (nodeIndex);
context.GetElement (nodeIndex);
PcapWriter *writer = GetStream (nodeIndex.Get (), interfaceIndex);
writer->WritePacket (p);
}

View File

@@ -21,7 +21,6 @@
#include "ns3/assert.h"
#include "ns3/packet.h"
#include "ns3/empty-trace-resolver.h"
#include "ns3/node.h"
#include "udp-l4-protocol.h"
@@ -45,12 +44,6 @@ UdpL4Protocol::UdpL4Protocol (Ptr<Node> node)
UdpL4Protocol::~UdpL4Protocol ()
{}
TraceResolver *
UdpL4Protocol::CreateTraceResolver (TraceContext const &context)
{
return new EmptyTraceResolver (context);
}
void
UdpL4Protocol::DoDispose (void)
{

View File

@@ -49,7 +49,6 @@ public:
UdpL4Protocol (Ptr<Node> node);
virtual ~UdpL4Protocol ();
virtual TraceResolver *CreateTraceResolver (TraceContext const &context);
/**
* \return A smart Socket pointer to a UdpSocket, allocated by this instance
* of the UDP protocol

View File

@@ -41,8 +41,8 @@ HierarchicalMobilityModel::HierarchicalMobilityModel (Ptr<MobilityModel> child,
parentNotifier = Create<MobilityModelNotifier> ();
parent->AddInterface (parentNotifier);
}
childNotifier->RegisterListener (MakeCallback (&HierarchicalMobilityModel::ChildChanged, this));
parentNotifier->RegisterListener (MakeCallback (&HierarchicalMobilityModel::ParentChanged, this));
childNotifier->TraceConnect ("/course-changed", MakeCallback (&HierarchicalMobilityModel::ChildChanged, this));
parentNotifier->TraceConnect ("/course-changed", MakeCallback (&HierarchicalMobilityModel::ParentChanged, this));
}
Ptr<MobilityModel>
@@ -89,13 +89,13 @@ HierarchicalMobilityModel::DoGetSpeed (void) const
}
void
HierarchicalMobilityModel::ParentChanged (Ptr<const MobilityModel> model)
HierarchicalMobilityModel::ParentChanged (const TraceContext &context, Ptr<const MobilityModel> model)
{
MobilityModel::NotifyCourseChange ();
}
void
HierarchicalMobilityModel::ChildChanged (Ptr<const MobilityModel> model)
HierarchicalMobilityModel::ChildChanged (const TraceContext &context, Ptr<const MobilityModel> model)
{
MobilityModel::NotifyCourseChange ();
}

View File

@@ -63,8 +63,8 @@ private:
virtual void DoSet (const Position &position);
virtual Speed DoGetSpeed (void) const;
void ParentChanged (Ptr<const MobilityModel> model);
void ChildChanged (Ptr<const MobilityModel> model);
void ParentChanged (const TraceContext &context, Ptr<const MobilityModel> model);
void ChildChanged (const TraceContext &context, Ptr<const MobilityModel> model);
Ptr<MobilityModel> m_child;
Ptr<MobilityModel> m_parent;

View File

@@ -19,6 +19,8 @@
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "mobility-model-notifier.h"
#include "ns3/composite-trace-resolver.h"
#include "ns3/trace-doc.h"
namespace ns3 {
@@ -32,37 +34,24 @@ MobilityModelNotifier::MobilityModelNotifier ()
SetInterfaceId (MobilityModelNotifier::iid);
}
void
MobilityModelNotifier::RegisterListener (Listener listener)
{
m_listeners.push_back (listener);
}
void
MobilityModelNotifier::UnregisterListener (Listener callback)
{
for (std::list<Listener>::iterator i = m_listeners.begin ();
i != m_listeners.end ();)
{
Listener listener = *i;
if (listener.IsEqual (callback))
{
i = m_listeners.erase (i);
}
else
{
i++;
}
}
}
void
MobilityModelNotifier::Notify (Ptr<const MobilityModel> position) const
{
for (std::list<Listener>::const_iterator i = m_listeners.begin ();
i != m_listeners.end (); i++)
{
Listener listener = *i;
listener (position);
}
m_trace (position);
}
Ptr<TraceResolver>
MobilityModelNotifier::GetTraceResolver (void) const
{
Ptr<CompositeTraceResolver> resolver =
Create<CompositeTraceResolver> ();
resolver->AddSource ("course-change",
TraceDoc ("The value of the speed vector changed",
"Ptr<const MobilityModel>",
"the mobility model whose course changed"),
m_trace);
resolver->SetParentResolver (Object::GetTraceResolver ());
return resolver;
}
} // namespace ns3

View File

@@ -24,6 +24,7 @@
#include "ns3/object.h"
#include "ns3/component-manager.h"
#include "ns3/callback.h"
#include "ns3/callback-trace-source.h"
#include "mobility-model.h"
namespace ns3 {
@@ -37,8 +38,6 @@ public:
static const InterfaceId iid;
static const ClassId cid;
typedef Callback<void,Ptr<const MobilityModel> > Listener;
/**
* Create a new position notifier
*/
@@ -48,23 +47,10 @@ public:
* \param position the position which just changed.
*/
void Notify (Ptr<const MobilityModel> position) const;
/**
* \param listener listener to add
*
* The listener will be notified upon every position change.
*/
void RegisterListener (Listener listener);
/**
* \param listener listener to remove
*
* The listener will not be notified anymore upon every
* position change. It is not an error to try to unregister
* a non-registered liste
*/
void UnregisterListener (Listener listener);
protected:
virtual Ptr<TraceResolver> GetTraceResolver (void) const;
private:
std::list<Listener> m_listeners;
CallbackTraceSource<Ptr<const MobilityModel> > m_trace;
};
} // namespace ns3

View File

@@ -23,6 +23,7 @@
#include "ns3/assert.h"
#include "ns3/object.h"
#include "ns3/debug.h"
#include "ns3/trace-resolver.h"
#include "channel.h"
@@ -183,12 +184,6 @@ NetDevice::Send(const Packet& p, const Address& dest, uint16_t protocolNumber)
}
}
TraceResolver *
NetDevice::CreateTraceResolver (TraceContext const &context)
{
return DoCreateTraceResolver (context);
}
Ptr<Channel>
NetDevice::GetChannel (void) const
{

View File

@@ -62,14 +62,6 @@ public:
static const InterfaceId iid;
virtual ~NetDevice();
/**
* \param context the trace context to use to construct the
* TraceResolver to return
* \returns a TraceResolver which can resolve all traces
* performed in this object. The caller must
* delete the returned object.
*/
TraceResolver *CreateTraceResolver (TraceContext const &context);
/**
* \return the channel this NetDevice is connected to. The value
@@ -282,15 +274,6 @@ public:
* Subclasses must implement this method.
*/
virtual bool DoNeedsArp (void) const = 0;
/**
* \param context the trace context to associated to the
* trace resolver.
* \returns a trace resolver associated to the input context.
* the caller takes ownership of the pointer returned.
*
* Subclasses must implement this method.
*/
virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context) = 0;
/**
* \returns the channel associated to this NetDevice.
*

View File

@@ -20,24 +20,12 @@
* Mathieu Lacage <mathieu.lacage@sophia.inria.fr>,
*/
#include "ns3/array-trace-resolver.h"
#include "ns3/trace-root.h"
#include "ns3/composite-trace-resolver.h"
#include "ns3/simulator.h"
#include "ns3/simulation-singleton.h"
#include "node-list.h"
#include "node.h"
namespace {
static class Initialization
{
public:
Initialization ()
{
ns3::TraceRoot::Register ("nodes", ns3::MakeCallback (&ns3::NodeList::CreateTraceResolver));
}
} g_initialization;
}
namespace ns3 {
NodeListIndex::NodeListIndex ()
@@ -62,6 +50,11 @@ NodeListIndex::Get (void) const
{
return m_index;
}
std::string
NodeListIndex::GetTypeName (void) const
{
return "ns3::NodeListIndex";
}
/**
@@ -74,9 +67,9 @@ public:
~NodeListPriv ();
uint32_t Add (Ptr<Node> node);
NodeList::Iterator Begin (void);
NodeList::Iterator End (void);
TraceResolver *CreateTraceResolver (TraceContext const &context);
NodeList::Iterator Begin (void) const;
NodeList::Iterator End (void) const;
Ptr<TraceResolver> GetTraceResolver (void) const;
Ptr<Node> GetNode (uint32_t n);
uint32_t GetNNodes (void);
@@ -108,12 +101,12 @@ NodeListPriv::Add (Ptr<Node> node)
}
NodeList::Iterator
NodeListPriv::Begin (void)
NodeListPriv::Begin (void) const
{
return m_nodes.begin ();
}
NodeList::Iterator
NodeListPriv::End (void)
NodeListPriv::End (void) const
{
return m_nodes.end ();
}
@@ -130,14 +123,11 @@ NodeListPriv::GetNode (uint32_t n)
}
TraceResolver *
NodeListPriv::CreateTraceResolver (TraceContext const &context)
Ptr<TraceResolver>
NodeListPriv::GetTraceResolver (void) const
{
ArrayTraceResolver<Ptr<Node>, NodeListIndex> *resolver =
new ArrayTraceResolver<Ptr<Node>, NodeListIndex>
(context,
MakeCallback (&NodeListPriv::GetNNodes, this),
MakeCallback (&NodeListPriv::GetNode, this));
Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
resolver->AddArray ("nodes", Begin (), End (), NodeListIndex ());
return resolver;
}
@@ -165,17 +155,30 @@ NodeList::End (void)
{
return SimulationSingleton<NodeListPriv>::Get ()->End ();
}
TraceResolver *
NodeList::CreateTraceResolver (TraceContext const &context)
{
return SimulationSingleton<NodeListPriv>::Get ()->CreateTraceResolver (context);
}
Ptr<Node>
NodeList::GetNode (uint32_t n)
{
return SimulationSingleton<NodeListPriv>::Get ()->GetNode (n);
}
void
NodeList::Connect (std::string name, const CallbackBase &cb)
{
SimulationSingleton<NodeListPriv>::Get ()->GetTraceResolver ()->Connect (name, cb, TraceContext ());
}
void
NodeList::Disconnect (std::string name, const CallbackBase &cb)
{
SimulationSingleton<NodeListPriv>::Get ()->GetTraceResolver ()->Disconnect (name, cb);
}
void
NodeList::TraceAll (std::ostream &os)
{
SimulationSingleton<NodeListPriv>::Get ()->GetTraceResolver ()->TraceAll (os, TraceContext ());
}
Ptr<TraceResolver>
NodeList::GetTraceResolver (void)
{
return SimulationSingleton<NodeListPriv>::Get ()->GetTraceResolver ();
}
}//namespace ns3

View File

@@ -29,9 +29,12 @@
namespace ns3 {
class Node;
class CallbackBase;
class TraceResolver;
class TraceContext;
/**
* \brief hold in a TraceContext the index of a node within a NodeList.
*/
class NodeListIndex : public TraceContextElement
{
public:
@@ -39,7 +42,11 @@ public:
NodeListIndex (uint32_t index);
void Print (std::ostream &os);
static uint16_t GetUid (void);
/**
* \returns the index of the node within the NodeList
*/
uint32_t Get (void) const;
std::string GetTypeName (void) const;
private:
uint32_t m_index;
};
@@ -53,7 +60,7 @@ private:
class NodeList
{
public:
typedef std::vector< Ptr<Node> >::iterator Iterator;
typedef std::vector< Ptr<Node> >::const_iterator Iterator;
/**
* \param node node to add
@@ -73,19 +80,30 @@ public:
* list.
*/
static Iterator End (void);
/**
* \param context trace context to use for trace resolver
* to create.
* \returns the requested trace resolver. The caller
* takes ownership of the returned pointer.
*/
static TraceResolver *CreateTraceResolver (TraceContext const &context);
/**
* \param n index of requested node.
* \returns the Node associated to index n.
*/
static Ptr<Node> GetNode (uint32_t n);
/**
* \param name namespace regexp to match
* \param cb callback to connect
*
* Connect input callback to all trace sources which match
* the input namespace regexp.
*/
static void Connect (std::string name, const CallbackBase &cb);
/**
* \param name namespace regexp to match
* \param cb callback to connect
*
* Disconnect input callback from all trace sources which match
* the input namespace regexp.
*/
static void Disconnect (std::string name, const CallbackBase &cb);
static void TraceAll (std::ostream &os);
static Ptr<TraceResolver> GetTraceResolver (void);
private:
};
}//namespace ns3

View File

@@ -25,7 +25,6 @@
#include "packet-socket-factory.h"
#include "ns3/simulator.h"
#include "ns3/composite-trace-resolver.h"
#include "ns3/array-trace-resolver.h"
namespace ns3{
@@ -53,6 +52,11 @@ NodeNetDeviceIndex::GetUid (void)
static uint16_t uid = AllocateUid<NodeNetDeviceIndex> ("NodeNetDeviceIndex");
return uid;
}
std::string
NodeNetDeviceIndex::GetTypeName (void) const
{
return "ns3::NodeNetDeviceIndex";
}
@@ -82,11 +86,12 @@ Node::Construct (void)
Node::~Node ()
{}
TraceResolver *
Node::CreateTraceResolver (TraceContext const &context)
Ptr<TraceResolver>
Node::GetTraceResolver (void) const
{
CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
DoFillTraceResolver (*resolver);
Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
resolver->AddArray ("devices", m_devices.begin (), m_devices.end (), NodeNetDeviceIndex ());
resolver->SetParentResolver (Object::GetTraceResolver ());
return resolver;
}
@@ -141,25 +146,6 @@ Node::GetNApplications (void) const
return m_applications.size ();
}
TraceResolver *
Node::CreateDevicesTraceResolver (const TraceContext &context)
{
ArrayTraceResolver<Ptr<NetDevice>,NodeNetDeviceIndex> *resolver =
new ArrayTraceResolver<Ptr<NetDevice>,NodeNetDeviceIndex>
(context,
MakeCallback (&Node::GetNDevices, this),
MakeCallback (&Node::GetDevice, this));
return resolver;
}
void
Node::DoFillTraceResolver (CompositeTraceResolver &resolver)
{
resolver.Add ("devices",
MakeCallback (&Node::CreateDevicesTraceResolver, this));
}
void
Node::DoDispose()
{

View File

@@ -37,13 +37,20 @@ class Packet;
class Address;
class CompositeTraceResolver;
/**
* \brief hold in a TraceContext the index of a NetDevice within a Node
*/
class NodeNetDeviceIndex : public TraceContextElement
{
public:
NodeNetDeviceIndex ();
NodeNetDeviceIndex (uint32_t index);
/**
* \returns the index of the NetDevice within its container Node.
*/
uint32_t Get (void) const;
void Print (std::ostream &os) const;
std::string GetTypeName (void) const;
static uint16_t GetUid (void);
private:
uint32_t m_index;
@@ -84,17 +91,6 @@ public:
virtual ~Node();
/**
* \param context the trace context for the TraceResolver to create
* \returns a newly-created TraceResolver. The caller takes
* ownership of the returned pointer.
*
* Request the Node to create a trace resolver. This method
* could be used directly by a user who needs access to very low-level
* trace configuration.
*/
TraceResolver *CreateTraceResolver (TraceContext const &context);
/**
* \returns the unique id of this node.
*
@@ -183,23 +179,15 @@ public:
void UnregisterProtocolHandler (ProtocolHandler handler);
protected:
virtual Ptr<TraceResolver> GetTraceResolver (void) const;
/**
* The dispose method. Subclasses must override this method
* and must chain up to it by calling Node::DoDispose at the
* end of their own DoDispose method.
*/
virtual void DoDispose (void);
/**
* \param resolver the resolver to store trace sources in.
*
* If a subclass wants to add new traces to a Node, it needs
* to override this method and record the new trace sources
* in the input resolver. Subclasses also _must_ chain up to
* their parent's DoFillTraceResolver method prior
* to recording they own trace sources.
*/
virtual void DoFillTraceResolver (CompositeTraceResolver &resolver);
private:
/**
* \param device the device added to this Node.
*
@@ -213,7 +201,6 @@ private:
bool ReceiveFromDevice (Ptr<NetDevice> device, const Packet &packet,
uint16_t protocol, const Address &from);
void Construct (void);
TraceResolver *CreateDevicesTraceResolver (const TraceContext &context);
struct ProtocolHandlerEntry {
ProtocolHandler handler;

View File

@@ -32,6 +32,11 @@ static ClassIdDefaultValue g_classIdDefaultValue ("Queue", "Packet Queue",
Queue::iid, "DropTailQueue");
std::string
QueueTraceType::GetTypeName (void) const
{
return "ns3::QueueTraceType";
}
uint16_t
QueueTraceType::GetUid (void)
{
@@ -94,13 +99,23 @@ Queue::~Queue()
NS_DEBUG("Queue::~Queue ()");
}
TraceResolver *
Queue::CreateTraceResolver (TraceContext const &context)
Ptr<TraceResolver>
Queue::GetTraceResolver (void) const
{
CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
resolver->Add ("enqueue", m_traceEnqueue, QueueTraceType (QueueTraceType::ENQUEUE));
resolver->Add ("dequeue", m_traceDequeue, QueueTraceType (QueueTraceType::DEQUEUE));
resolver->Add ("drop", m_traceDrop, QueueTraceType (QueueTraceType::DROP));
Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
resolver->AddSource ("enqueue",
TraceDoc ("store packet in queue",
"const Packet &", "packet queued"),
m_traceEnqueue, QueueTraceType (QueueTraceType::ENQUEUE));
resolver->AddSource ("dequeue",
TraceDoc ("remove packet from queue",
"const Packet &", "packet dequeued"),
m_traceDequeue, QueueTraceType (QueueTraceType::DEQUEUE));
resolver->AddSource ("drop",
TraceDoc ("drop packet from queue",
"const Packet &", "packet dropped"),
m_traceDrop, QueueTraceType (QueueTraceType::DROP));
resolver->SetParentResolver (Object::GetTraceResolver ());
return resolver;
}

View File

@@ -37,6 +37,9 @@ namespace ns3 {
class StringEnumDefaultValue;
/**
* \brief hold in a TraceContext the type of a trace source
*/
class QueueTraceType : public TraceContextElement
{
public:
@@ -48,10 +51,20 @@ public:
static uint16_t GetUid (void);
QueueTraceType ();
QueueTraceType (enum Type type);
/**
* \returns true if this is an enqueue event, false otherwise.
*/
bool IsEnqueue (void) const;
/**
* \returns true if this is a dequeue event, false otherwise.
*/
bool IsDequeue (void) const;
/**
* \returns true if this is a drop event, false otherwise.
*/
bool IsDrop (void) const;
void Print (std::ostream &os) const;
std::string GetTypeName (void) const;
private:
enum Type m_type;
};
@@ -69,8 +82,6 @@ public:
Queue ();
virtual ~Queue ();
TraceResolver *CreateTraceResolver (TraceContext const &context);
/**
* \return true if the queue is empty; false otherwise
@@ -167,6 +178,7 @@ private:
virtual bool DoPeek (Packet &p) = 0;
protected:
Ptr<TraceResolver> GetTraceResolver (void) const;
// called by subclasses to notify parent of packet drops.
void Drop (const Packet& p);

View File

@@ -1407,27 +1407,6 @@ GlobalRouteManagerImpl::SPFVertexAddParent (SPFVertex* v)
namespace ns3 {
class GlobalRouterTestNode : public Node
{
public:
GlobalRouterTestNode ();
private:
virtual void DoAddDevice (Ptr<NetDevice> device) const {};
virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context);
};
GlobalRouterTestNode::GlobalRouterTestNode ()
{
// Ptr<Ipv4L3Protocol> ipv4 = Create<Ipv4L3Protocol> (this);
}
TraceResolver*
GlobalRouterTestNode::DoCreateTraceResolver (TraceContext const &context)
{
return 0;
}
class GlobalRouteManagerImplTest : public Test {
public:
GlobalRouteManagerImplTest ();

View File

@@ -0,0 +1,100 @@
#include "ns3/internet-node.h"
#include "ns3/ptr.h"
#include "ns3/trace-resolver.h"
#include "ns3/node-list.h"
#include "ns3/point-to-point-net-device.h"
#include "ns3/csma-net-device.h"
#include "ns3/queue.h"
#include "ns3/mobility-model-notifier.h"
using namespace ns3;
void
PrintSimpleText (const TraceResolver::SourceCollection *sources, std::ostream &os)
{
for (TraceResolver::SourceCollection::Iterator i = sources->Begin (); i != sources->End (); i++)
{
os << "source=" << i->path << std::endl;
os << "TraceContext=[";
i->context.PrintAvailable (os, ",");
os << "]" << std::endl;
os << "help=\"" << i->doc.GetHelp () << "\"" << std::endl;
os << "void TraceSinkCallback (const TraceContext &";
for (TraceDoc::Iterator k = i->doc.ArgsBegin (); k != i->doc.ArgsEnd (); k++)
{
os << ", " << k->first;
}
os << ")" << std::endl;
os << "argument 1 -- the trace context associated to the connected trace source." << std::endl;
uint32_t k = 2;
for (TraceDoc::Iterator j = i->doc.ArgsBegin (); j != i->doc.ArgsEnd (); j++)
{
os << "argument " << k << " -- " << j->second << "." << std::endl;
k++;
}
os << std::endl;
}
}
void
PrintDoxygenText (const TraceResolver::SourceCollection *sources, std::ostream &os)
{
uint32_t z = 0;
for (TraceResolver::SourceCollection::Iterator i = sources->Begin (); i != sources->End (); i++)
{
os << "///" << std::endl;
os << "/// \\ingroup TraceSourceList" << std::endl;
os << "/// \\brief " << i->doc.GetHelp () << std::endl;
os << "/// \\param arg1 the trace context associated to the connected trace source." << std::endl;
uint32_t j = 2;
for (TraceDoc::Iterator l = i->doc.ArgsBegin (); l != i->doc.ArgsEnd (); l++)
{
os << "/// \\param arg" << j << " " << l->second << "." << std::endl;
j++;
}
os << "///" << std::endl;
os << "///" << std::endl;
os << "/// The path to this trace source is: " << i->path << "." << std::endl;
os << "///" << std::endl;
if (i->context.Begin ().IsLast ())
{
os << "/// No data can be extracted from \\p arg1 with ns3::TraceContext::GetElement." << std::endl;
}
else
{
os << "/// The following classes can be extracted from \\p arg1 with " << std::endl;
os << "/// ns3::TraceContext::GetElement:" << std::endl;
for (TraceContext::Iterator m = i->context.Begin (); !m.IsLast (); m.Next ())
{
os << "/// - " << m.Get () << std::endl;
}
}
os << "void TraceSinkCallback" << z << " (const TraceContext & arg1" ;
j = 2;
for (TraceDoc::Iterator k = i->doc.ArgsBegin (); k != i->doc.ArgsEnd (); k++)
{
os << ", " << k->first << " arg" << j;
j++;
}
os << ");" << std::endl;
os << std::endl;
z++;
}
}
int main (int argc, char *argv[])
{
Ptr<Node> node = Create<InternetNode> ();
node->AddInterface (Create<MobilityModelNotifier> ());
Ptr<PointToPointNetDevice> p2p = Create<PointToPointNetDevice> (node);
p2p->AddQueue (Queue::CreateDefault ());
Ptr<CsmaNetDevice> csma = Create<CsmaNetDevice> (node);
csma->AddQueue (Queue::CreateDefault ());
TraceResolver::SourceCollection collection;
NodeList::GetTraceResolver ()->CollectSources ("", TraceContext (), &collection);
PrintDoxygenText (&collection, std::cout);
return 0;
}

View File

@@ -19,3 +19,7 @@ def build(bld):
obj = bld.create_ns3_program('replay-simulation', ['simulator'])
obj.source = 'replay-simulation.cc'
obj = bld.create_ns3_program('print-trace-sources',
['internet-node', 'csma-cd', 'point-to-point'])
obj.source = 'print-trace-sources.cc'