Revision fbe00e73 src/sim/csimplemodule.cc

View differences:

src/sim/csimplemodule.cc
14 14
/*--------------------------------------------------------------*
15 15
  Copyright (C) 1992-2008 Andras Varga
16 16
  Copyright (C) 2006-2008 OpenSim Ltd.
17
  Copyright (C) 2009 Georg Kunz
17 18

  
18 19
  This file is distributed WITHOUT ANY WARRANTY. See the file
19 20
  `license' for details on this and other legal matters.
......
23 24
#include <stdio.h>           // sprintf
24 25
#include <string.h>          // strcpy
25 26
#include <exception>
27
#include <cstring>
28
#include <sstream>
29
#include <stdlib.h>
26 30
#include "csimplemodule.h"
31

  
27 32
#include "cgate.h"
28 33
#include "cmessage.h"
29 34
#include "ccoroutine.h"
......
34 39
#include "cenvir.h"
35 40
#include "cexception.h"
36 41
#include "commonutil.h"
42
#include "cthreadpool.h"
43
#include "cconfiguration.h"
44
#include "cconfigoption.h"
45
#include "../envir/envirbase.h"
46
#include "cstringtokenizer.h"
47

  
37 48

  
38 49
USING_NAMESPACE
39 50

  
......
41 52
bool cSimpleModule::stack_cleanup_requested;
42 53
cSimpleModule *cSimpleModule::after_cleanup_transfer_to;
43 54

  
55
Register_PerRunConfigOption(CFGID_ASYNCMODULE_PARZERODUR, "parallelize-zero-duration-events", CFG_BOOL, "false", "Parallelize Events with zero duration");
56
Register_PerObjectConfigOption(CFGID_NUM_LOCAL_RNGS, "number-local-rngs", CFG_INT, "1", "Number of RNGS per module");
57
Register_PerObjectConfigOption(CFGID_LOCAL_RNG_SEED, "local-rng-seed", CFG_STRING, "", "A whitespace seperated list of the seeds for each RNG of the corresponding module, eg '24 232 342 auto 342'");
58

  
44 59

  
45 60
void cSimpleModule::activate(void *p)
46 61
{
......
167 182
}
168 183

  
169 184
// legacy constructor, only for backwards compatiblity; first two args are unused
170
cSimpleModule::cSimpleModule(const char *, cModule *, unsigned stksize)
185
cSimpleModule::cSimpleModule(const char *, cModule *, unsigned stksize) :
186
		t_end(0.0)
171 187
{
172 188
    coroutine = NULL;
173 189
    setFlag(FL_USESACTIVITY, stksize!=0);
......
188 204
                               "or rewrite modules to use handleMessage() instead of activity()",
189 205
                               stksize,ev.getExtraStackForEnvir(),getFullPath().c_str());
190 206
    }
207

  
208
	//
209
	// find out if events with 0 durations should also be parallelized?
210
	//
211
	parZeroDur = ev.getConfig()->getAsBool(CFGID_ASYNCMODULE_PARZERODUR);
212

  
213
	//
214
	// init state flag to non-busy since no thread is active yet
215
	//
216
	AO_store(&busy, 0);
217

  
218
	//
219
	// needs to be initialized here for use during model initialization
220
	//
221
	scheduledMessageCount = 0;
222
    currentEventPriority = 0;
223

  
224
	//
225
	// initialize with the current time. This variable is already used when
226
	// scheduling events during the initialization phase of the simulation.
227
	// Hence, it needs to be initialized. However, we cannot assume 0 here since
228
	// the constructor is also called during dynamic module creation at any
229
	// point in time during the simulation.
230
	//
231
	now = simTime();
232

  
191 233
}
192 234

  
193
cSimpleModule::cSimpleModule(unsigned stksize)
235
cSimpleModule::cSimpleModule(unsigned stksize) :
236
		t_end(0.0)
194 237
{
195 238
    coroutine = NULL;
196 239
    setFlag(FL_USESACTIVITY, stksize!=0);
......
211 254
                               "or rewrite modules to use handleMessage() instead of activity()",
212 255
                               stksize,ev.getExtraStackForEnvir(),getFullPath().c_str());
213 256
    }
257

  
258
	//
259
	// find out if events with 0 durations should also be parallelized?
260
	//
261
	parZeroDur = ev.getConfig()->getAsBool(CFGID_ASYNCMODULE_PARZERODUR);
262

  
263
	//
264
	// init state flag to non-busy since no thread is active yet
265
	//
266
	AO_store(&busy, 0);
267

  
268
	//
269
	// needs to be initialized here for use during model initialization
270
	//
271
	scheduledMessageCount = 0;
272
    currentEventPriority = 0;
273

  
274
	//
275
	// initialize with the current time. This variable is already used when
276
	// scheduling events during the initialization phase of the simulation.
277
	// Hence, it needs to be initialized. However, we cannot assume 0 here since
278
	// the constructor is also called during dynamic module creation at any
279
	// point in time during the simulation.
280
	//
281
	now = simTime();
282

  
214 283
}
215 284

  
216 285
cSimpleModule::~cSimpleModule()
......
347 416

  
348 417
#define TRY(code, msgprefix) try {code;} catch(cRuntimeError& e) {e.prependMessage(msgprefix);throw;}
349 418

  
350
int cSimpleModule::sendDelayed(cMessage *msg, simtime_t delay, const char *gateName, int gateIndex)
351
{
352
    cGate *outgate;
353
    TRY(outgate = gate(gateName,gateIndex), "send()/sendDelayed()");
354
    return sendDelayed(msg, delay, outgate);
355
}
356

  
357
int cSimpleModule::sendDelayed(cMessage *msg, simtime_t delay, int gateId)
358
{
359
    cGate *outgate;
360
    TRY(outgate = gate(gateId), "send()/sendDelayed()");
361
    return sendDelayed(msg, delay, outgate);
362
}
363

  
364
int cSimpleModule::sendDelayed(cMessage *msg, simtime_t delay, cGate *outgate)
365
{
366
    // error checking:
367
    if (outgate==NULL)
368
       throw cRuntimeError("send()/sendDelayed(): gate pointer is NULL");
369
    if (outgate->getType()==cGate::INPUT)
370
       throw cRuntimeError("send()/sendDelayed(): cannot send via an input gate (`%s')", outgate->getFullName());
371
    if (!outgate->getNextGate())  // NOTE: without this error check, msg would become self-message
372
       throw cRuntimeError("send()/sendDelayed(): gate `%s' not connected", outgate->getFullName());
373
    if (msg==NULL)
374
        throw cRuntimeError("send()/sendDelayed(): message pointer is NULL");
375
    if (msg->getOwner()!=this)
376
    {
377
        if (this!=simulation.getContextModule())
378
            throw cRuntimeError("send()/sendDelayed() of module (%s)%s called in the context of "
379
                                "module (%s)%s: method called from the latter module "
380
                                "lacks Enter_Method() or Enter_Method_Silent()? "
381
                                "Also, if message to be sent is passed from that module, "
382
                                "you'll need to call take(msg) after Enter_Method() as well",
383
                                getClassName(), getFullPath().c_str(),
384
                                simulation.getContextModule()->getClassName(),
385
                                simulation.getContextModule()->getFullPath().c_str());
386
        else if (msg->getOwner()==&simulation.msgQueue && msg->isSelfMessage() && msg->getArrivalModuleId()==getId())
387
            throw cRuntimeError("send()/sendDelayed(): cannot send message (%s)%s, it is "
388
                                "currently scheduled as a self-message for this module",
389
                                msg->getClassName(), msg->getName());
390
        else if (msg->getOwner()==&simulation.msgQueue && msg->isSelfMessage())
391
            throw cRuntimeError("send()/sendDelayed(): cannot send message (%s)%s, it is "
392
                                "currently scheduled as a self-message for ANOTHER module",
393
                                msg->getClassName(), msg->getName());
394
        else if (msg->getOwner()==&simulation.msgQueue)
395
            throw cRuntimeError("send()/sendDelayed(): cannot send message (%s)%s, it is "
396
                                "currently in scheduled-events, being underway between two modules",
397
                                msg->getClassName(), msg->getName());
398
        else
399
            throw cRuntimeError("send()/sendDelayed(): cannot send message (%s)%s, "
400
                                "it is currently contained/owned by (%s)%s",
401
                                msg->getClassName(), msg->getName(), msg->getOwner()->getClassName(),
402
                                msg->getOwner()->getFullPath().c_str());
403
    }
404
    if (delay < 0)
405
        throw cRuntimeError("sendDelayed(): negative delay %s", SIMTIME_STR(delay));
406

  
407
    // set message parameters and send it
408
    simtime_t delayEndTime = simTime()+delay;
409
    msg->setSentFrom(this, outgate->getId(), delayEndTime);
410
    if (msg->isPacket())
411
        ((cPacket *)msg)->setDuration(0);
412

  
413
    EVCB.beginSend(msg);
414
    bool keepit = outgate->deliver(msg, delayEndTime);
415
    if (!keepit)
416
    {
417
        delete msg; //FIXME problem: tell tkenv somehow that msg has been deleted, otherwise animation will crash
418
    }
419
    else
420
    {
421
        EVCB.messageSent_OBSOLETE(msg); //FIXME obsolete
422
        EVCB.endSend(msg);
423
    }
424
    return 0;
425
}
426

  
427
int cSimpleModule::sendDirect(cMessage *msg, cModule *mod, const char *gateName, int gateIndex)
428
{
429
    return sendDirect(msg, SIMTIME_ZERO, SIMTIME_ZERO, mod, gateName, gateIndex);
430
}
431

  
432
int cSimpleModule::sendDirect(cMessage *msg, cModule *mod, int gateId)
433
{
434
    return sendDirect(msg, SIMTIME_ZERO, SIMTIME_ZERO, mod, gateId);
435
}
436

  
437
int cSimpleModule::sendDirect(cMessage *msg, cGate *togate)
438
{
439
    return sendDirect(msg, SIMTIME_ZERO, SIMTIME_ZERO, togate);
440
}
441

  
442
int cSimpleModule::sendDirect(cMessage *msg, simtime_t propdelay, simtime_t duration,
443
                              cModule *mod, const char *gateName, int gateIndex)
444
{
445
    if (!mod)
446
        throw cRuntimeError("sendDirect(): destination module pointer is NULL");
447
    cGate *togate;
448
    TRY(togate = mod->gate(gateName, gateIndex), "sendDirect()");
449
    return sendDirect(msg, propdelay, duration, togate);
450
}
451

  
452
int cSimpleModule::sendDirect(cMessage *msg, simtime_t propdelay, simtime_t duration, cModule *mod, int gateId)
453
{
454
    if (!mod)
455
        throw cRuntimeError("sendDirect(): destination module pointer is NULL");
456
    cGate *togate;
457
    TRY(togate = mod->gate(gateId), "sendDirect()");
458
    return sendDirect(msg, propdelay, duration, togate);
459
}
460

  
461

  
462
int cSimpleModule::sendDirect(cMessage *msg, simtime_t propdelay, simtime_t duration, cGate *togate)
463
{
464
    // Note: it is permitted to send to an output gate. It is especially useful
465
    // with several submodules sending to a single output gate of their parent module.
466
    if (togate==NULL)
467
        throw cRuntimeError("sendDirect(): destination gate pointer is NULL");
468
    if (togate->getPreviousGate())
469
        throw cRuntimeError("sendDirect(): module must have dedicated gate(s) for receiving via sendDirect()"
470
                            " (\"from\" side of dest. gate `%s' should NOT be connected)",togate->getFullPath().c_str());
471
    if (propdelay<0 || duration<0)
472
        throw cRuntimeError("sendDirect(): the propagation and duration parameters cannot be negative");
473
    if (msg==NULL)
474
        throw cRuntimeError("sendDirect(): message pointer is NULL");
475
    if (msg->getOwner()!=this)
476
    {
477
        // try to give a meaningful error message
478
        if (this!=simulation.getContextModule())
479
            throw cRuntimeError("sendDirect() of module (%s)%s called in the context of "
480
                                "module (%s)%s: method called from the latter module "
481
                                "lacks Enter_Method() or Enter_Method_Silent()? "
482
                                "Also, if message to be sent is passed from that module, "
483
                                "you'll need to call take(msg) after Enter_Method() as well",
484
                                getClassName(), getFullPath().c_str(),
485
                                simulation.getContextModule()->getClassName(),
486
                                simulation.getContextModule()->getFullPath().c_str());
487
        else if (msg->getOwner()==&simulation.msgQueue && msg->isSelfMessage() && msg->getArrivalModuleId()==getId())
488
            throw cRuntimeError("sendDirect(): cannot send message (%s)%s, it is "
489
                                "currently scheduled as a self-message for this module",
490
                                msg->getClassName(), msg->getName());
491
        else if (msg->getOwner()==&simulation.msgQueue && msg->isSelfMessage())
492
            throw cRuntimeError("sendDirect(): cannot send message (%s)%s, it is "
493
                                "currently scheduled as a self-message for ANOTHER module",
494
                                msg->getClassName(), msg->getName());
495
        else if (msg->getOwner()==&simulation.msgQueue)
496
            throw cRuntimeError("sendDirect(): cannot send message (%s)%s, it is "
497
                                "currently in scheduled-events, being underway between two modules",
498
                                msg->getClassName(), msg->getName());
499
        else
500
            throw cRuntimeError("sendDirect(): cannot send message (%s)%s, "
501
                                "it is currently contained/owned by (%s)%s",
502
                                msg->getClassName(), msg->getName(), msg->getOwner()->getClassName(),
503
                                msg->getOwner()->getFullPath().c_str());
504
    }
505

  
506
    // set message parameters and send it
507
    msg->setSentFrom(this, -1, simTime());
508

  
509
    EVCB.beginSend(msg);
510
    if (msg->isPacket())
511
        ((cPacket *)msg)->setDuration(duration);
512
    else if (duration!=SIMTIME_ZERO)
513
        throw cRuntimeError("sendDirect(): cannot send non-packet message (%s)%s when nonzero duration is specified",
514
                            msg->getClassName(), msg->getName());
515
    EVCB.messageSendDirect(msg, togate, propdelay, duration);
516
    bool keepit = togate->deliver(msg, simTime() + propdelay);
517
    if (!keepit)
518
    {
519
        delete msg; //FIXME problem: tell tkenv somehow that msg has been deleted, otherwise animation will crash
520
    }
521
    else
522
    {
523
        EVCB.messageSent_OBSOLETE(msg, togate); //FIXME obsolete
524
        EVCB.endSend(msg);
525
    }
526
    return 0;
527
}
528

  
529
int cSimpleModule::scheduleAt(simtime_t t, cMessage *msg)
530
{
531
    if (msg==NULL)
532
        throw cRuntimeError("scheduleAt(): message pointer is NULL");
533
    if (t<simTime())
534
        throw cRuntimeError(eBACKSCHED, msg->getClassName(), msg->getName(), SIMTIME_DBL(t));
535
    if (msg->getOwner()!=this)
536
    {
537
        if (this!=simulation.getContextModule())
538
            throw cRuntimeError("scheduleAt() of module (%s)%s called in the context of "
539
                                "module (%s)%s: method called from the latter module "
540
                                "lacks Enter_Method() or Enter_Method_Silent()?",
541
                                getClassName(), getFullPath().c_str(),
542
                                simulation.getContextModule()->getClassName(),
543
                                simulation.getContextModule()->getFullPath().c_str());
544
        else if (msg->getOwner()==&simulation.msgQueue && msg->isSelfMessage() && msg->getArrivalModuleId()==getId())
545
            throw cRuntimeError("scheduleAt(): message (%s)%s is currently scheduled, "
546
                                "use cancelEvent() before rescheduling",
547
                                msg->getClassName(), msg->getName());
548
        else if (msg->getOwner()==&simulation.msgQueue && msg->isSelfMessage())
549
            throw cRuntimeError("scheduleAt(): cannot schedule message (%s)%s, it is "
550
                                "currently scheduled as self-message for ANOTHER module",
551
                                msg->getClassName(), msg->getName());
552

  
553
         else if (msg->getOwner()==&simulation.msgQueue)
554
            throw cRuntimeError("scheduleAt(): cannot schedule message (%s)%s, it is "
555
                                "currently in scheduled-events, being underway between two modules",
556
                                msg->getClassName(), msg->getName());
557
        else
558
            throw cRuntimeError("scheduleAt(): cannot schedule message (%s)%s, "
559
                                "it is currently contained/owned by (%s)%s",
560
                                msg->getClassName(), msg->getName(), msg->getOwner()->getClassName(),
561
                                msg->getOwner()->getFullPath().c_str());
562
    }
563

  
564
    // set message parameters and schedule it
565
    msg->setSentFrom(this, -1, simTime());
566
    msg->setArrival(this, -1, t);
567
    EVCB.messageSent_OBSOLETE( msg ); //XXX obsolete but needed for Tkenv
568
    EVCB.messageScheduled(msg);
569
    simulation.insertMsg(msg);
570
    return 0;
571
}
572

  
573 419
cMessage *cSimpleModule::cancelEvent(cMessage *msg)
574 420
{
575 421
    // make sure we really have the message and it is scheduled
......
757 603
    return coroutine ? coroutine->getStackUsage() : 0;
758 604
}
759 605

  
606
void cSimpleModule::initLocalRNGs()
607
{
608
    //TODO
609
    unsigned nrNumGens;
610
    unsigned long * seeds;
611

  
612
    //
613
    // how many local random number generators do we need?
614
    // default is 1
615
    //
616
    nrNumGens = ev.getConfig()->parseLong(
617
            ev.getConfig()->getPerObjectConfigValue(getFullPath().c_str(),
618
                    "number-local-rngs"), "1", 1);
619

  
620
    //
621
    // read the seeds from ini file
622
    //
623
    const char * seedString = ev.getConfig()->getPerObjectConfigValue(
624
            getFullPath().c_str(), "local-rng-seed");
625

  
626
    //
627
    // setup seeds for each RNG
628
    //
629
    seeds = new unsigned long[nrNumGens];
630
    cStringTokenizer tokenizer(seedString);
631
    const char * token = NULL;
632
    for (unsigned i = 0; i < nrNumGens; i++)
633
    {
634
        if (tokenizer.hasMoreTokens())
635
        {
636
            token = tokenizer.nextToken();
637
            if (strcmp(token, "auto") == 0)
638
            {
639
                token = NULL;
640
            }
641
        }
642

  
643
        EnvirBase* e = dynamic_cast<EnvirBase*> (&ev);
644
        if (e != NULL)
645
        {
646
            if (token)
647
            {
648
                //if the seed is set in the ini for this module, use ini-settings
649
                //with fallback to autogeneration if parsing failes
650
                seeds[i] = ev.getConfig()->parseLong(token, "",
651
                        e->getSeedGenerator()->intRand());
652
            }
653
            else
654
            {
655
                //else use SeedGenerator for automatic seed generation.
656
                seeds[i] = e->getSeedGenerator()->intRand();
657
            }
658
            token = NULL;
659
        }
660
        else
661
        {
662
            throw cRuntimeError(
663
                    "cSimpleModule: Failed to initialize Number Generator, dynamic cast to EnvirBase failed.");
664
        }
665
    }
666

  
667
    //
668
    // generate the required number of RNGs with the corresponding seeds
669
    //
670
    setupSeeds(nrNumGens,seeds);
671
    delete[] seeds;
672

  
673
}
674

  
675
void cSimpleModule::setMessageMetaData(cMessage* msg)
676
{
677
    msg->setEventDuration(SimTime::simTimeUninitialized);
678
    msg->setSchedulingOrderId(scheduledMessageCount++);
679
    msg->setParentExecutionOrderId(executionOrderId);
680
    msg->setParentStartTime(now);
681
}
682

  
683
int cSimpleModule::scheduleAt(simtime_t t, cMessage *msg)
684
{
685
    setMessageMetaData(msg);
686

  
687
    //
688
    // check current state
689
    //
690
    if (executionState == asynchronous)
691
    {
692
        if (msg==NULL)
693
			throw cRuntimeError("scheduleAt(): message pointer is NULL");
694
        if (t < t_end)
695
        	throw cRuntimeError("scheduleAt(): event cannot be scheduled at "
696
        			"%s because this precedes the end of the processing duration "
697
        			"at %s of the scheduling event.",
698
        			t.str().c_str(), t_end.str().c_str());
699

  
700
        if (t == now && currentEventPriority < msg->getSchedulingPriority()) {
701
            throw cRuntimeError("scheduleAt(): priority of scheduled Event larger than scheduling event and equal starting times => scheduling in the past");
702
        }
703
        // insert this message in the FES. When the scheduler arrives at this
704
        // message it will trigger the processing of the associated task
705
        msg->setSentFrom(this, -1, t_end);
706
        msg->setArrival(this, -1, t);
707

  
708
        simulation.msgQueue.insert(msg);
709
        return 0;
710
    }
711
    else // synch execution
712
    {
713
		if (msg==NULL)
714
			throw cRuntimeError("scheduleAt(): message pointer is NULL");
715
		if (t<simTime())
716
			throw cRuntimeError(eBACKSCHED, msg->getClassName(), msg->getName(), SIMTIME_DBL(t));
717
		if (msg->getOwner()!=this)
718
		{
719
			if (this!=simulation.getContextModule())
720
				throw cRuntimeError("scheduleAt() of module (%s)%s called in the context of "
721
						"module (%s)%s: method called from the latter module "
722
						"lacks Enter_Method() or Enter_Method_Silent()?",
723
						getClassName(), getFullPath().c_str(),
724
						simulation.getContextModule()->getClassName(),
725
						simulation.getContextModule()->getFullPath().c_str());
726
			else if (msg->getOwner()==&simulation.msgQueue && msg->isSelfMessage() && msg->getArrivalModuleId()==getId())
727
				throw cRuntimeError("scheduleAt(): message (%s)%s is currently scheduled, "
728
						"use cancelEvent() before rescheduling",
729
						msg->getClassName(), msg->getName());
730
			else if (msg->getOwner()==&simulation.msgQueue && msg->isSelfMessage())
731
				throw cRuntimeError("scheduleAt(): cannot schedule message (%s)%s, it is "
732
						"currently scheduled as self-message for ANOTHER module",
733
						msg->getClassName(), msg->getName());
734

  
735
			else if (msg->getOwner()==&simulation.msgQueue)
736
				throw cRuntimeError("scheduleAt(): cannot schedule message (%s)%s, it is "
737
						"currently in scheduled-events, being underway between two modules",
738
						msg->getClassName(), msg->getName());
739
			else
740
				throw cRuntimeError("scheduleAt(): cannot schedule message (%s)%s, "
741
						"it is currently contained/owned by (%s)%s",
742
						msg->getClassName(), msg->getName(), msg->getOwner()->getClassName(),
743
						msg->getOwner()->getFullPath().c_str());
744
		}
745

  
746
		// set message parameters and schedule it
747
		msg->setSentFrom(this, -1, simTime());
748
		msg->setArrival(this, -1, t);
749
		EVCB.messageSent_OBSOLETE( msg ); //XXX obsolete but needed for Tkenv
750
		EVCB.messageScheduled(msg);
751
		simulation.insertMsg(msg);
752
		return 0;
753
    }
754
}
755

  
756

  
757
void cSimpleModule::callHandleAsyncMessage(cMessage* msg)
758
{
759
    //
760
    // set execution state
761
    //
762
    executionState = asynchronous;
763

  
764
    //
765
    // set the simtime for this event
766
    //
767
    cThreadPool::setSimTime(msg->getArrivalTime());
768
    // corresponds to setContextModule(mod);
769
    cThreadPool::setContext(this);
770
    cThreadPool::setDefaultOwner(this);
771

  
772
    //
773
    // update meta data
774
    //
775
    prepareHandleMessage(msg);
776

  
777
    //
778
    // call the actual method
779
    //
780
    handleMessage(msg);
781
}
782

  
783

  
784
void cSimpleModule::callHandleMessage(cMessage* msg)
785
{
786
    //
787
    // set execution state
788
    //
789
    executionState = synchronous;
790

  
791
    //
792
    // update meta data
793
    //
794
    prepareHandleMessage(msg);
795

  
796
    //
797
    // call the actual method
798
    //
799
    handleMessage(msg);
800
}
801

  
802

  
803
void cSimpleModule::prepareHandleMessage(cMessage* msg)
804
{
805
    //
806
    // set some internal state
807
    //
808
    t_end = msg->getArrivalTime() + msg->getEventDuration();
809
    now = msg->getArrivalTime();
810
    currentEventPriority = msg->getSchedulingPriority();
811

  
812
    //
813
    // take ownership of the message only after the test above
814
    //
815
    this->take(msg);
816

  
817
    //
818
    // reset message counter
819
    // message 0 is the barriermsg
820
    //
821
    scheduledMessageCount = 1;
822

  
823
    executionOrderId = msg->getExecutionOrderId();
824

  
825
}
826

  
827
int cSimpleModule::send(cMessage *msg, int gateid)
828
{
829
    return sendDelayed(msg, 0.0, gateid);
830
}
831

  
832

  
833
int cSimpleModule::send(cMessage *msg, const char *gatename, int sn)
834
{
835
    return sendDelayed(msg, 0.0, gatename, sn);
836
}
760 837

  
838

  
839
int cSimpleModule::send(cMessage *msg, cGate *outputgate)
840
{
841
    return sendDelayed(msg, 0.0, outputgate);
842
}
843

  
844

  
845
int cSimpleModule::sendDelayed(cMessage *msg, simtime_t delay, int gateid)
846
{
847
    cGate *outgate = gate(gateid);
848
    if (outgate==NULL)
849
        throw cRuntimeError("send()/sendDelayed(): module has no gate #%d", gateid);
850

  
851
    return sendDelayed(msg, delay, outgate);
852
}
853

  
854

  
855
int cSimpleModule::sendDelayed(cMessage *msg, simtime_t delay, const char *gatename, int sn)
856
{
857
    cGate *outgate = gate(gatename, sn);
858
    if (outgate==NULL)
859
       throw cRuntimeError(sn<0 ? "send()/sendDelayed(): module has no gate `%s'":
860
                               "send()/sendDelayed(): module has no gate `%s[%d]'",gatename,sn);
861

  
862
    return sendDelayed(msg, delay, outgate);
863
}
864

  
865

  
866
int cSimpleModule::sendDelayed(cMessage *msg, simtime_t delay, cGate *outputgate)
867
{
868
    setMessageMetaData(msg);
869

  
870
    //
871
    // check current state
872
    //
873
    if (executionState == asynchronous)
874
    {
875
        //
876
        // error checking, omit ownership checks if it breaks
877
        //
878
        if (outputgate==NULL)
879
            throw cRuntimeError("send()/sendDelayed(): gate pointer is NULL");
880
        if (outputgate->getType()=='I')
881
            throw cRuntimeError("send()/sendDelayed(): cannot send via an input gate (`%s')",outputgate->getName());
882
        if (!outputgate->getNextGate())  // NOTE: without this error check, msg would become self-message
883
            throw cRuntimeError("send()/sendDelayed(): gate `%s' not connected",outputgate->getFullName());
884
        if (msg==NULL)
885
            throw cRuntimeError("send()/sendDelayed(): message pointer is NULL");
886
        if (msg->getOwner()!=this)
887
        {
888
            if (this!=simulation.getContext())
889
                throw cRuntimeError("send()/sendDelayed() of module (%s)%s called in the context of "
890
                                        "module (%s)%s: method called from the latter module "
891
                                        "lacks Enter_Method() or Enter_Method_Silent()? "
892
                                        "Also, if message to be sent is passed from that module, "
893
                                        "you'll need to call take(msg) after Enter_Method() as well",
894
                                        getClassName(), getFullPath().c_str(),
895
                                        simulation.getContext()->getClassName(),
896
                                        simulation.getContext()->getFullPath().c_str());
897
            else if (msg->getOwner()==&simulation.msgQueue && msg->isSelfMessage() && msg->getArrivalModuleId()==getId())
898
                throw cRuntimeError("send()/sendDelayed(): cannot send message (%s)%s, it is "
899
                                        "currently scheduled as a self-message for this module",
900
                                        msg->getClassName(), msg->getName());
901
            else if (msg->getOwner()==&simulation.msgQueue && msg->isSelfMessage())
902
                throw cRuntimeError("send()/sendDelayed(): cannot send message (%s)%s, it is "
903
                                        "currently scheduled as a self-message for ANOTHER module",
904
                                        msg->getClassName(), msg->getName());
905
            else if (msg->getOwner()==&simulation.msgQueue)
906
                throw cRuntimeError("send()/sendDelayed(): cannot send message (%s)%s, it is "
907
                                        "currently in scheduled-events, being underway between two modules",
908
                                        msg->getClassName(), msg->getName());
909
            else
910
                throw cRuntimeError("send()/sendDelayed(): cannot send message (%s)%s, "
911
                                        "it is currently contained/owned by (%s)%s",
912
                                        msg->getClassName(), msg->getName(), msg->getOwner()->getClassName(),
913
                                        msg->getOwner()->getFullPath().c_str());
914
        }
915

  
916
        if (delay < 0.0)
917
            throw cRuntimeError("sendDelayed(): negative delay %s",delay.str().c_str());
918

  
919
        simtime_t arrivalTime = now + delay;
920
        if (arrivalTime < t_end) // TODO: Consider channel delay!
921
            throw cRuntimeError("sendDelayed(): send delay shorter than processing delay %s", delay.str().c_str());
922

  
923
        if (delay == 0 && currentEventPriority < msg->getSchedulingPriority()) {
924
            throw cRuntimeError("sendDelayed(): priority of scheduled Event larger than scheduling event and equal starting times => scheduling in the past");
925
        }
926
        //
927
        // set message parameters and send it
928
        //
929
        msg->setSentFrom(this, outputgate->getId(), arrivalTime);
930
        bool keepit = outputgate->deliver(msg, arrivalTime);
931
        if (!keepit)
932
            delete msg;
933

  
934
        return 0;
935
    }
936
    else // syncExecution
937
    {
938
		// error checking:
939
		if (outputgate==NULL)
940
			throw cRuntimeError("send()/sendDelayed(): gate pointer is NULL");
941
		if (outputgate->getType()==cGate::INPUT)
942
			throw cRuntimeError("send()/sendDelayed(): cannot send via an input gate (`%s')", outputgate->getFullName());
943
		if (!outputgate->getNextGate())  // NOTE: without this error check, msg would become self-message
944
			throw cRuntimeError("send()/sendDelayed(): gate `%s' not connected", outputgate->getFullName());
945
		if (msg==NULL)
946
			throw cRuntimeError("send()/sendDelayed(): message pointer is NULL");
947
		if (msg->getOwner()!=this)
948
		{
949
			if (this!=simulation.getContextModule())
950
				throw cRuntimeError("send()/sendDelayed() of module (%s)%s called in the context of "
951
						"module (%s)%s: method called from the latter module "
952
						"lacks Enter_Method() or Enter_Method_Silent()? "
953
						"Also, if message to be sent is passed from that module, "
954
						"you'll need to call take(msg) after Enter_Method() as well",
955
						getClassName(), getFullPath().c_str(),
956
						simulation.getContextModule()->getClassName(),
957
						simulation.getContextModule()->getFullPath().c_str());
958
			else if (msg->getOwner()==&simulation.msgQueue && msg->isSelfMessage() && msg->getArrivalModuleId()==getId())
959
				throw cRuntimeError("send()/sendDelayed(): cannot send message (%s)%s, it is "
960
						"currently scheduled as a self-message for this module",
961
						msg->getClassName(), msg->getName());
962
			else if (msg->getOwner()==&simulation.msgQueue && msg->isSelfMessage())
963
				throw cRuntimeError("send()/sendDelayed(): cannot send message (%s)%s, it is "
964
						"currently scheduled as a self-message for ANOTHER module",
965
						msg->getClassName(), msg->getName());
966
			else if (msg->getOwner()==&simulation.msgQueue)
967
				throw cRuntimeError("send()/sendDelayed(): cannot send message (%s)%s, it is "
968
						"currently in scheduled-events, being underway between two modules",
969
						msg->getClassName(), msg->getName());
970
			else
971
				throw cRuntimeError("send()/sendDelayed(): cannot send message (%s)%s, "
972
						"it is currently contained/owned by (%s)%s",
973
						msg->getClassName(), msg->getName(), msg->getOwner()->getClassName(),
974
						msg->getOwner()->getFullPath().c_str());
975
		}
976
		if (delay < 0)
977
			throw cRuntimeError("sendDelayed(): negative delay %s", SIMTIME_STR(delay));
978

  
979
		// set message parameters and send it
980
		simtime_t delayEndTime = simTime()+delay;
981
		msg->setSentFrom(this, outputgate->getId(), delayEndTime);
982
		if (msg->isPacket())
983
			((cPacket *)msg)->setDuration(0);
984

  
985
		EVCB.beginSend(msg);
986
		bool keepit = outputgate->deliver(msg, delayEndTime);
987
		if (!keepit)
988
		{
989
			delete msg; //FIXME problem: tell tkenv somehow that msg has been deleted, otherwise animation will crash
990
		}
991
		else
992
		{
993
			EVCB.messageSent_OBSOLETE(msg); //FIXME obsolete
994
			EVCB.endSend(msg);
995
		}
996
		return 0;
997
    }
998
}
999

  
1000

  
1001
int cSimpleModule::sendDirect(cMessage *msg, simtime_t delay, simtime_t duration, cModule *mod, int inputgateid)
1002
{
1003
    cGate *togate = mod->gate(inputgateid);
1004
    if (togate==NULL)
1005
        throw cRuntimeError("sendDirect(): module `%s' has no gate #%d",
1006
                                mod->getFullPath().c_str(), inputgateid);
1007

  
1008
    return sendDirect(msg, delay, duration, togate);
1009
}
1010

  
1011

  
1012
int cSimpleModule::sendDirect(cMessage *msg, simtime_t delay, simtime_t duration, cModule *mod, const char *inputgatename, int sn)
1013
{
1014
    if (!mod)
1015
        throw cRuntimeError("sendDirect(): module ptr is NULL");
1016
    cGate *togate = mod->gate(inputgatename,sn);
1017
    if (togate==NULL)
1018
        throw cRuntimeError(sn<0 ? "sendDirect(): module `%s' has no gate `%s'":
1019
                                "sendDirect(): module `%s' has no gate `%s[%d]'",
1020
                                mod->getFullPath().c_str(), inputgatename, sn);
1021
    return sendDirect(msg, delay, duration, togate);
1022
}
1023

  
1024

  
1025
int cSimpleModule::sendDirect(cMessage *msg, simtime_t delay, simtime_t duration, cGate *togate)
1026
{
1027
    setMessageMetaData(msg);
1028

  
1029
    //
1030
    // check current state
1031
    //
1032
    if (executionState == asynchronous)
1033
    {
1034
        //
1035
        // error checking
1036
        //
1037
        // Note: it is permitted to send to an output gate. It is especially useful
1038
        // with several submodules sending to a single output gate of their parent module.
1039
        if (togate==NULL)
1040
                throw cRuntimeError("sendDirect(): destination gate pointer is NULL");
1041
        if (togate->getPreviousGate())
1042
                throw cRuntimeError("sendDirect(): module must have dedicated gate(s) for receiving via sendDirect()"
1043
                                                                " (\"from\" side of dest. gate `%s' should NOT be connected)",togate->getFullPath().c_str());
1044
        if (msg==NULL)
1045
                throw cRuntimeError("sendDirect(): message pointer is NULL");
1046
        if (msg->getOwner()!=this)
1047
        {
1048
                if (this!=simulation.getContext())
1049
                        throw cRuntimeError("sendDirect() of module (%s)%s called in the context of "
1050
                                                                        "module (%s)%s: method called from the latter module "
1051
                                                                        "lacks Enter_Method() or Enter_Method_Silent()? "
1052
                                                                        "Also, if message to be sent is passed from that module, "
1053
                                                                        "you'll need to call take(msg) after Enter_Method() as well",
1054
                                                                        getClassName(), getFullPath().c_str(),
1055
                                                                        simulation.getContext()->getClassName(),
1056
                                                                        simulation.getContext()->getFullPath().c_str());
1057
                else if (msg->getOwner()==&simulation.msgQueue && msg->isSelfMessage() && msg->getArrivalModuleId()==getId())
1058
                        throw cRuntimeError("sendDirect(): cannot send message (%s)%s, it is "
1059
                                                                        "currently scheduled as a self-message for this module",
1060
                                                                        msg->getClassName(), msg->getName());
1061
                else if (msg->getOwner()==&simulation.msgQueue && msg->isSelfMessage())
1062
                        throw cRuntimeError("sendDirect(): cannot send message (%s)%s, it is "
1063
                                                                        "currently scheduled as a self-message for ANOTHER module",
1064
                                                                        msg->getClassName(), msg->getName());
1065
                else if (msg->getOwner()==&simulation.msgQueue)
1066
                        throw cRuntimeError("sendDirect(): cannot send message (%s)%s, it is "
1067
                                                                        "currently in scheduled-events, being underway between two modules",
1068
                                                                        msg->getClassName(), msg->getName());
1069
                else
1070
                        throw cRuntimeError("sendDirect(): cannot send message (%s)%s, "
1071
                                                                        "it is currently contained/owned by (%s)%s",
1072
                                                                        msg->getClassName(), msg->getName(), msg->getOwner()->getClassName(),
1073
                                                                        msg->getOwner()->getFullPath().c_str());
1074
        }
1075

  
1076
        simtime_t arrivalTime = now + delay;
1077
        if (arrivalTime < t_end) // TODO: Consider channel delay!
1078
            throw cRuntimeError("sendDirect(): send delay shorter than processing delay %s",delay.str().c_str());
1079

  
1080
        if (delay == 0 && currentEventPriority < msg->getSchedulingPriority()) {
1081
            throw cRuntimeError("sendDirect(): priority of scheduled Event larger than scheduling event and equal starting times => scheduling in the past");
1082
        }
1083

  
1084
        // set message parameters and send it
1085
        msg->setSentFrom(this, -1, now);
1086

  
1087
        bool keepit = togate->deliver(msg, arrivalTime);
1088
        if (!keepit)
1089
                delete msg;
1090
        return 0;
1091
    }
1092
    else  // sync execution
1093
    {
1094
    	return cSimpleModule::sendDirect(msg, delay, duration, togate);
1095
    }
1096
}

Also available in: Unified diff