Statistics
| Branch: | Revision:

root / src / sim / cscheduler.cc @ e26d3d25

History | View | Annotate | Download (5.32 KB)

1
//=========================================================================
2
//  CSCHEDULER.CC - part of
3
//
4
//                  OMNeT++/OMNEST
5
//           Discrete System Simulation in C++
6
//
7
//  Author: Andras Varga, 2003
8
//
9
//=========================================================================
10

    
11
/*--------------------------------------------------------------*
12
  Copyright (C) 2003-2008 Andras Varga
13
  Copyright (C) 2006-2008 OpenSim Ltd.
14
  Monash University, Dept. of Electrical and Computer Systems Eng.
15
  Melbourne, Australia
16

17
  This file is distributed WITHOUT ANY WARRANTY. See the file
18
  `license' for details on this and other legal matters.
19
*--------------------------------------------------------------*/
20

    
21
#include "cscheduler.h"
22
#include "cmessage.h"
23
#include "csimulation.h"
24
#include "cmessageheap.h"
25
#include "globals.h"
26
#include "cenvir.h"
27
#include "cconfiguration.h"
28
#include "cconfigoption.h"
29
#include "platmisc.h" // usleep
30

    
31
USING_NAMESPACE
32

    
33
Register_GlobalConfigOption(CFGID_REALTIMESCHEDULER_SCALING, "realtimescheduler-scaling", CFG_DOUBLE, NULL, "When cRealTimeScheduler is selected as scheduler class: ratio of simulation time to real time. For example, scaling=2 will cause simulation time to progress twice as fast as runtime.");
34

    
35
cScheduler::cScheduler()
36
{
37
    sim = NULL;
38
}
39

    
40
cScheduler::~cScheduler()
41
{
42
}
43

    
44
void cScheduler::setSimulation(cSimulation *_sim)
45
{
46
    sim = _sim;
47
}
48

    
49
//-----
50

    
51
Register_Class(cSequentialScheduler);
52

    
53
cMessage *cSequentialScheduler::getNextEvent()
54
{
55
#ifdef NOBARRIER
56
    //
57
    // If we retrieve a valid msg from the queue, we return it:
58
    //
59
    cMessage *msg = sim->msgQueue.peekFirst();
60
    if (msg)
61
        return msg;
62

    
63
    //
64
    // if there is no event left and we don't use the threadpool, end the sim
65
    //
66
    if (!sim->threadPool)
67
        throw cTerminationException(eENDEDOK);
68

    
69
    //
70
    // If we did not get a valid msg from the queue, but there are still
71
    // barrier messages left, we wait:
72
    //
73
    while (sim->msgQueue.empty() && !sim->threadPool->barrierEmpty())
74
    {
75
        __asm__ ("pause");
76
    }
77
    msg = sim->msgQueue.peekFirst();
78

    
79
    //
80
    // If there is a msg now, we return it:
81
    //
82
    if (msg)
83
        return msg;
84

    
85
    //
86
    // If there is still no message in the queue, there are
87
    // also no barriers left (else we would have waited), and we quit:
88
    //
89
    else
90
        throw cTerminationException(eENDEDOK);
91

    
92
#else
93
    cMessage *msg = sim->msgQueue.peekFirst();
94
    if (!msg)
95
        throw cTerminationException(eENDEDOK);
96
    return msg;
97
#endif
98
}
99

    
100
//-----
101

    
102
Register_Class(cRealTimeScheduler);
103

    
104
void cRealTimeScheduler::startRun()
105
{
106
    factor = ev.getConfig()->getAsDouble(CFGID_REALTIMESCHEDULER_SCALING);
107
    if (factor!=0)
108
        factor = 1/factor;
109
    doScaling = (factor!=0);
110

    
111
    gettimeofday(&baseTime, NULL);
112
}
113

    
114
void cRealTimeScheduler::endRun()
115
{
116
}
117

    
118
void cRealTimeScheduler::executionResumed()
119
{
120
    gettimeofday(&baseTime, NULL);
121
    baseTime = timeval_substract(baseTime, SIMTIME_DBL(doScaling ? factor*sim->getSimTime() : sim->getSimTime()));
122
}
123

    
124
bool cRealTimeScheduler::waitUntil(const timeval& targetTime)
125
{
126
    // if there's more than 200ms to wait, wait in 100ms chunks
127
    // in order to keep UI responsiveness by invoking ev.idle()
128
    timeval curTime;
129
    gettimeofday(&curTime, NULL);
130
    while (targetTime.tv_sec-curTime.tv_sec >=2 ||
131
           timeval_diff_usec(targetTime, curTime) >= 200000)
132
    {
133
        usleep(100000); // 100ms
134
        if (ev.idle())
135
            return false;
136
        gettimeofday(&curTime, NULL);
137
    }
138

    
139
    // difference is now at most 100ms, do it at once
140
    long usec = timeval_diff_usec(targetTime, curTime);
141
    if (usec>0)
142
        usleep(usec);
143
    return true;
144
}
145

    
146
cMessage *cRealTimeScheduler::getNextEvent()
147
{
148
#ifdef NOBARRIER
149
    //
150
    // If we retrieve a valid msg from the queue, we return it:
151
    //
152
    cMessage *msg = sim->msgQueue.peekFirst();
153
    if (msg)
154
        return msg;
155

    
156
    //
157
    // if there is no event left and we don't use the threadpool, end the sim
158
    //
159
    if (!sim->threadPool)
160
        throw cTerminationException(eENDEDOK);
161

    
162
    //
163
    // If we did not get a valid msg from the queue, but there are still
164
    // barrier messages left, we wait:
165
    //
166
    while (sim->msgQueue.empty() && !sim->threadPool->barrierEmpty())
167
    {
168
        __asm__ ("pause");
169
    }
170
    msg = sim->msgQueue.peekFirst();
171

    
172
    //
173
    // If there is a msg now, we return it:
174
    //
175
    if (msg)
176
        return msg;
177

    
178
    //
179
    // If there is still no message in the queue, there are
180
    // also no barriers left (else we would have waited), and we quit:
181
    //
182
    else
183
        throw cTerminationException(eENDEDOK);
184

    
185
#else
186
    cMessage *msg = sim->msgQueue.peekFirst();
187
    if (!msg)
188
        throw cTerminationException(eENDEDOK);
189

    
190
    // calculate target time
191
    simtime_t eventSimtime = msg->getArrivalTime();
192
    timeval targetTime = timeval_add(baseTime, SIMTIME_DBL(doScaling ? factor*eventSimtime : eventSimtime));
193

    
194
    // if needed, wait until that time arrives
195
    timeval curTime;
196
    gettimeofday(&curTime, NULL);
197
    if (timeval_greater(targetTime, curTime))
198
    {
199
        if (!waitUntil(targetTime))
200
            return NULL; // user break
201
    }
202
    else
203
    {
204
        // we're behind -- customized versions of this class may alert
205
        // if we're too much behind, or modify basetime to accept the skew
206
    }
207

    
208
    // ok, return the message
209
    return msg;
210
#endif
211
}
212

    
213

    
214