@@ -60,17 +60,14 @@ EventsExecutor::spin()
6060 // When condition variable is notified, check this predicate to proceed
6161 auto has_event_predicate = [this ]() {return !events_queue_->empty ();};
6262
63- // Local event queue to allow entities to push events while we execute them
64- EventQueue execution_event_queue;
65-
6663 timers_manager_->start ();
6764
6865 while (rclcpp::ok (context_) && spinning.load ()) {
6966 std::unique_lock<std::mutex> push_lock (push_mutex_);
7067 // We wait here until something has been pushed to the event queue
7168 events_queue_cv_.wait (push_lock, has_event_predicate);
7269 // Local event queue to allow entities to push events while we execute them
73- execution_event_queue = events_queue_->get_all_events ();
70+ EventQueue execution_event_queue = events_queue_->get_all_events ();
7471 // Unlock the mutex
7572 push_lock.unlock ();
7673 // Consume all available events, this queue will be empty at the end of the function
@@ -82,43 +79,12 @@ EventsExecutor::spin()
8279void
8380EventsExecutor::spin_some (std::chrono::nanoseconds max_duration)
8481{
85- if (spinning.exchange (true )) {
86- throw std::runtime_error (" spin_some() called while already spinning" );
87- }
88- RCLCPP_SCOPE_EXIT (this ->spinning .store (false ););
89-
9082 // In this context a 0 input max_duration means no duration limit
9183 if (std::chrono::nanoseconds (0 ) == max_duration) {
9284 max_duration = timers_manager_->MAX_TIME ;
9385 }
9486
95- // This function will wait until the first of the following events occur:
96- // - The input max_duration is elapsed
97- // - A timer triggers
98- // - An executor event is received and processed
99-
100- // When condition variable is notified, check this predicate to proceed
101- auto has_event_predicate = [this ]() {return !events_queue_->empty ();};
102-
103-
104- // Select the smallest between input max_duration and timer timeout
105- auto next_timer_timeout = timers_manager_->get_head_timeout ();
106- if (next_timer_timeout < max_duration) {
107- max_duration = next_timer_timeout;
108- }
109-
110- std::unique_lock<std::mutex> push_lock (push_mutex_);
111- // Wait until timeout or event
112- events_queue_cv_.wait_for (push_lock, max_duration, has_event_predicate);
113- // Local event queue to allow entities to push events while we execute them
114- EventQueue execution_event_queue = events_queue_->get_all_events ();
115- // We don't need the lock anymore
116- push_lock.unlock ();
117-
118- // Execute all ready timers
119- timers_manager_->execute_ready_timers ();
120- // Consume all available events, this queue will be empty at the end of the function
121- this ->consume_all_events (execution_event_queue);
87+ return this ->spin_some_impl (max_duration, false );
12288}
12389
12490void
@@ -127,54 +93,66 @@ EventsExecutor::spin_all(std::chrono::nanoseconds max_duration)
12793 if (max_duration <= 0ns) {
12894 throw std::invalid_argument (" max_duration must be positive" );
12995 }
96+ return this ->spin_some_impl (max_duration, true );
97+ }
13098
99+ void
100+ EventsExecutor::spin_some_impl (std::chrono::nanoseconds max_duration, bool exhaustive)
101+ {
131102 if (spinning.exchange (true )) {
132103 throw std::runtime_error (" spin_some() called while already spinning" );
133104 }
134- RCLCPP_SCOPE_EXIT (this ->spinning .store (false ););
135105
136- // When condition variable is notified, check this predicate to proceed
137- auto has_event_predicate = [this ]() {return !events_queue_->empty ();};
138-
139- // Local event queue to allow entities to push events while we execute them
140- EventQueue execution_event_queue;
106+ RCLCPP_SCOPE_EXIT (this ->spinning .store (false ););
141107
142108 auto start = std::chrono::steady_clock::now ();
109+
143110 auto max_duration_not_elapsed = [max_duration, start]() {
144111 auto elapsed_time = std::chrono::steady_clock::now () - start;
145112 return elapsed_time < max_duration;
146113 };
147114
148- // Select the smallest between input max duration and timer timeout
149- auto next_timer_timeout = timers_manager_->get_head_timeout ();
150- if (next_timer_timeout < max_duration) {
151- max_duration = next_timer_timeout;
152- }
115+ size_t ready_events_at_start = 0 ;
116+ size_t executed_events = 0 ;
153117
154- {
155- // Wait once until timeout or event
156- std::unique_lock<std::mutex> push_lock (push_mutex_);
157- events_queue_cv_.wait_for (push_lock, max_duration, has_event_predicate);
118+ if (!exhaustive) {
119+ // Get the number of events ready at start
120+ std::unique_lock<std::mutex> lock (push_mutex_);
121+ ready_events_at_start = events_queue_->size ();
122+ lock.unlock ();
158123 }
159124
160- auto timeout = timers_manager_->get_head_timeout ();
161-
162- // Keep executing until no more work to do or timeout expired
163125 while (rclcpp::ok (context_) && spinning.load () && max_duration_not_elapsed ()) {
164- std::unique_lock<std::mutex> push_lock (push_mutex_);
165- execution_event_queue = events_queue_->get_all_events ();
166- push_lock.unlock ();
126+ // Execute first ready event from queue if exists
127+ if (exhaustive || (executed_events < ready_events_at_start)) {
128+ std::unique_lock<std::mutex> lock (push_mutex_);
129+ bool has_event = !events_queue_->empty ();
130+
131+ if (has_event) {
132+ rmw_listener_event_t event = events_queue_->front ();
133+ events_queue_->pop ();
134+ this ->execute_event (event);
135+ executed_events++;
136+ continue ;
137+ }
138+ }
167139
168- // Exit if there is no more work to do
169- const bool ready_timer = timeout < 0ns;
170- const bool has_events = !execution_event_queue.empty ();
171- if (!ready_timer && !has_events) {
172- break ;
140+ bool timer_executed;
141+
142+ if (exhaustive) {
143+ // Execute timer if is ready
144+ timer_executed = timers_manager_->execute_head_timer ();
145+ } else {
146+ // Execute timer if was ready at start
147+ timer_executed = timers_manager_->execute_head_timer (start);
173148 }
174149
175- // Execute all ready work
176- timeout = timers_manager_->execute_ready_timers ();
177- this ->consume_all_events (execution_event_queue);
150+ if (timer_executed) {
151+ continue ;
152+ }
153+
154+ // If there's no more work available, exit
155+ break ;
178156 }
179157}
180158
0 commit comments