Statistics
| Branch: | Revision:

root / include / ccomponent.h @ 08285dff

History | View | Annotate | Download (21.9 KB)

1
//==========================================================================
2
//   CCOMPONENT.H  -  header for
3
//                     OMNeT++/OMNEST
4
//            Discrete System Simulation in C++
5
//
6
//==========================================================================
7

    
8
/*--------------------------------------------------------------*
9
  Copyright (C) 1992-2008 Andras Varga
10
  Copyright (C) 2006-2008 OpenSim Ltd.
11

12
  This file is distributed WITHOUT ANY WARRANTY. See the file
13
  `license' for details on this and other legal matters.
14
*--------------------------------------------------------------*/
15

    
16
#ifndef __CCOMPONENT_H
17
#define __CCOMPONENT_H
18

    
19
#include <vector>
20
#include "simkerneldefs.h"
21
#include "cownedobject.h"
22
#include "cpar.h"
23
#include "cdefaultlist.h"
24
#include "simtime.h"
25
#include "cenvir.h"
26
#include "clistener.h"
27

    
28
NAMESPACE_BEGIN
29

    
30
class cComponentType;
31
class cProperties;
32
class cDisplayString;
33
class cRNG;
34
class cStatistic;
35

    
36
/**
37
 * Common base for module and channel classes: cModule and cChannel.
38
 * cComponent provides parameters, properties and RNG mapping.
39
 *
40
 * @ingroup SimCore
41
 */
