Statistics
| Branch: | Revision:

root / src / sim / ccomponent.cc @ 08285dff

History | View | Annotate | Download (23.7 KB)

1
//==========================================================================
2
//   CCOMPONENT.CC  -  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
#include <algorithm>
17
#include "ccomponent.h"
18
#include "ccomponenttype.h"
19
#include "cmodule.h"
20
#include "cchannel.h"
21
#include "cmodelchange.h"
22
#include "cproperties.h"
23
#include "cproperty.h"
24
#include "cpar.h"
25
#include "cparimpl.h"
26
#include "crng.h"
27
#include "cstatistic.h"
28
#include "cconfiguration.h"
29
#include "cconfigoption.h"
30
#include "cdisplaystring.h"
31
#include "stringutil.h"
32
#include "cenvir.h"
33

    
34
USING_NAMESPACE
35

    
36

    
37
Register_PerObjectConfigOption(CFGID_PARAM_RECORD_AS_SCALAR, "param-record-as-scalar", CFG_BOOL, "false", "Applicable to module parameters: specifies whether the module parameter should be recorded into the output scalar file. Set it for parameters whose value you'll need for result analysis.");
38

    
39
std::map<std::string,simsignal_t> cComponent::signalIDs;
40
std::map<simsignal_t,std::string> cComponent::signalNames;
41
int cComponent::lastSignalID;
42

    
43
static const int NOTIFICATION_STACK_SIZE = 64;
44
cIListener **cComponent::notificationStack[NOTIFICATION_STACK_SIZE];
45
int cComponent::notificationSP = 0;
46

    
47

    
48
cComponent::cComponent(const char *name) : cDefaultList(name)
49
{
50
    componenttype = NULL;
51
    rngmapsize = 0;
52
    rngmap = 0;
53

    
54
    paramvsize = numparams = 0;
55
    paramv = NULL;
56

    
57
    dispstr = NULL;
58
    setEvEnabled(true);
59

    
60
    signalTable = NULL;
61
    signalHasLocalListeners = signalHasAncestorListeners = 0;
62
}
63

    
64
cComponent::~cComponent()
65
{
66
    ASSERT(signalTable==NULL); // note: releaseLocalListeners() gets called in subclasses, ~cModule and ~cChannel
67
    delete [] rngmap;
68
    delete [] paramv;
69
    delete dispstr;
70
}
71

    
72
void cComponent::forEachChild(cVisitor *v)
73
{
74
    for (int i=0; i<numparams; i++)
75
        v->visit(&paramv[i]);
76

    
77
    cDefaultList::forEachChild(v);
78
}
79

    
80
void cComponent::setComponentType(cComponentType *componenttype)
81
{
82
    this->componenttype = componenttype;
83
}
84

    
85
void cComponent::initialize()
86
{
87
    // Called before simulation starts (or usually after dynamic module was created).
88
    // Should be redefined by user.
89
}
90

    
91
void cComponent::finish()
92
{
93
    // Called at the end of a successful simulation (and usually before destroying a dynamic module).
94
    // Should be redefined by user.
95
}
96

    
97
void cComponent::handleParameterChange(const char *)
98
{
99
    // Called when a module parameter changes.
100
    // Can be redefined by the user.
101
}
102

    
103
cComponentType *cComponent::getComponentType() const
104
{
105
    if (!componenttype)
106
        throw cRuntimeError(this, "Object has no associated cComponentType (maybe %s should not subclass cModule/cChannel?)", getClassName());
107
    return componenttype;
108
}
109

    
110
const char *cComponent::getNedTypeName() const
111
{
112
    return getComponentType()->getFullName();
113
}
114

    
115
void cComponent::reallocParamv(int size)
116
{
117
    ASSERT(size>=numparams);
118
    if (size!=(short)size)
119
        throw cRuntimeError(this, "reallocParamv(%d): at most %d parameters allowed", size, 0x7fff);
120
    cPar *newparamv = new cPar[size];
121
    for (int i=0; i<numparams; i++)
122
        paramv[i].moveto(newparamv[i]);
123
    delete [] paramv;
124
    paramv = newparamv;
125
    paramvsize = (short)size;
126
}
127

    
128
void cComponent::addPar(cParImpl *value)
129
{
130
    if (parametersFinalized())
131
        throw cRuntimeError(this, "cannot add parameters at runtime");
132
    if (findPar(value->getName())>=0)
133
        throw cRuntimeError(this, "cannot add parameter `%s': already exists", value->getName());
134
    if (numparams==paramvsize)
135
        reallocParamv(paramvsize+1);
136
    paramv[numparams++].init(this, value);
137
}
138

    
139
cPar& cComponent::par(int k)
140
{
141
    if (k<0 || k>=numparams)
142
        throw cRuntimeError(this, "parameter id %d out of range", k);
143
    return paramv[k];
144
}
145

    
146
cPar& cComponent::par(const char *parname)
147
{
148
    int k = findPar(parname);
149
    if (k<0)
150
        throw cRuntimeError(this, "has no parameter named `%s'", parname);
151
    return paramv[k];
152
}
153

    
154
int cComponent::findPar(const char *parname) const
155
{
156
    int n = getNumParams();
157
    for (int i=0; i<n; i++)
158
        if (paramv[i].isName(parname))
159
            return i;
160
    return -1;
161
}
162

    
163
void cComponent::finalizeParameters()
164
{
165
    if (parametersFinalized())
166
        throw cRuntimeError(this, "finalizeParameters() already called for this module or channel");
167

    
168
    // temporarily switch context
169
    cContextSwitcher tmp(this);
170
    cContextTypeSwitcher tmp2(CTX_BUILD);
171

    
172
    // read input parameters
173
    int n = getNumParams();
174
    for (int i=0; i<n; i++)
175
        par(i).read();
176

    
177
    setFlag(FL_PARAMSFINALIZED, true);
178
}
179

    
180
bool cComponent::hasDisplayString()
181
{
182
    if (dispstr)
183
        return true;
184
    if (flags & FL_DISPSTR_CHECKED)
185
        return flags & FL_DISPSTR_NOTEMPTY;
186

    
187
    // not yet checked: do it now
188
    cProperties *props = getProperties();
189
    cProperty *prop = props->get("display");
190
    const char *propValue = prop ? prop->getValue(cProperty::DEFAULTKEY) : NULL;
191
    bool result = !opp_isempty(propValue);
192

    
193
    setFlag(FL_DISPSTR_CHECKED, true);
194
    setFlag(FL_DISPSTR_NOTEMPTY, result);
195
    return result;
196
}
197

    
198
cDisplayString& cComponent::getDisplayString()
199
{
200
    if (!dispstr)
201
    {
202
        dispstr = new cDisplayString();
203
        dispstr->setHostObject(this);
204

    
205
        // set display string (it may depend on parameter values via "$param" references)
206
        if (!parametersFinalized())
207
            throw cRuntimeError(this, "Cannot access display string yet: parameters not yet set up");
208
        cProperties *props = getProperties();
209
        cProperty *prop = props->get("display");
210
        const char *propValue = prop ? prop->getValue(cProperty::DEFAULTKEY) : NULL;
211
        if (propValue)
212
            dispstr->parse(propValue);
213
    }
214
    return *dispstr;
215
}
216

    
217
void cComponent::setDisplayString(const char *s)
218
{
219
    getDisplayString().parse(s);
220
}
221

    
222
void cComponent::bubble(const char *text)
223
{
224
    ev.bubble(this, text);
225
}
226

    
227
void cComponent::recordParametersAsScalars()
228
{
229
    int n = getNumParams();
230
    for (int i=0; i<n; i++)
231
    {
232
        if (ev.getConfig()->getAsBool(par(i).getFullPath().c_str(), CFGID_PARAM_RECORD_AS_SCALAR, false))
233
        {
234
            //TODO the following checks should probably produce a WARNING not an error;
235
            //TODO also, the values should probably be recorded as "param" in the scalar file
236
            if (par(i).getType() == cPar::BOOL) // note: a bool is not considered to be numeric
237
                recordScalar(par(i).getName(), par(i).boolValue());
238
            else if (par(i).isNumeric()) {
239
                if (par(i).isVolatile() && (par(i).doubleValue()!=par(i).doubleValue() || par(i).doubleValue()!=par(i).doubleValue())) // crude check for random variates
240
                    throw cRuntimeError(this, "recording volatile parameter `%s' that contains a non-constant value (probably a random variate) as an output scalar -- recorded value is probably just a meaningless random number", par(i).getName());
241
                recordScalar(par(i).getName(), par(i).doubleValue());
242
            }
243
            else
244
                throw cRuntimeError(this, "cannot record non-numeric parameter `%s' as an output scalar", par(i).getName());
245
        }
246
    }
247
}
248

    
249
void cComponent::recordScalar(const char *name, double value, const char *unit)
250
{
251
    if (!unit)
252
        ev.recordScalar(this, name, value);
253
    else {
254
        opp_string_map attributes;
255
        attributes["unit"] = unit;
256
        ev.recordScalar(this, name, value, &attributes);
257
    }
258
}
259

    
260
void cComponent::recordStatistic(cStatistic *stats, const char *unit)
261
{
262
    stats->recordAs(NULL, unit);
263
}
264

    
265
void cComponent::recordStatistic(const char *name, cStatistic *stats, const char *unit)
266
{
267
    stats->recordAs(name, unit);
268
}
269

    
270
//----
271

    
272
bool cComponent::SignalData::addListener(cIListener *l)
273
{
274
    if (findListener(l) != -1)
275
        return false; // already subscribed
276

    
277
    // reallocate each time (subscribe operations are rare, so we optimize for memory footprint)
278
    int n = countListeners();
279
    cIListener **v = new cIListener*[n+2];
280
    memcpy(v, listeners, n*sizeof(cIListener*));
281
    v[n] = l;
282
    v[n+1] = NULL;
283
    delete [] listeners;
284
    listeners = v;
285
    return true;
286
}
287

    
288
bool cComponent::SignalData::removeListener(cIListener *l)
289
{
290
    int k = findListener(l);
291
    if (k == -1)
292
        return false; // not there
293

    
294
    // remove listener. note: don't delete listeners[] even if empty,
295
    // because fire() relies on it not being NULL
296
    int n = countListeners();
297
    listeners[k] = listeners[n-1];
298
    listeners[n-1] = NULL;
299
    return true;
300
}
301

    
302
int cComponent::SignalData::countListeners()
303
{
304
    if (!listeners)
305
        return 0;
306
    int k = 0;
307
    while (listeners[k])
308
        k++;
309
    return k;
310
}
311

    
312
int cComponent::SignalData::findListener(cIListener *l)
313
{
314
    if (!listeners)
315
        return -1;
316
    for (int k = 0; listeners[k]; k++)
317
        if (listeners[k] == l)
318
            return k;
319
    return -1;
320
}
321

    
322
simsignal_t cComponent::registerSignal(const char *name)
323
{
324
    if (signalIDs.find(name) == signalIDs.end()) {
325
        simsignal_t signalID = ++lastSignalID;
326
        signalIDs[name] = signalID;
327
        signalNames[signalID] = name;
328
    }
329
    return signalIDs[name];
330
}
331

    
332
const char *cComponent::getSignalName(simsignal_t signalID)
333
{
334
    return signalNames.find(signalID)!=signalNames.end() ? signalNames[signalID].c_str() : NULL;
335
}
336

    
337
void cComponent::clearSignalState()
338
{
339
    // clear registered signals and the notification stack
340
    signalIDs.clear();
341
    signalNames.clear();
342
    lastSignalID = -1;
343
    notificationSP = 0;
344

    
345
    // re-register predefined signals
346
    simsignal_t preSignalID = registerSignal("PRE_MODEL_CHANGE");
347
    simsignal_t postSignalID = registerSignal("POST_MODEL_CHANGE");
348
    ASSERT(preSignalID==PRE_MODEL_CHANGE);
349
    ASSERT(postSignalID==POST_MODEL_CHANGE);
350
}
351

    
352
cComponent::SignalData *cComponent::findSignalData(simsignal_t signalID) const
353
{
354
    // note: we could use std::binary_search() instead of linear search here,
355
    // but the number of signals that have listeners is likely to be small (<10),
356
    // so linear search is probably faster.
357
    if (signalTable)
358
        for (int i=0; i<(int)signalTable->size(); i++)
359
            if ((*signalTable)[i].signalID == signalID)
360
                return &(*signalTable)[i];
361
    return NULL;
362
}
363

    
364
cComponent::SignalData *cComponent::findOrCreateSignalData(simsignal_t signalID)
365
{
366
    SignalData *data = findSignalData(signalID);
367
    if (!data) {
368
        if (!signalTable)
369
            signalTable = new SignalTable;
370

    
371
        // add new entry
372
        signalTable->push_back(SignalData());
373
        data = &(*signalTable)[signalTable->size()-1];
374
        data->signalID = signalID;
375

    
376
        // sort signalTable[] so we can do binary search by signalID
377
        std::sort(signalTable->begin(), signalTable->end(), SignalData::gt);
378
        data = findSignalData(signalID); // must find it again because sort() moved it
379
    }
380
    return data;
381
}
382

    
383
void cComponent::checkNotFiring(simsignal_t signalID, cIListener **listenerList)
384
{
385
    // Check that the given listener list is not being notified.
386
    // NOTE: we use the listener list and not SignalData* for a reason:
387
    // SignalData may get moved as a result of new signals being subscribed
388
    // (they are stored in an std::vector!), so checking for pointer equality
389
    // would be no good. Move does not change the listener list pointer.
390
    if (listenerList)
391
        for (int i=0; i<notificationSP; i++)
392
            if (notificationStack[i] == listenerList)
393
                throw cRuntimeError(this, "subscribe()/unsubscribe() failed: cannot update listener list "
394
                                          "while its listeners are being notified, signalID=%d", signalID);
395
}
396

    
397
void cComponent::removeSignalData(simsignal_t signalID)
398
{
399
    if (signalTable) {
400
        // find in signal table
401
        int i;
402
        for (i=0; i<(int)signalTable->size(); i++)
403
            if ((*signalTable)[i].signalID == signalID)
404
                break;
405

    
406
        // if found, remove
407
        if (i<(int)signalTable->size()) {
408
            ASSERT(!(*signalTable)[i].hasListener()); // must not have listeners
409
            signalTable->erase(signalTable->begin()+i);
410
        }
411
        if (signalTable->empty()) {
412
            delete signalTable;
413
            signalTable = NULL;
414
        }
415
    }
416
}
417

    
418
void cComponent::emit(simsignal_t signalID, long l)
419
{
420
    if (mayHaveListeners(signalID))
421
        fire(this, signalID, l);
422
}
423

    
424
void cComponent::emit(simsignal_t signalID, unsigned long l)
425
{
426
    if (mayHaveListeners(signalID))
427
        fire(this, signalID, l);
428
}
429

    
430
void cComponent::emit(simsignal_t signalID, double d)
431
{
432
    if (mayHaveListeners(signalID))
433
        fire(this, signalID, d);
434
}
435

    
436
void cComponent::emit(simsignal_t signalID, const SimTime& t)
437
{
438
    if (mayHaveListeners(signalID))
439
        fire(this, signalID, t);
440
}
441

    
442
void cComponent::emit(simsignal_t signalID, const char *s)
443
{
444
    if (mayHaveListeners(signalID))
445
        fire(this, signalID, s);
446
}
447

    
448
void cComponent::emit(simsignal_t signalID, cObject *obj)
449
{
450
    if (mayHaveListeners(signalID))
451
        fire(this, signalID, obj);
452
}
453

    
454
template<typename T>
455
void cComponent::fire(cComponent *source, simsignal_t signalID, T x)
456
{
457
    uint64 mask = (uint64)1 << signalID;
458
    if ((~signalHasLocalListeners & mask)==0)  // always true for signalID > 63
459
    {
460
        // notify local listeners if there are any
461
        SignalData *data = findSignalData(signalID);
462
        if (data) {
463
            cIListener **listeners = data->listeners;
464
            if (notificationSP >= NOTIFICATION_STACK_SIZE)
465
                throw cRuntimeError(this, "emit(): recursive notification stack overflow, signalID=%d", signalID);
466

    
467
            int oldNotificationSP = notificationSP;
468
            try {
469
                notificationStack[notificationSP++] = listeners; // lock against modification
470
                for (int i=0; listeners[i]; i++)
471
                    listeners[i]->receiveSignal(source, signalID, x); // will crash if listener is already deleted
472
                notificationSP--;
473
            }
474
            catch (std::exception& e) {
475
                notificationSP = oldNotificationSP;
476
                throw;
477
            }
478

    
479
        }
480
    }
481

    
482
    if ((~signalHasAncestorListeners & mask)==0)  // always true for signalID > 63
483
    {
484
        // notify ancestors recursively
485
        cModule *parent = getParentModule();
486
        if (parent)
487
            parent->fire(source, signalID, x);
488
    }
489
}
490

    
491
void cComponent::fireFinish()
492
{
493
    if (signalTable)
494
        for (int i=0; i<(int)signalTable->size(); i++)
495
            for (cIListener **lp = (*signalTable)[i].listeners; *lp; ++lp)
496
                (*lp)->finish(this, (*signalTable)[i].signalID);
497
}
498

    
499
inline void setBit(uint64& flags, int bitnum, bool value)
500
{
501
    uint64 mask = (uint64)1 << bitnum;
502
    if (value)
503
        flags |= mask;
504
    else
505
        flags &= ~mask;
506
}
507

    
508
inline bool getBit(const uint64& flags, int bitnum)
509
{
510
    uint64 mask = (uint64)1 << bitnum;
511
    return flags & mask;
512
}
513

    
514
void cComponent::subscribe(simsignal_t signalID, cIListener *listener)
515
{
516
    // add to local listeners
517
    SignalData *data = findOrCreateSignalData(signalID);
518
    checkNotFiring(signalID, data->listeners);
519
    if (!data->addListener(listener))
520
        throw cRuntimeError(this, "subscribe(): listener already subscribed, signalID=%d", signalID);
521
    setBit(signalHasLocalListeners, signalID, true);
522

    
523
    // update hasAncestorListener flag in the whole subtree.
524
    // Note: if it was true here, it is already true in the whole subtree,
525
    // so no need to call signalListenerAdded()
526
    if (!getBit(signalHasAncestorListeners, signalID)) {
527
        signalListenerAdded(signalID);
528
        setBit(signalHasAncestorListeners, signalID, false); // restore it after signalListenerAdded() set it to true
529
    }
530

    
531
    listener->subscribecount++;
532
    listener->subscribedTo(this, signalID);
533
}
534

    
535
void cComponent::signalListenerAdded(simsignal_t signalID)
536
{
537
    // set the flag recursively in the subtree. If it's already set,
538
    // no need to recurse because all components must already have it
539
    // set as well
540
    if (!getBit(signalHasAncestorListeners, signalID)) {
541
        setBit(signalHasAncestorListeners, signalID, true);
542
        if (dynamic_cast<cModule *>(this)) {
543
            // Note: because of the dynamic_cast, this part could be moved to cModule
544
            for (cModule::SubmoduleIterator submod((cModule *)this); !submod.end(); submod++)
545
                submod()->signalListenerAdded(signalID);
546
            for (cModule::ChannelIterator chan((cModule *)this); !chan.end(); chan++)
547
                chan()->signalListenerAdded(signalID);
548
        }
549
    }
550
}
551

    
552
void cComponent::unsubscribe(simsignal_t signalID, cIListener *listener)
553
{
554
    // remove from local listeners list
555
    SignalData *data = findSignalData(signalID);
556
    if (!data)
557
        return;
558
    checkNotFiring(signalID, data->listeners);
559
    if (!data->removeListener(listener))
560
        return; // was already removed
561

    
562
    if (!data->hasListener()) {
563
        // no local listeners left: remove entry and adjust flags
564
        removeSignalData(signalID);
565
        setBit(signalHasLocalListeners, signalID, false);
566

    
567
        // clear "has ancestor listeners" flags in the whole submodule tree,
568
        // unless there are still listeners above this module
569
        if (!getBit(signalHasAncestorListeners, signalID))
570
            signalListenerRemoved(signalID);
571
    }
572

    
573
    listener->subscribecount--;
574
    listener->unsubscribedFrom(this, signalID);
575
}
576

    
577
void cComponent::signalListenerRemoved(simsignal_t signalID)
578
{
579
    // clear the flag recursively in the subtree. If the signal
580
    // has a listener at a module, leave its subtree alone.
581
    setBit(signalHasAncestorListeners, signalID, false);
582
    SignalData *data = findSignalData(signalID);
583
    if (!data || !data->hasListener()) {
584
        if (dynamic_cast<cModule *>(this)) {
585
            // Note: because of the dynamic_cast, this part could be moved to cModule
586
            for (cModule::SubmoduleIterator submod((cModule *)this); !submod.end(); submod++)
587
                submod()->signalListenerRemoved(signalID);
588
            for (cModule::ChannelIterator chan((cModule *)this); !chan.end(); chan++)
589
                chan()->signalListenerRemoved(signalID);
590
        }
591
    }
592
}
593

    
594
bool cComponent::isSubscribed(simsignal_t signalID, cIListener *listener) const
595
{
596
    SignalData *data = findSignalData(signalID);
597
    return data && data->findListener(listener) != -1;
598
}
599

    
600
void cComponent::repairSignalFlags()
601
{
602
    // adjusts hasAncestorListeners bits in the component's subtree;
603
    // to be called when the component's ownership changes
604
    cModule *p = getParentModule();
605
    signalHasAncestorListeners = p ? (p->signalHasAncestorListeners | p->signalHasLocalListeners) : 0;
606

    
607
    if (dynamic_cast<cModule *>(this)) {
608
        // Note: because of the dynamic_cast, this part could be moved to cModule
609
        for (cModule::SubmoduleIterator submod((cModule *)this); !submod.end(); submod++)
610
            submod()->repairSignalFlags();
611
        for (cModule::ChannelIterator chan((cModule *)this); !chan.end(); chan++)
612
            chan()->repairSignalFlags();
613
    }
614
}
615

    
616
void cComponent::subscribe(const char *signalName, cIListener *listener)
617
{
618
    subscribe(registerSignal(signalName), listener);
619
}
620

    
621
bool cComponent::isSubscribed(const char *signalName, cIListener *listener) const
622
{
623
    return isSubscribed(registerSignal(signalName), listener);
624
}
625

    
626
void cComponent::unsubscribe(const char *signalName, cIListener *listener)
627
{
628
    unsubscribe(registerSignal(signalName), listener);
629
}
630

    
631
std::vector<simsignal_t> cComponent::getLocalListenedSignals() const
632
{
633
    std::vector<simsignal_t> result;
634
    if (signalTable)
635
        for (int i=0; i<(int)signalTable->size(); i++)
636
            result.push_back((*signalTable)[i].signalID);
637
    return result;
638
}
639

    
640
std::vector<cIListener*> cComponent::getLocalSignalListeners(simsignal_t signalID) const
641
{
642
    std::vector<cIListener*> result;
643
    SignalData *data = findSignalData(signalID);
644
    if (data && data->hasListener())
645
        for (int i=0; data->listeners[i]; i++)
646
            result.push_back(data->listeners[i]);
647
    return result;
648
}
649

    
650
void cComponent::checkLocalSignalConsistency() const
651
{
652
    for (simsignal_t signalID=0; signalID<64; signalID++) {
653
        SignalData *data = findSignalData(signalID);
654
        bool hasLocalListeners = data && data->hasListener();
655

    
656
        bool hasAncestorListeners = false;
657
        for (cModule *mod = getParentModule(); mod; mod=mod->getParentModule()) {
658
            SignalData *data = mod->findSignalData(signalID);
659
            if (data && data->hasListener()) {
660
                hasAncestorListeners = true;
661
                break;
662
            }
663
        }
664

    
665
        if (hasLocalListeners != getBit(signalHasLocalListeners, signalID))
666
            throw cRuntimeError(this, "hasLocalListeners flag incorrect for signalID=%d", signalID);
667
        if (hasAncestorListeners != getBit(signalHasAncestorListeners, signalID))
668
            throw cRuntimeError(this, "signalHasAncestorListeners flag incorrect for signalID=%d", signalID);
669
    }
670
}
671

    
672
void cComponent::checkSignalConsistency() const
673
{
674
    checkLocalSignalConsistency();
675
    if (dynamic_cast<const cModule *>(this)) {
676
        for (cModule::SubmoduleIterator submod((cModule *)this); !submod.end(); submod++)
677
            submod()->checkSignalConsistency();
678
        for (cModule::ChannelIterator chan((cModule *)this); !chan.end(); chan++)
679
            chan()->checkSignalConsistency();
680
    }
681
}
682

    
683
bool cComponent::computeHasListeners(simsignal_t signalID) const
684
{
685
    SignalData *data = findSignalData(signalID);
686
    if (data && data->hasListener())
687
        return true;
688
    cModule *parent = getParentModule();
689
    if (parent)
690
        return parent->computeHasListeners(signalID);
691
    return false;
692
}
693

    
694
void cComponent::releaseLocalListeners()
695
{
696
    // note: this may NOT be called from our destructor (only subclasses' destructor),
697
    // because it would result in a "pure virtual method called" error
698
    if (signalTable)
699
    {
700
        while (signalTable && !signalTable->empty())
701
        {
702
            SignalData& signalData = signalTable->front();
703
            simsignal_t signalID = signalData.signalID;
704

    
705
            // unsubscribe listeners. Note: a "while (signalData.hasListener())"
706
            // loop would not work, because the last unsubscribe deletes signalData
707
            // as well. This "unsubscribe n times" method chosen here has problems if new
708
            // listeners get subscribed inside the unsubscribed() hook though.
709
            int n = signalData.countListeners();
710
            for (int i = 0; i < n; i++)
711
                unsubscribe(signalID, signalData.listeners[0]);
712
        }
713
        delete signalTable;
714
        signalTable = NULL;
715
    }
716

    
717
/*
718
    // this is a faster version, but since listener lists and flags are only
719
    // updated at the end, hasListeners(), isSubscribed() etc. may give
720
    // strange results when invoked within from unsubscribedFrom().
721
    if (signalTable)
722
    {
723
        // fire unsubscribedFrom() on listeners
724
        for (int i = 0; i < (int)signalTable->size(); i++) {
725
            for (cIListener **lp = (*signalTable)[i].listeners; *lp; ++lp) {
726
                (*lp)->subscribecount--;
727
                (*lp)->unsubscribedFrom(this, (*signalTable)[i].signalID);
728
            }
729
        }
730
        signalHasLocalListeners = 0;
731
        delete signalTable;
732
        signalTable = NULL;
733
    }
734
    cModule *parent = getParentModule();
735
    signalHasAncestorListeners = parent ? (parent->signalHasLocalListeners | parent->signalHasAncestorListeners) : 0; // this only works if releaseLocalListeners() is called top-down
736
*/
737
}
738

    
739
cRNG* cComponent::getRNG(int k) const
740
{
741
        const cModule* const thisMod=dynamic_cast<const cModule* const>(this);
742
        int modId=0;
743
        if(thisMod) modId=thisMod->getId();
744
        k+=modId*ev.getNumRNGsPerModule();
745
        return ev.getRNG(k);
746
}
747