LEFT | RIGHT |
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ | 1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ |
2 /* | 2 /* |
3 * Copyright (c) 2005,2006 INRIA | 3 * Copyright (c) 2005,2006 INRIA |
4 * Copyright (c) 2007 Emmanuelle Laprise | 4 * Copyright (c) 2007 Emmanuelle Laprise |
5 * | 5 * |
6 * This program is free software; you can redistribute it and/or modify | 6 * This program is free software; you can redistribute it and/or modify |
7 * it under the terms of the GNU General Public License version 2 as | 7 * it under the terms of the GNU General Public License version 2 as |
8 * published by the Free Software Foundation; | 8 * published by the Free Software Foundation; |
9 * | 9 * |
10 * This program is distributed in the hope that it will be useful, | 10 * This program is distributed in the hope that it will be useful, |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 * GNU General Public License for more details. | 13 * GNU General Public License for more details. |
14 * | 14 * |
15 * You should have received a copy of the GNU General Public License | 15 * You should have received a copy of the GNU General Public License |
16 * along with this program; if not, write to the Free Software | 16 * along with this program; if not, write to the Free Software |
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
18 * | 18 * |
19 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr> | 19 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr> |
20 * TimeStep support by Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca> | 20 * TimeStep support by Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca> |
21 */ | 21 */ |
22 #include "nstime.h" | 22 #include "nstime.h" |
23 #include "abort.h" | 23 #include "abort.h" |
24 #include "global-value.h" | 24 #include "global-value.h" |
25 #include "enum.h" | 25 #include "enum.h" |
26 #include "string.h" | 26 #include "string.h" |
27 #include "object.h" | 27 #include "object.h" |
28 #include "config.h" | 28 #include "config.h" |
| 29 #include "system-mutex.h" |
29 #include "log.h" | 30 #include "log.h" |
30 #include "simulator.h" | |
31 #include <cmath> | 31 #include <cmath> |
| 32 #include <iomanip> // showpos |
32 #include <sstream> | 33 #include <sstream> |
33 | 34 |
34 NS_LOG_COMPONENT_DEFINE ("Time"); | 35 NS_LOG_COMPONENT_DEFINE ("Time"); |
35 | 36 |
36 namespace ns3 { | 37 namespace ns3 { |
37 | 38 |
38 // The set of marked times | 39 // The set of marked times |
39 // static | 40 // static |
40 Time::MarkedTimes * Time::g_markingTimes; | 41 Time::MarkedTimes * Time::g_markingTimes = 0; |
41 | 42 |
42 // Function called to force static initialization·· | 43 /** |
| 44 * Get mutex for critical sections around modification of Time::g_markingTimes |
| 45 * |
| 46 * \relates Time |
| 47 */ |
| 48 SystemMutex & |
| 49 GetMarkingMutex () |
| 50 { |
| 51 static SystemMutex * g_markingMutex = new SystemMutex; |
| 52 return *g_markingMutex; |
| 53 } |
| 54 |
| 55 ·· |
| 56 ·· |
| 57 // Function called to force static initialization |
43 // static | 58 // static |
44 bool Time::StaticInit () | 59 bool Time::StaticInit () |
45 { | 60 { |
46 static bool firstTime = true; | 61 static bool firstTime = true; |
47 | 62 |
| 63 CriticalSection critical (GetMarkingMutex ()); |
| 64 ·· |
48 if (firstTime) | 65 if (firstTime) |
49 { | 66 { |
50 if (! g_markingTimes) | 67 if (! g_markingTimes) |
51 { | 68 { |
52 g_markingTimes = new Time::MarkedTimes; | 69 g_markingTimes = new Time::MarkedTimes; |
53 } | 70 } |
54 ······ | 71 else |
| 72 { |
| 73 NS_LOG_ERROR ("firstTime but g_markingTimes != 0"); |
| 74 } |
| 75 |
55 // Schedule the cleanup. | 76 // Schedule the cleanup. |
56 // We'd really like: | 77 // We'd really like: |
57 // NS_LOG_LOGIC ("scheduling ClearMarkedTimes()"); | 78 // NS_LOG_LOGIC ("scheduling ClearMarkedTimes()"); |
58 // Simulator::Schedule ( Seconds (0), & ClearMarkedTimes); | 79 // Simulator::Schedule ( Seconds (0), & ClearMarkedTimes); |
59 // [or even better: Simulator::AtStart ( & ClearMarkedTimes ); ] | 80 // [or even better: Simulator::AtStart ( & ClearMarkedTimes ); ] |
60 // But this triggers a static initialization order error, | 81 // But this triggers a static initialization order error, |
61 // since the Simulator static initialization may not have occurred. | 82 // since the Simulator static initialization may not have occurred. |
62 // Instead, we call ClearMarkedTimes directly from Simulator::Run () | 83 // Instead, we call ClearMarkedTimes directly from Simulator::Run () |
63 firstTime = false; | 84 firstTime = false; |
64 } | 85 } |
65 | 86 |
66 return firstTime; | 87 return firstTime; |
67 } | 88 } |
68 | 89 |
69 | 90 |
70 Time::Time (const std::string& s) | 91 Time::Time (const std::string& s) |
71 { | 92 { |
72 NS_LOG_FUNCTION (this << &s); | 93 NS_LOG_FUNCTION (this << &s); |
73 std::string::size_type n = s.find_first_not_of ("+-0123456789."); | 94 std::string::size_type n = s.find_first_not_of ("+-0123456789."); |
74 if (n != std::string::npos) | 95 if (n != std::string::npos) |
75 { // Found non-numeric | 96 { // Found non-numeric |
76 std::istringstream iss; | 97 std::istringstream iss; |
77 iss.str (s.substr (0, n)); | 98 iss.str (s.substr (0, n)); |
78 double r; | 99 double r; |
79 iss >> r; | 100 iss >> r; |
(...skipping 29 matching lines...) Expand all Loading... |
109 } | 130 } |
110 else | 131 else |
111 { | 132 { |
112 // they didn't provide units, assume seconds | 133 // they didn't provide units, assume seconds |
113 std::istringstream iss; | 134 std::istringstream iss; |
114 iss.str (s); | 135 iss.str (s); |
115 double v; | 136 double v; |
116 iss >> v; | 137 iss >> v; |
117 *this = Time::FromDouble (v, Time::S); | 138 *this = Time::FromDouble (v, Time::S); |
118 } | 139 } |
119 | 140 |
120 if (g_markingTimes) | 141 if (g_markingTimes) |
121 { | 142 { |
122 Mark (this); | 143 Mark (this); |
123 } | 144 } |
124 } | 145 } |
125 | 146 |
126 // static | 147 // static |
127 struct Time::Resolution | 148 struct Time::Resolution |
128 Time::SetDefaultNsResolution (void) | 149 Time::SetDefaultNsResolution (void) |
129 { | 150 { |
130 NS_LOG_FUNCTION_NOARGS (); | 151 NS_LOG_FUNCTION_NOARGS (); |
131 struct Resolution resolution; | 152 struct Resolution resolution; |
132 SetResolution (Time::NS, &resolution, false); | 153 SetResolution (Time::NS, &resolution, false); |
133 return resolution; | 154 return resolution; |
134 } | 155 } |
135 | 156 |
136 // static | 157 // static |
137 void | 158 void |
138 Time::SetResolution (enum Unit resolution) | 159 Time::SetResolution (enum Unit resolution) |
139 { | 160 { |
140 NS_LOG_FUNCTION (resolution); | 161 NS_LOG_FUNCTION (resolution); |
141 SetResolution (resolution, PeekResolution ()); | 162 SetResolution (resolution, PeekResolution ()); |
142 } | 163 } |
143 | 164 |
144 | 165 |
145 // static | 166 // static |
146 void | 167 void |
147 Time::SetResolution (enum Unit unit, struct Resolution *resolution, | 168 Time::SetResolution (enum Unit unit, struct Resolution *resolution, |
148 const bool convert /* = true */) | 169 const bool convert /* = true */) |
149 { | 170 { |
150 NS_LOG_FUNCTION (resolution); | 171 NS_LOG_FUNCTION (resolution); |
151 if (convert) | 172 if (convert) |
152 { // We have to convert old values | 173 { |
| 174 // We have to convert existing Times with the old |
| 175 // conversion values, so do it first |
153 ConvertTimes (unit); | 176 ConvertTimes (unit); |
154 } | 177 } |
155 | 178 |
156 int8_t power [LAST] = { 15, 12, 9, 6, 3, 0}; | 179 int8_t power [LAST] = { 15, 12, 9, 6, 3, 0}; |
157 for (int i = 0; i < Time::LAST; i++) | 180 for (int i = 0; i < Time::LAST; i++) |
158 { | 181 { |
159 int shift = power[i] - power[(int)unit]; | 182 int shift = power[i] - power[(int)unit]; |
160 uint64_t factor = (uint64_t) std::pow (10, std::fabs (shift)); | 183 int64_t factor = (int64_t) std::pow (10, std::fabs (shift)); |
161 struct Information *info = &resolution->info[i]; | 184 struct Information *info = &resolution->info[i]; |
162 info->factor = factor; | 185 info->factor = factor; |
163 if (shift == 0) | 186 if (shift == 0) |
164 { | 187 { |
165 info->timeFrom = int64x64_t (1); | 188 info->timeFrom = int64x64_t (1); |
166 info->timeTo = int64x64_t (1); | 189 info->timeTo = int64x64_t (1); |
167 info->toMul = true; | 190 info->toMul = true; |
168 info->fromMul = true; | 191 info->fromMul = true; |
169 } | 192 } |
170 else if (shift > 0) | 193 else if (shift > 0) |
(...skipping 13 matching lines...) Expand all Loading... |
184 } | 207 } |
185 } | 208 } |
186 resolution->unit = unit; | 209 resolution->unit = unit; |
187 } | 210 } |
188 | 211 |
189 | 212 |
190 // static | 213 // static |
191 void | 214 void |
192 Time::ClearMarkedTimes () | 215 Time::ClearMarkedTimes () |
193 { | 216 { |
| 217 /** |
| 218 * \internal |
| 219 * |
| 220 * We're called by Simulator::Run, which knows nothing about the mutex, |
| 221 * so we need a critical section here. |
| 222 * |
| 223 * It would seem natural to use this function at the end of |
| 224 * ConvertTimes, but that function already has the mutex. |
| 225 * Our SystemMutex throws a fatal error if we try to lock it more than |
| 226 * once in the same thread (at least in the unix implementation), |
| 227 * so calling this function from ConvertTimes is a bad idea. |
| 228 * |
| 229 * Instead, we copy this body into ConvertTimes. |
| 230 */ |
| 231 ·· |
| 232 CriticalSection critical (GetMarkingMutex ()); |
| 233 ·· |
194 NS_LOG_FUNCTION_NOARGS (); | 234 NS_LOG_FUNCTION_NOARGS (); |
195 if (g_markingTimes) | 235 if (g_markingTimes) |
196 { | 236 { |
197 NS_LOG_LOGIC ("clearing MarkedTimes"); | 237 NS_LOG_LOGIC ("clearing MarkedTimes"); |
198 delete g_markingTimes; | 238 delete g_markingTimes; |
199 g_markingTimes = 0; | 239 g_markingTimes = 0; |
200 } | 240 } |
201 } // Time::ClearMarkedTimes | 241 } // Time::ClearMarkedTimes |
202 | 242 |
203 | 243 |
204 // static | 244 // static |
205 void | 245 void |
206 Time::Mark (Time * const time) | 246 Time::Mark (Time * const time) |
207 { | 247 { |
| 248 CriticalSection critical (GetMarkingMutex ()); |
| 249 |
208 NS_LOG_FUNCTION (time); | 250 NS_LOG_FUNCTION (time); |
209 NS_ASSERT (time != 0); | 251 NS_ASSERT (time != 0); |
210 | 252 |
| 253 // Repeat the g_markingTimes test here inside the CriticalSection, |
| 254 // since earlier test was outside and might be stale. |
211 if (g_markingTimes) | 255 if (g_markingTimes) |
212 { | 256 { |
213 std::pair< MarkedTimes::iterator, bool> ret; | 257 std::pair< MarkedTimes::iterator, bool> ret; |
214 | 258 |
215 ret = g_markingTimes->insert ( time); | 259 ret = g_markingTimes->insert ( time); |
216 NS_LOG_LOGIC ("\t[" << g_markingTimes->size () << "] recording " << time); | 260 NS_LOG_LOGIC ("\t[" << g_markingTimes->size () << "] recording " << time); |
217 | 261 |
218 if (ret.second == false) | 262 if (ret.second == false) |
219 { | 263 { |
220 NS_LOG_WARN ("already recorded " << time << "!"); | 264 NS_LOG_WARN ("already recorded " << time << "!"); |
221 } | 265 } |
222 } | 266 } |
223 } // Time::Mark () | 267 } // Time::Mark () |
224 | 268 |
225 | 269 |
226 // static | 270 // static |
227 void | 271 void |
228 Time::Clear (Time * const time) | 272 Time::Clear (Time * const time) |
229 { | 273 { |
| 274 CriticalSection critical (GetMarkingMutex ()); |
| 275 |
230 NS_LOG_FUNCTION (time); | 276 NS_LOG_FUNCTION (time); |
231 NS_ASSERT (time != 0); | 277 NS_ASSERT (time != 0); |
232 | 278 |
233 if (g_markingTimes) | 279 if (g_markingTimes) |
234 { | 280 { |
235 NS_ASSERT_MSG (g_markingTimes->count (time) == 1, | 281 NS_ASSERT_MSG (g_markingTimes->count (time) == 1, |
236 "Time object " << time << | 282 "Time object " << time << |
237 " registered " << g_markingTimes->count (time) << | 283 " registered " << g_markingTimes->count (time) << |
238 " times (should be 1)." ); | 284 " times (should be 1)." ); |
239 | 285 |
240 MarkedTimes::size_type num = g_markingTimes->erase (time); | 286 MarkedTimes::size_type num = g_markingTimes->erase (time); |
241 if (num != 1) | 287 if (num != 1) |
242 { | 288 { |
243 NS_LOG_WARN ("unexpected result erasing " << time << "!"); | 289 NS_LOG_WARN ("unexpected result erasing " << time << "!"); |
244 NS_LOG_WARN ("got " << num << ", expected 1"); | 290 NS_LOG_WARN ("got " << num << ", expected 1"); |
245 } | 291 } |
246 else | 292 else |
247 { | 293 { |
248 NS_LOG_LOGIC ("\t[" << g_markingTimes->size () << "] removing " << ti
me); | 294 NS_LOG_LOGIC ("\t[" << g_markingTimes->size () << "] removing " << ti
me); |
249 } | 295 } |
250 } | 296 } |
251 } // Time::Clear () | 297 } // Time::Clear () |
252 | 298 |
253 | 299 |
254 // static | 300 // static |
255 void | 301 void |
256 Time::ConvertTimes (const enum Unit unit) | 302 Time::ConvertTimes (const enum Unit unit) |
257 { | 303 { |
| 304 CriticalSection critical (GetMarkingMutex ()); |
| 305 |
258 NS_LOG_FUNCTION_NOARGS(); | 306 NS_LOG_FUNCTION_NOARGS(); |
259 | 307 |
260 NS_ASSERT_MSG (g_markingTimes != 0, | 308 NS_ASSERT_MSG (g_markingTimes != 0, |
261 "No MarkedTimes registry. " | 309 "No MarkedTimes registry. " |
262 "Time::SetResolution () called more than once?"); | 310 "Time::SetResolution () called more than once?"); |
263 | 311 |
264 for ( MarkedTimes::iterator it = g_markingTimes->begin(); | 312 for ( MarkedTimes::iterator it = g_markingTimes->begin(); |
265 it != g_markingTimes->end(); | 313 it != g_markingTimes->end(); |
266 it++ ) | 314 it++ ) |
267 { | 315 { |
268 Time * const tp = *it; | 316 Time * const tp = *it; |
269 (*tp) = tp->ToInteger (unit); | 317 if ( ! ( (tp->m_data == std::numeric_limits<int64_t>::min ()) |
270 } | 318 || (tp->m_data == std::numeric_limits<int64_t>::max ()) |
271 ·· | 319 ) |
| 320 ) |
| 321 { |
| 322 tp->m_data = tp->ToInteger (unit); |
| 323 } |
| 324 } |
| 325 |
272 NS_LOG_LOGIC ("logged " << g_markingTimes->size () << " Time objects."); | 326 NS_LOG_LOGIC ("logged " << g_markingTimes->size () << " Time objects."); |
273 ·· | 327 |
274 ClearMarkedTimes (); | 328 // Body of ClearMarkedTimes |
| 329 // Assert above already guarantees g_markingTimes != 0 |
| 330 NS_LOG_LOGIC ("clearing MarkedTimes"); |
| 331 delete g_markingTimes; |
| 332 g_markingTimes = 0; |
| 333 ·· |
275 } // Time::ConvertTimes () | 334 } // Time::ConvertTimes () |
276 | 335 |
277 | 336 |
278 // static | 337 // static |
279 enum Time::Unit | 338 enum Time::Unit |
280 Time::GetResolution (void) | 339 Time::GetResolution (void) |
281 { | 340 { |
282 NS_LOG_FUNCTION_NOARGS (); | 341 // No function log b/c it interferes with operator<< |
283 return PeekResolution ()->unit; | 342 return PeekResolution ()->unit; |
284 } | 343 } |
285 | 344 |
286 | 345 |
287 std::ostream& | 346 std::ostream& |
288 operator<< (std::ostream& os, const Time & time) | 347 operator<< (std::ostream& os, const Time & time) |
289 { | 348 { |
290 std::string unit; | 349 std::string unit; |
291 switch (Time::GetResolution ()) | 350 Time::Unit res = Time::GetResolution (); |
| 351 switch (res) |
292 { | 352 { |
293 case Time::S: | 353 case Time::S: |
294 unit = "s"; | 354 unit = "s"; |
295 break; | 355 break; |
296 case Time::MS: | 356 case Time::MS: |
297 unit = "ms"; | 357 unit = "ms"; |
298 break; | 358 break; |
299 case Time::US: | 359 case Time::US: |
300 unit = "us"; | 360 unit = "us"; |
301 break; | 361 break; |
302 case Time::NS: | 362 case Time::NS: |
303 unit = "ns"; | 363 unit = "ns"; |
304 break; | 364 break; |
305 case Time::PS: | 365 case Time::PS: |
306 unit = "ps"; | 366 unit = "ps"; |
307 break; | 367 break; |
308 case Time::FS: | 368 case Time::FS: |
309 unit = "fs"; | 369 unit = "fs"; |
310 break; | 370 break; |
311 case Time::LAST: | 371 case Time::LAST: |
312 NS_ABORT_MSG ("can't be reached"); | 372 NS_ABORT_MSG ("can't be reached"); |
313 unit = "unreachable"; | 373 unit = "unreachable"; |
314 break; | 374 break; |
315 } | 375 } |
316 int64x64_t v = time; | 376 int64_t v = time.ToInteger (res); |
317 os << v << unit; | 377 ·· |
| 378 std::ios_base::fmtflags ff = os.flags (); |
| 379 { // See bug 1737: gcc libstc++ 4.2 bug |
| 380 if (v == 0) |
| 381 {· |
| 382 » os << '+'; |
| 383 } |
| 384 else |
| 385 { |
| 386 » os << std::showpos; |
| 387 } |
| 388 } |
| 389 os << v << ".0" << unit; |
| 390 os.flags (ff); // Restore stream flags |
318 return os; | 391 return os; |
319 } | 392 } |
320 std::istream& operator>> (std::istream& is, Time & time) | 393 std::istream& operator>> (std::istream& is, Time & time) |
321 { | 394 { |
322 std::string value; | 395 std::string value; |
323 is >> value; | 396 is >> value; |
324 time = Time (value); | 397 time = Time (value); |
325 return is; | 398 return is; |
326 } | 399 } |
327 | 400 |
328 ATTRIBUTE_VALUE_IMPLEMENT (Time); | 401 ATTRIBUTE_VALUE_IMPLEMENT (Time); |
329 ATTRIBUTE_CHECKER_IMPLEMENT (Time); | 402 |
| 403 Ptr<const AttributeChecker> |
| 404 MakeTimeChecker (const Time min, const Time max) |
| 405 { |
| 406 NS_LOG_FUNCTION (min << max); |
| 407 |
| 408 struct Checker : public AttributeChecker |
| 409 { |
| 410 Checker (const Time minValue, const Time maxValue) |
| 411 : m_minValue (minValue), |
| 412 m_maxValue (maxValue) {} |
| 413 virtual bool Check (const AttributeValue &value) const { |
| 414 NS_LOG_FUNCTION (&value); |
| 415 const TimeValue *v = dynamic_cast<const TimeValue *> (&value); |
| 416 if (v == 0) |
| 417 { |
| 418 return false; |
| 419 } |
| 420 return v->Get () >= m_minValue && v->Get () <= m_maxValue; |
| 421 } |
| 422 virtual std::string GetValueTypeName (void) const { |
| 423 NS_LOG_FUNCTION_NOARGS (); |
| 424 return "ns3::TimeValue"; |
| 425 } |
| 426 virtual bool HasUnderlyingTypeInformation (void) const { |
| 427 NS_LOG_FUNCTION_NOARGS (); |
| 428 return true; |
| 429 } |
| 430 virtual std::string GetUnderlyingTypeInformation (void) const { |
| 431 NS_LOG_FUNCTION_NOARGS (); |
| 432 std::ostringstream oss; |
| 433 oss << "Time" << " " << m_minValue << ":" << m_maxValue; |
| 434 return oss.str (); |
| 435 } |
| 436 virtual Ptr<AttributeValue> Create (void) const { |
| 437 NS_LOG_FUNCTION_NOARGS (); |
| 438 return ns3::Create<TimeValue> (); |
| 439 } |
| 440 virtual bool Copy (const AttributeValue &source, AttributeValue &destination
) const { |
| 441 NS_LOG_FUNCTION (&source << &destination); |
| 442 const TimeValue *src = dynamic_cast<const TimeValue *> (&source); |
| 443 TimeValue *dst = dynamic_cast<TimeValue *> (&destination); |
| 444 if (src == 0 || dst == 0) |
| 445 { |
| 446 return false; |
| 447 } |
| 448 *dst = *src; |
| 449 return true; |
| 450 } |
| 451 Time m_minValue; |
| 452 Time m_maxValue; |
| 453 } *checker = new Checker (min, max); |
| 454 return Ptr<const AttributeChecker> (checker, false); |
| 455 } |
| 456 |
330 | 457 |
331 } // namespace ns3 | 458 } // namespace ns3 |
332 | 459 |
LEFT | RIGHT |