42
class SIM_API cComponent : public cDefaultList //implies noncopyable
43
{
44
    friend class cPar; // needs to call handleParameterChange()
45
    friend class cChannel; // allow it to access FL_INITIALIZED and releaseLocalListeners()
46
    friend class cModule; // allow it to access FL_INITIALIZED, releaseLocalListeners() and repairSignalFlags()
47
    friend class cGate;   // because of repairSignalFlags()
48

    
49
  private:
50
    enum {
51
      FL_PARAMSFINALIZED = 4,   // whether finalizeParameters() has been called
52
      FL_INITIALIZED = 8,       // whether initialize() has been called
53
      FL_EVLOGENABLED = 16,     // whether logging via ev<< is enabled
54
      FL_DISPSTR_CHECKED = 32,  // for hasDisplayString(): whether the FL_DISPSTR_NOTEMPTY flag is valid
55
      FL_DISPSTR_NOTEMPTY = 64, // for hasDisplayString(): whether the display string is not empty
56
    };
57

    
58
  private:
59
    cComponentType *componenttype;  // component type object
60

    
61
    short rngmapsize;  // size of rngmap array (RNGs>=rngmapsize are mapped one-to-one to physical RNGs)
62
    int *rngmap;       // maps local RNG numbers (may be NULL if rngmapsize==0)
63

    
64
    short paramvsize;
65
    short numparams;
66
    cPar *paramv;  // array of cPar objects
67

    
68
    cDisplayString *dispstr; // display string (created on demand)
69

    
70
    struct SignalData
71
    {
72
        simsignal_t signalID;
73
        cIListener **listeners; // NULL-terminated array
74

    
75
        SignalData() {signalID=SIMSIGNAL_NULL; listeners=NULL;}
76
        bool addListener(cIListener *l);
77
        bool removeListener(cIListener *l);
78
        int findListener(cIListener *l);
79
        int countListeners();
80
        bool hasListener() {return listeners && listeners[0];}
81
        static bool gt(const SignalData& e1, const SignalData& e2) {return e1.signalID > e2.signalID;}
82
    };
83

    
84
    typedef std::vector<SignalData> SignalTable;
85
    SignalTable *signalTable; // ordered by signalID so we can do binary search
86

    
87
    // flags to speed up emit() for signals 0..63 when there are no or few listeners
88
    uint64 signalHasLocalListeners;    // bit[k]==1: signalID k has local listeners
89
    uint64 signalHasAncestorListeners; // bit[k]==1: signalID k has listener in parent or in any ancestor component
90

    
91
    // string-to-simsignal_t mapping
92
    static std::map<std::string,simsignal_t> signalIDs;
93
    static std::map<simsignal_t,std::string> signalNames;
94
    static int lastSignalID;
95

    
96
    // stack of listener lists being notified, to detect concurrent modification
97
    static cIListener **notificationStack[];
98
    static int notificationSP;
99

    
100
  private:
101
    SignalData *findSignalData(simsignal_t signalID) const;
102
    SignalData *findOrCreateSignalData(simsignal_t signalID);
103
    void removeSignalData(simsignal_t signalID);
104
    void checkNotFiring(simsignal_t, cIListener **listenerList);
105
    template<typename T> void fire(cComponent *src, simsignal_t signalID, T x);
106
    void fireFinish();
107
    void signalListenerAdded(simsignal_t signalID);
108
    void signalListenerRemoved(simsignal_t signalID);
109
    void repairSignalFlags();
110
    bool computeHasListeners(simsignal_t signalID) const;
111
    void releaseLocalListeners();
112

    
113
  public:
114
    // internal: currently used by Cmdenv
115
    void setEvEnabled(bool e)  {setFlag(FL_EVLOGENABLED,e);}
116
    bool isEvEnabled() const  {return flags&FL_EVLOGENABLED;}
117

    
118
    // internal: invoked from within cEnvir::getRNGMappingFor(component)
119
    void setRNGMap(short size, int *map) {rngmapsize=size; rngmap=map;}
120

    
121
    // internal: sets associated cComponentType for the component;
122
    // called as part of the creation process.
123
    virtual void setComponentType(cComponentType *componenttype);
124

    
125
    // internal: adds a new parameter to the component; called as part of the creation process
126
    virtual void addPar(cParImpl *value);
127

    
128
    // internal: reallocates paramv (size must be >= numparams)
129
    void reallocParamv(int size);
130

    
131
    // internal: save parameters marked with "save-as-scalars=true"
132
    virtual void recordParametersAsScalars();
133

    
134
    // internal: has finalizeParameters() been called?
135
    bool parametersFinalized() const {return flags&FL_PARAMSFINALIZED;}
136

    
137
    // internal: has initialize() been called?
138
    bool initialized() const {return flags&FL_INITIALIZED;}
139

    
140
    // internal: used from Tkenv: find out if this module has a display string.
141
    // getDisplayString() would create the object immediately which we want to avoid.
142
    bool hasDisplayString();
143

    
144
    // internal: checks consistency of signal listener flags
145
    void checkLocalSignalConsistency() const;
146
    void checkSignalConsistency() const;
147

    
148
    // internal: clears signal-related static data structures; to be invoked before each simulation run
149
    static void clearSignalState();
150

    
151
  protected:
152
    /** @name Initialization, finish and parameter change hooks.
153
     *
154
     * Initialize and finish functions may be provided by the user,
155
     * to perform special tasks at the beginning and the end of the simulation.
156
     * The functions are made protected because they are supposed
157
     * to be called only via callInitialize() and callFinish().
158
     *
159
     * The initialization process was designed to support multi-stage
160
     * initialization of compound modules (i.e. initialization in several
161
     * 'waves'). (Calling the initialize() function of a simple module is
162
     * hence a special case). The initialization process is performed
163
     * on a module like this. First, the number of necessary initialization
164
     * stages is determined by calling numInitStages(), then initialize(stage)
165
     * is called with <tt>0,1,...numstages-1</tt> as argument. The default
166
     * implementation of numInitStages() and initialize(stage) provided here
167
     * defaults to single-stage initialization, that is, numInitStages()
168
     * returns 1 and initialize(stage) simply calls initialize() if stage is 0.
169
     */
170
    //@{
171

    
172
    /**
173
     * Multi-stage initialization hook. This default implementation does
174
     * single-stage init, that is, calls initialize() if stage is 0.
175
     */
176
    virtual void initialize(int stage) {if (stage==0) initialize();}
177

    
178
    /**
179
     * Multi-stage initialization hook, should be redefined to return the
180
     * number of initialization stages required. This default implementation
181
     * does single-stage init, that is, returns 1.
182
     */
183
    virtual int numInitStages() const  {return 1;}
184

    
185
    /**
186
     * Single-stage initialization hook. This default implementation
187
     * does nothing.
188
     */
189
    virtual void initialize();
190

    
191
    /**
192
     * Finish hook. finish() is called after end of simulation, if it
193
     * terminated without error. This default implementation does nothing.
194
     */
195
    virtual void finish();
196

    
197
    /**
198
     * This method is called by the simulation kernel to notify the module or
199
     * channel that the value of an existing parameter got changed.
200
     * Redefining this method allows simple modules and channels to be react on
201
     * parameter changes, for example by re-reading the value.
202
     * This default implementation does nothing.
203
     *
204
     * The parameter name can be NULL if more than one parameter has changed.
205
     *
206
     * To make it easier to write predictable components, the function does
207
     * NOT get called on uninitialized components (i.e. when initialized() returns
208
     * false). For each component the function is called (with NULL as a parname)
209
     * after the last stage of the initialization so the module gets a chance to
210
     * update its cached parameters.
211
     *
212
     * Also, one must be extremely careful when changing parameters from inside
213
     * handleParameterChange(), to avoid creating an infinite notification loop.
214
     */
215
    virtual void handleParameterChange(const char *parname);
216
    //@}
217

    
218
  public:
219
    /** @name Constructors, destructor, assignment. */
220
    //@{
221
    /**
222
     * Constructor. Note that module and channel objects should not be created
223
     * directly, via their cComponentType objects. cComponentType::create()
224
     * will do all housekeeping associated with creating the module (assigning
225
     * an ID to the module, inserting it into the <tt>simulation</tt> object,
226
     * etc.).
227
     */
228
    cComponent(const char *name = NULL);
229

    
230
    /**
231
     * Destructor.
232
     */
233
    virtual ~cComponent();
234
    //@}
235

    
236
    /** @name Redefined cObject functions */
237
    //@{
238
    /**
239
     * Redefined to include component parameters in the traversal as well.
240
     */
241
    virtual void forEachChild(cVisitor *v);
242
    //@}
243

    
244
    /**
245
     * Must be called after the component was created, and (with modules)
246
     * before buildInside(). It reads input parameters from omnetpp.ini,
247
     * and cModule extends this method to add gates to the module too
248
     * (as this is the earliest time parameter values are available,
249
     * and gate vector sizes may depend on parameters).
250
     */
251
    virtual void finalizeParameters();
252

    
253
    /** @name Misc. */
254
    //@{
255
    /**
256
     * Return the properties for this component. Properties cannot be changed
257
     * at runtime.
258
     */
259
    virtual cProperties *getProperties() const = 0;
260

    
261
    /**
262
     * Returns the associated component type. Guaranteed to be non-NULL.
263
     */
264
    cComponentType *getComponentType() const;
265

    
266
    /**
267
     * Returns the fully qualified NED type name of the component (i.e. the
268
     * simple name prefixed with the package name and any existing enclosing
269
     * NED type names).
270
     *
271
     * This method is a shortcut to <tt>getComponentType()->getFullName()</tt>.
272
     */
273
    virtual const char *getNedTypeName() const;
274

    
275
    /**
276
     * Redefined to return true in cModule and subclasses, otherwise returns false.
277
     */
278
    virtual bool isModule() const  {return false;}
279

    
280
    /**
281
     * Returns true for channels, and false for modules.
282
     */
283
    bool isChannel() const  {return !isModule();}
284

    
285
    /**
286
     * Returns the module containing this module/channel. This is not necessarily
287
     * the same object as getOwner(), especially for channel objects. For the system
288
     * module, it returns NULL.
289
     */
290
    virtual cModule *getParentModule() const = 0;
291

    
292
    /**
293
     * Returns the global RNG mapped to local RNG number k. For large indices
294
     * (k >= map size) the global RNG k is returned, provided it exists.
295
     */
296
    cRNG* getRNG(int k) const;
297
    //@}
298

    
299
    /** @name Interface for calling initialize()/finish().
300
     * Those functions may not be called directly, only via
301
     * callInitialize() and callFinish() provided here.
302
     */
303
    //@{
304

    
305
    /**
306
     * Interface for calling initialize() from outside.
307
     */
308
    virtual void callInitialize() = 0;
309

    
310
    /**
311
     * Interface for calling initialize() from outside. It does a single stage
312
     * of initialization, and returns <tt>true</tt> if more stages are required.
313
     */
314
    virtual bool callInitialize(int stage) = 0;
315

    
316
    /**
317
     * Interface for calling finish() from outside. This method includes
318
     * calling finish() of contained components (submodules, channels) as well.
319
     */
320
    virtual void callFinish() = 0;
321
    //@}
322

    
323
    /** @name Parameters. */
324
    //@{
325

    
326
    /**
327
     * Returns total number of the component's parameters.
328
     */
329
    virtual int getNumParams() const  {return numparams;}
330

    
331
    /**
332
     * Returns reference to the parameter identified with its
333
     * index k. Throws an error if the parameter does not exist.
334
     */
335
    virtual cPar& par(int k);
336

    
337
    /**
338
     * Returns reference to the parameter identified with its
339
     * index k. Throws an error if the parameter does not exist.
340
     */
341
    const cPar& par(int k) const  {return const_cast<cComponent *>(this)->par(k);}
342

    
343
    /**
344
     * Returns reference to the parameter specified with its name.
345
     * Throws an error if the parameter does not exist.
346
     */
347
    virtual cPar& par(const char *parname);
348

    
349
    /**
350
     * Returns reference to the parameter specified with its name.
351
     * Throws an error if the parameter does not exist.
352
     */
353
    const cPar& par(const char *parname) const  {return const_cast<cComponent *>(this)->par(parname);}
354

    
355
    /**
356
     * Returns index of the parameter specified with its name.
357
     * Returns -1 if the object doesn't exist.
358
     */
359
    virtual int findPar(const char *parname) const;
360

    
361
    /**
362
     * Check if a parameter exists.
363
     */
364
    bool hasPar(const char *s) const {return findPar(s)>=0;}
365
    //@}
366

    
367
    /** @name Emitting simulation signals. */
368
    //@{
369
    /**
370
     * Returns the signal ID (handle) for the given signal name. Signal names
371
     * and IDs are global. The signal ID for a particular name gets assigned
372
     * at the first registerSignal() call; further registerSignal() calls for
373
     * the same name will return the same ID.
374
     *
375
     * There is some significance to the order of registerSignal() calls: the
376
     * first 64 signal names registered have somewhat better notification
377
     * performance characteristics than later signals, so it is advised to
378
     * register frequently emitted signals first.
379
     */
380
    static simsignal_t registerSignal(const char *name);
381

    
382
    /**
383
     * The inverse of registerSignal(): returns the name of the given signal,
384
     * or NULL for invalid signal handles.
385
     */
386
    static const char *getSignalName(simsignal_t signalID);
387

    
388
    /**
389
     * Emits the long value as a signal. If the given signal has listeners in this
390
     * component or in ancestor components, their appropriate receiveSignal() methods
391
     * get called. If there are no listeners, the runtime cost is usually minimal.
392
     */
393
    void emit(simsignal_t signalID, long l);
394

    
395
    /**
396
     * Emits the unsigned long value as a signal. If the given signal has listeners in
397
     * this component or in ancestor components, their appropriate receiveSignal() methods
398
     * get called. If there are no listeners, the runtime cost is usually minimal.
399
     */
400
    void emit(simsignal_t signalID, unsigned long l);
401

    
402
    /**
403
     * Emits the double value as a signal. If the given signal has listeners in this
404
     * component or in ancestor components, their appropriate receiveSignal() methods
405
     * get called. If there are no listeners, the runtime cost is usually minimal.
406
     */
407
    void emit(simsignal_t signalID, double d);
408

    
409
    /**
410
     * Emits the simtime_t value as a signal. If the given signal has listeners in this
411
     * component or in ancestor components, their appropriate receiveSignal() methods
412
     * get called. If there are no listeners, the runtime cost is usually minimal.
413
     *
414
     * Note: for technical reasons, the argument type is SimTime instead of simtime_t;
415
     * otherwise when compiled with USE_DOUBLE_SIMTIME we would have two "double"
416
     * overloads for emit().
417
     */
418
    void emit(simsignal_t signalID, const SimTime& t);
419

    
420
    /**
421
     * Emits the given string as a signal. If the given signal has listeners in this
422
     * component or in ancestor components, their appropriate receiveSignal() methods
423
     * get called. If there are no listeners, the runtime cost is usually minimal.
424
     */
425
    void emit(simsignal_t signalID, const char *s);
426

    
427
    /**
428
     * Emits the given object as a signal. If the given signal has listeners in this
429
     * component or in ancestor components, their appropriate receiveSignal() methods
430
     * get called. If there are no listeners, the runtime cost is usually minimal.
431
     */
432
    void emit(simsignal_t signalID, cObject *obj);
433

    
434
    /** Delegates to emit(simsignal_t, long) */
435
    void emit(simsignal_t signalID, bool b) {emit(signalID,(long)b);}
436

    
437
    /** Delegates to emit(simsignal_t, long) */
438
    void emit(simsignal_t signalID, char c) {emit(signalID,(long)c);}
439

    
440
    /** Delegates to emit(simsignal_t, unsigned long) */
441
    void emit(simsignal_t signalID, unsigned char c) {emit(signalID,(unsigned long)c);}
442

    
443
    /** Delegates to emit(simsignal_t, long) */
444
    void emit(simsignal_t signalID, short i) {emit(signalID,(long)i);}
445

    
446
    /** Delegates to emit(simsignal_t, unsigned long) */
447
    void emit(simsignal_t signalID, unsigned short i) {emit(signalID,(unsigned long)i);}
448

    
449
    /** Delegates to emit(simsignal_t, long) */
450
    void emit(simsignal_t signalID, int i) {emit(signalID,(long)i);}
451

    
452
    /** Delegates to emit(simsignal_t, unsigned long) */
453
    void emit(simsignal_t signalID, unsigned int i) {emit(signalID,(unsigned long)i);}
454

    
455
    /** Delegates to emit(simsignal_t, double) */
456
    void emit(simsignal_t signalID, float f) {emit(signalID,(double)f);}
457

    
458
    /** Delegates to emit(simsignal_t, double) */
459
    void emit(simsignal_t signalID, long double d) {emit(signalID,(double)d);}
460

    
461
    /**
462
     * If producing a value for a signal has a significant runtime cost, this
463
     * method can be used to check beforehand whether the given signal possibly
464
     * has any listeners at all -- if not, emitting the signal can be skipped.
465
     * This functions is significantly more efficient than hasListeners()
466
     * (amortizes in constant time), but may return "false positive".
467
     */
468
    bool mayHaveListeners(simsignal_t signalID) const {
469
        // for fast signals (ID in 0..63) we use flags that cache the state;
470
        // for other signals we return true. Note: no "if" for efficiency reasons
471
        uint64 mask = (uint64)1 << signalID;
472
        return (~signalHasLocalListeners & ~signalHasAncestorListeners & mask)==0; // always true for signalID > 63
473
    }
474

    
475
    /**
476
     * Returns true if the given signal has any listeners. For some signals
477
     * this method has a significant overhead (linear to the number of hierarchy
478
     * levels in the network).
479
     *
480
     * @see mayHaveListeners()
481
     */
482
    bool hasListeners(simsignal_t signalID) const {
483
        uint64 mask = (uint64)1 << signalID;
484
        return mask ? ((signalHasLocalListeners|signalHasAncestorListeners) & mask) : computeHasListeners(signalID);
485
    }
486
    //@}
487

    
488
    /** @name Subscribing to simulation signals. */
489
    //@{
490
    /**
491
     * Adds a listener (callback object) that will be notified when a given
492
     * signal is emitted (see emit() methods). It is an error to subscribe
493
     * the same listener twice to the same signal. The order in which listeners
494
     * will be notified is undefined, so it is not necessarily the same order
495
     * in which listeners were subscribed.
496
     */
497
    void subscribe(simsignal_t signalID, cIListener *listener);
498

    
499
    /**
500
     * Convenience method; it is equivalent to
501
     * <tt>subscribe(registerSignal(signalName), listener).</tt>
502
     */
503
    void subscribe(const char *signalName, cIListener *listener);
504

    
505
    /**
506
     * Removes the given listener. It has no effect if the given listener
507
     * is not subscribed.
508
     */
509
    void unsubscribe(simsignal_t signalID, cIListener *listener);
510

    
511
    /**
512
     * Convenience method; it is equivalent to
513
     * <tt>unsubscribe(registerSignal(signalName), listener).</tt>
514
     */
515
    void unsubscribe(const char *signalName, cIListener *listener);
516

    
517
    /**
518
     * Returns true if the given listener is subscribed to the given signal
519
     * at this component (i.e. it does not look at listeners subscribed
520
     * at ancestor components).
521
     */
522
    bool isSubscribed(simsignal_t signalID, cIListener *listener) const;
523

    
524
    /**
525
     * Convenience method; it is equivalent to
526
     * <tt>isSubscribed(registerSignal(signalName), listener).</tt>
527
     */
528
    bool isSubscribed(const char *signalName, cIListener *listener) const;
529

    
530
    /**
531
     * Returns the signals which have listeners subscribed at this component.
532
     */
533
    std::vector<simsignal_t> getLocalListenedSignals() const;
534

    
535
    /**
536
     * Returns the listeners subscribed to the given signal at this component.
537
     */
538
    std::vector<cIListener*> getLocalSignalListeners(simsignal_t signalID) const;
539
    //@}
540

    
541
    /** @name Display strings, animation. */
542
    //@{
543
    /**
544
     * Returns the display string which defines presentation when the module
545
     * is displayed as a submodule in a compound module graphics.
546
     */
547
    cDisplayString& getDisplayString();
548

    
549
    /**
550
     * Shortcut to <tt>getDisplayString().set(dispstr)</tt>.
551
     */
552
    void setDisplayString(const char *dispstr);
553

    
554
    /**
555
     * When the models is running under Tkenv, it displays the given text
556
     * in the network graphics, as a bubble above the module's icon.
557
     */
558
    void bubble(const char *text);
559
    //@}
560

    
561
    /** @name Statistics collection */
562
    //@{
563

    
564
    /**
565
     * Records a double into the scalar result file.
566
     */
567
    void recordScalar(const char *name, double value, const char *unit=NULL);
568

    
569
    /**
570
     * Convenience method, delegates to recordScalar(const char *, double).
571
     */
572
    void recordScalar(const char *name, SimTime value, const char *unit=NULL) {recordScalar(name, value.dbl(), unit);}
573

    
574
    /**
575
     * Records the given statistics into the scalar result file. Delegates to
576
     * cStatistic::recordAs(). Note that if the statistics object is a histogram,
577
     * this operation may invoke its transform() method.
578
     */
579
    void recordStatistic(cStatistic *stats, const char *unit=NULL);
580

    
581
    /**
582
     * Records the given statistics into the scalar result file with the given name.
583
     * Delegates to cStatistic::recordAs().  Note that if the statistics object is
584
     * a histogram, this operation may invoke its transform() method.
585
     */
586
    void recordStatistic(const char *name, cStatistic *stats, const char *unit=NULL);
587
    //@}
588
};
589

    
590
NAMESPACE_END
591

    
592

    
593
#endif
594