@@ -96,90 +96,95 @@ EventsExecutor::spin_some(std::chrono::nanoseconds max_duration)
9696 return elapsed_time < max_duration;
9797 };
9898
99- // Execute events until timeout or no more work available
100- while (max_duration_not_elapsed ()) {
101- bool work_available = false ;
99+ // Get the number of events ready at this time point
100+ std::unique_lock<std::mutex> lock (push_mutex_);
101+ size_t available_events_at_tp = events_queue_->size ();
102+ lock.unlock ();
102103
103- // Check for ready timers
104- auto next_timer_timeout = timers_manager_->get_head_timeout ();
104+ size_t executed_events = 0 ;
105105
106- bool timer_ready = next_timer_timeout < 0ns;
106+ // Checks if all events that were ready when spin_some was called, were executed.
107+ auto executed_ready_events_at_tp = [executed_events, available_events_at_tp]() {
108+ return executed_events >= available_events_at_tp;
109+ };
107110
108- if (timer_ready) {
109- timers_manager_-> execute_head_timer ();
110- work_available = true ;
111- } else {
112- // Execute first event from queue if it exists
111+ // Execute events and timers ready when spin_some was called,
112+ // until timeout or no more work available.
113+ while ( rclcpp::ok (context_) && spinning. load () && max_duration_not_elapsed ()) {
114+ // Execute first event from queue if it exists
115+ if (! executed_ready_events_at_tp ()) {
113116 std::unique_lock<std::mutex> lock (push_mutex_);
114117
115118 bool has_event = !events_queue_->empty ();
116119
117120 if (has_event) {
118121 rmw_listener_event_t event = events_queue_->front ();
119122 events_queue_->pop ();
123+ // std::cout << "Execute event" << std::endl;
120124 this ->execute_event (event);
121- work_available = true ;
125+ executed_events++;
126+ continue ;
122127 }
123128 }
124129
125- // If there's no more work available, exit
126- if (!work_available ) {
127- break ;
130+ // Execute timer, if was ready at start
131+ if (timers_manager_-> execute_head_timer_if_ready_at_tp (start) ) {
132+ continue ;
128133 }
134+
135+ // If there's no more work available, exit
136+ break ;
129137 }
130138}
131139
132140void
133141EventsExecutor::spin_all (std::chrono::nanoseconds max_duration)
134142{
135- if (max_duration <= 0ns ) {
136- throw std::invalid_argument ( " max_duration must be positive " );
143+ if (spinning. exchange ( true ) ) {
144+ throw std::runtime_error ( " spin_all() called while already spinning " );
137145 }
138146
139- if (spinning. exchange ( true ) ) {
140- throw std::runtime_error ( " spin_some() called while already spinning " );
147+ if (max_duration < 0ns ) {
148+ throw std::invalid_argument ( " max_duration must be positive " );
141149 }
150+
142151 RCLCPP_SCOPE_EXIT (this ->spinning .store (false ););
143152
144- // When condition variable is notified, check this predicate to proceed
145- auto has_event_predicate = [this ]() {return !events_queue_->empty ();};
153+ // In this context a 0 input max_duration means no duration limit
154+ if (std::chrono::nanoseconds (0 ) == max_duration) {
155+ max_duration = timers_manager_->MAX_TIME ;
156+ }
146157
147158 auto start = std::chrono::steady_clock::now ();
159+
148160 auto max_duration_not_elapsed = [max_duration, start]() {
149161 auto elapsed_time = std::chrono::steady_clock::now () - start;
150162 return elapsed_time < max_duration;
151163 };
152164
153- // Select the smallest between input max duration and timer timeout
154- auto next_timer_timeout = timers_manager_->get_head_timeout ();
155- if (next_timer_timeout < max_duration) {
156- max_duration = next_timer_timeout;
157- }
158-
159- {
160- // Wait once until timeout or event
161- std::unique_lock<std::mutex> push_lock (push_mutex_);
162- events_queue_cv_.wait_for (push_lock, max_duration, has_event_predicate);
163- }
165+ // Execute timer and events until timeout or no more work available
166+ while (rclcpp::ok (context_) && spinning.load () && max_duration_not_elapsed ()) {
167+ // Execute first event from queue if it exists
168+ {
169+ std::unique_lock<std::mutex> lock (push_mutex_);
164170
165- auto timeout = timers_manager_-> get_head_timeout ();
171+ bool has_event = !events_queue_-> empty ();
166172
167- // Keep executing until no more work to do or timeout expired
168- while (rclcpp::ok (context_) && spinning.load () && max_duration_not_elapsed ()) {
169- std::unique_lock<std::mutex> push_lock (push_mutex_);
170- EventQueue execution_event_queue = events_queue_->get_all_events ();
171- push_lock.unlock ();
173+ if (has_event) {
174+ rmw_listener_event_t event = events_queue_->front ();
175+ events_queue_->pop ();
176+ this ->execute_event (event);
177+ continue ;
178+ }
179+ }
172180
173- // Exit if there is no more work to do
174- const bool ready_timer = timeout < 0ns;
175- const bool has_events = !execution_event_queue.empty ();
176- if (!ready_timer && !has_events) {
177- break ;
181+ // Execute timer, if was ready
182+ if (timers_manager_->execute_head_timer ()) {
183+ continue ;
178184 }
179185
180- // Execute all ready work
181- timeout = timers_manager_->execute_ready_timers ();
182- this ->consume_all_events (execution_event_queue);
186+ // If there's no more work available, exit
187+ break ;
183188 }
184189}
185190
0 commit comments