dvcompute/simulation/internal/
event_queue.rs

1// Copyright (c) 2020-2022  David Sorokin <davsor@mail.ru>, based in Yoshkar-Ola, Russia
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at https://mozilla.org/MPL/2.0/.
6
7#[cfg(any(feature="seq_mode", feature="wasm_mode"))]
8use std::cell::UnsafeCell;
9
10#[cfg(any(feature="seq_mode", feature="wasm_mode"))]
11use std::ops::Deref;
12
13#[cfg(feature="cons_mode")]
14use libc::*;
15
16use crate::simulation::error::*;
17use crate::simulation::specs::SpecsRepr;
18use crate::simulation::point::Point;
19use crate::simulation::event::*;
20
21#[cfg(any(feature="seq_mode", feature="wasm_mode"))]
22use crate::simulation;
23
24#[cfg(any(feature="seq_mode", feature="wasm_mode"))]
25use crate::simulation::utils::priority_queue::PriorityQueue;
26
27/// The event queue for the optimistic Time Warp method.
28#[cfg(any(feature="seq_mode", feature="wasm_mode"))]
29pub struct EventQueue {
30
31    /// The current event time.
32    time: UnsafeCell<f64>,
33
34    /// The priority queue.
35    pq: UnsafeCell<PriorityQueue<(f64, isize), EventRepr>>
36}
37
38#[cfg(any(feature="seq_mode", feature="wasm_mode"))]
39impl EventQueue {
40
41    /// Create a new event queue for the sequential simulation.
42    pub fn new(specs: &SpecsRepr) -> EventQueue {
43        EventQueue {
44            time: UnsafeCell::new(specs.start_time),
45            pq: UnsafeCell::new(PriorityQueue::new())
46        }
47    }
48
49    /// Enqueue the event by the specified activation time and handler generator.
50    #[inline]
51    pub fn enqueue_event(&self, event_time: f64, priority: isize, comp: EventRepr, p: &Point) {
52        assert!(event_time >= p.time, "The event time cannot be less than the current modeling time");
53        let pq = self.pq.get();
54        unsafe {
55            (*pq).enqueue((event_time, - priority), comp);
56        }
57    }
58
59    /// Enqueue the IO-based event by the specified activation time and handler generator.
60    #[inline]
61    pub fn enqueue_io_event(&self, event_time: f64, priority: isize, comp: EventRepr, p: &Point) {
62        self.enqueue_event(event_time, priority, comp, p)
63    }
64
65    /// Run the pending events.
66    pub fn run_events(&self, including_current: bool, p: &Point) -> simulation::Result<()> {
67        loop {
68            let ((t2, pri2), c2) = unsafe {
69                let pq = self.pq.get();
70                let t0 = self.time.get();
71                match (*pq).minimal_key() {
72                    Some((t2, _)) if *t2 < *t0 => {
73                        panic!("The time value is too small. The event queue is desynchronized");
74                    }
75                    Some((t2, _)) if *t2 < p.time || (including_current && *t2 == p.time) => {
76                        *t0 = *t2;
77                    }
78                    _ => {
79                        break;
80                    }
81                }
82                (*pq).dequeue()
83            };
84            let run = p.run;
85            let specs = &run.specs;
86            let t0 = specs.start_time;
87            let dt = specs.dt;
88            let n2 = ((t2 - t0) / dt).floor() as usize;
89            let p2 = Point {
90                run: p.run,
91                time: t2,
92                priority: -pri2,
93                minimal_priority: p.minimal_priority,
94                iteration: n2,
95                phase: -1
96            };
97            match c2.call_event(&p2) {
98                Result::Ok(()) => (),
99                Result::Err(Error::Cancel) => (),
100                Result::Err(Error::Other(x)) => {
101                    match x.deref() {
102                        &OtherError::Retry(_) => {
103                            return Result::Err(Error::Other(x.clone()))
104                        },
105                        &OtherError::Panic(_) => {
106                            return Result::Err(Error::Other(x.clone()))
107                        },
108                        &OtherError::IO(_) => {
109                            return Result::Err(Error::Other(x.clone()))
110                        }
111                    }
112                }
113            }
114        }
115        Result::Ok(())
116    }
117}
118
119/// Represents the event queue.
120#[cfg(feature="cons_mode")]
121pub type EventQueue = c_void;
122
123#[cfg(all(feature="cons_mode", not(feature="cons_core_mode")))]
124#[cfg_attr(windows, link(name = "dvcompute_core_cons.dll"))]
125#[cfg_attr(not(windows), link(name = "dvcompute_core_cons"))]
126extern {
127
128    /// Create a new event queue.
129    #[doc(hidden)]
130    pub fn create_extern_event_queue(specs: *const SpecsRepr) -> *mut EventQueue;
131
132    /// Delete the event queue.
133    #[doc(hidden)]
134    pub fn delete_extern_event_queue(queue: *mut EventQueue);
135
136    /// Enqueue a new event.
137    #[doc(hidden)]
138    pub fn enqueue_extern_event(queue: *mut EventQueue, event_time: f64, priority: isize, comp: EventRepr, p: *const Point);
139
140    /// Enqueue a new IO event.
141    #[doc(hidden)]
142    pub fn enqueue_extern_io_event(queue: *mut EventQueue, event_time: f64, priority: isize, comp: EventRepr, p: *const Point);
143
144    /// Run the events.
145    #[doc(hidden)]
146    pub fn run_extern_events(including_current: isize, p: *const Point) -> *mut ErrorRepr;
147}
148
149#[cfg(all(feature="cons_mode", feature="cons_core_mode"))]
150extern {
151
152    /// Create a new event queue.
153    #[doc(hidden)]
154    pub fn create_extern_event_queue(specs: *const SpecsRepr) -> *mut EventQueue;
155
156    /// Delete the event queue.
157    #[doc(hidden)]
158    pub fn delete_extern_event_queue(queue: *mut EventQueue);
159
160    /// Enqueue a new event.
161    #[doc(hidden)]
162    pub fn enqueue_extern_event(queue: *mut EventQueue, event_time: f64, priority: isize, comp: EventRepr, p: *const Point);
163
164    /// Enqueue a new IO event.
165    #[doc(hidden)]
166    pub fn enqueue_extern_io_event(queue: *mut EventQueue, event_time: f64, priority: isize, comp: EventRepr, p: *const Point);
167
168    /// Run the events.
169    #[doc(hidden)]
170    pub fn run_extern_events(including_current: isize, p: *const Point) -> *mut ErrorRepr;
171}