• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "hci/acl_manager/round_robin_scheduler.h"
18 
19 #include <bluetooth/log.h>
20 
21 #include <memory>
22 #include <utility>
23 
24 #include "hci/acl_manager/acl_fragmenter.h"
25 namespace bluetooth {
26 namespace hci {
27 namespace acl_manager {
28 
RoundRobinScheduler(os::Handler * handler,Controller * controller,common::BidiQueueEnd<AclBuilder,AclView> * hci_queue_end)29 RoundRobinScheduler::RoundRobinScheduler(os::Handler* handler, Controller* controller,
30                                          common::BidiQueueEnd<AclBuilder, AclView>* hci_queue_end)
31     : handler_(handler), controller_(controller), hci_queue_end_(hci_queue_end) {
32   max_acl_packet_credits_ = controller_->GetNumAclPacketBuffers();
33   acl_packet_credits_ = max_acl_packet_credits_;
34   hci_mtu_ = controller_->GetAclPacketLength();
35   LeBufferSize le_buffer_size = controller_->GetLeBufferSize();
36   le_max_acl_packet_credits_ = le_buffer_size.total_num_le_packets_;
37   le_acl_packet_credits_ = le_max_acl_packet_credits_;
38   le_hci_mtu_ = le_buffer_size.le_data_packet_length_;
39   controller_->RegisterCompletedAclPacketsCallback(
40           handler->BindOn(this, &RoundRobinScheduler::incoming_acl_credits));
41 }
42 
~RoundRobinScheduler()43 RoundRobinScheduler::~RoundRobinScheduler() {
44   unregister_all_connections();
45   controller_->UnregisterCompletedAclPacketsCallback();
46 }
47 
Register(ConnectionType connection_type,uint16_t handle,std::shared_ptr<acl_manager::AclConnection::Queue> queue)48 void RoundRobinScheduler::Register(ConnectionType connection_type, uint16_t handle,
49                                    std::shared_ptr<acl_manager::AclConnection::Queue> queue) {
50   log::assert_that(acl_queue_handlers_.count(handle) == 0,
51                    "assert failed: acl_queue_handlers_.count(handle) == 0");
52   acl_queue_handler acl_queue_handler = {connection_type, std::move(queue), false, 0};
53   acl_queue_handlers_.insert(
54           std::pair<uint16_t, RoundRobinScheduler::acl_queue_handler>(handle, acl_queue_handler));
55   log::info("registering acl_queue handle={}, acl_credits={}, le_credits={}", handle,
56             acl_packet_credits_, le_acl_packet_credits_);
57   if (fragments_to_send_.size() == 0) {
58     log::info("start round robin");
59     start_round_robin();
60   }
61 }
62 
Unregister(uint16_t handle)63 void RoundRobinScheduler::Unregister(uint16_t handle) {
64   log::assert_that(acl_queue_handlers_.count(handle) == 1,
65                    "assert failed: acl_queue_handlers_.count(handle) == 1");
66 
67   // Drop the pending fragments and recalculate number_of_sent_packets_
68   drop_packet_fragments(handle);
69 
70   auto& acl_queue_handler = acl_queue_handlers_.find(handle)->second;
71   log::info("unregistering acl_queue handle={}, sent_packets={}", handle,
72             acl_queue_handler.number_of_sent_packets_);
73 
74   bool credits_reclaimed_from_zero = acl_queue_handler.number_of_sent_packets_ > 0;
75 
76   // Reclaim outstanding packets
77   if (acl_queue_handler.connection_type_ == ConnectionType::CLASSIC) {
78     credits_reclaimed_from_zero &= (acl_packet_credits_ == 0);
79     acl_packet_credits_ += acl_queue_handler.number_of_sent_packets_;
80   } else {
81     credits_reclaimed_from_zero &= (le_acl_packet_credits_ == 0);
82     le_acl_packet_credits_ += acl_queue_handler.number_of_sent_packets_;
83   }
84   acl_queue_handler.number_of_sent_packets_ = 0;
85 
86   if (acl_queue_handler.dequeue_is_registered_) {
87     acl_queue_handler.dequeue_is_registered_ = false;
88     acl_queue_handler.queue_->GetDownEnd()->UnregisterDequeue();
89   }
90   acl_queue_handlers_.erase(handle);
91   starting_point_ = acl_queue_handlers_.begin();
92 
93   // Restart sending packets if we got acl credits
94   if (credits_reclaimed_from_zero) {
95     start_round_robin();
96   }
97 }
98 
SetLinkPriority(uint16_t handle,bool high_priority)99 void RoundRobinScheduler::SetLinkPriority(uint16_t handle, bool high_priority) {
100   auto acl_queue_handler = acl_queue_handlers_.find(handle);
101   if (acl_queue_handler == acl_queue_handlers_.end()) {
102     log::warn("handle {} is invalid", handle);
103     return;
104   }
105   acl_queue_handler->second.high_priority_ = high_priority;
106 }
107 
GetCredits()108 uint16_t RoundRobinScheduler::GetCredits() { return acl_packet_credits_; }
109 
GetLeCredits()110 uint16_t RoundRobinScheduler::GetLeCredits() { return le_acl_packet_credits_; }
111 
start_round_robin()112 void RoundRobinScheduler::start_round_robin() {
113   if (acl_packet_credits_ == 0 && le_acl_packet_credits_ == 0) {
114     log::warn("Both buffers are full");
115     return;
116   }
117   if (!fragments_to_send_.empty()) {
118     auto connection_type = fragments_to_send_.front().connection_type_;
119     bool classic_buffer_full =
120             acl_packet_credits_ == 0 && connection_type == ConnectionType::CLASSIC;
121     bool le_buffer_full = le_acl_packet_credits_ == 0 && connection_type == ConnectionType::LE;
122     if (classic_buffer_full || le_buffer_full) {
123       log::warn("Buffer of connection_type {} is full", connection_type);
124       return;
125     }
126     send_next_fragment();
127     return;
128   }
129   if (acl_queue_handlers_.empty()) {
130     log::info("No any acl connection");
131     return;
132   }
133 
134   if (acl_queue_handlers_.size() == 1 || starting_point_ == acl_queue_handlers_.end()) {
135     starting_point_ = acl_queue_handlers_.begin();
136   }
137   size_t count = acl_queue_handlers_.size();
138 
139   for (auto acl_queue_handler = starting_point_; count > 0; count--) {
140     // Prevent registration when credits is zero
141     bool classic_buffer_full =
142             acl_packet_credits_ == 0 &&
143             acl_queue_handler->second.connection_type_ == ConnectionType::CLASSIC;
144     bool le_buffer_full = le_acl_packet_credits_ == 0 &&
145                           acl_queue_handler->second.connection_type_ == ConnectionType::LE;
146     if (!acl_queue_handler->second.dequeue_is_registered_ && !classic_buffer_full &&
147         !le_buffer_full) {
148       acl_queue_handler->second.dequeue_is_registered_ = true;
149       uint16_t acl_handle = acl_queue_handler->first;
150       acl_queue_handler->second.queue_->GetDownEnd()->RegisterDequeue(
151               handler_, common::Bind(&RoundRobinScheduler::buffer_packet, common::Unretained(this),
152                                      acl_handle));
153     }
154     acl_queue_handler = std::next(acl_queue_handler);
155     if (acl_queue_handler == acl_queue_handlers_.end()) {
156       acl_queue_handler = acl_queue_handlers_.begin();
157     }
158   }
159 
160   starting_point_ = std::next(starting_point_);
161 }
162 
buffer_packet(uint16_t acl_handle)163 void RoundRobinScheduler::buffer_packet(uint16_t acl_handle) {
164   BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
165   auto acl_queue_handler = acl_queue_handlers_.find(acl_handle);
166   if (acl_queue_handler == acl_queue_handlers_.end()) {
167     log::error("Ignore since ACL connection vanished with handle: 0x{:X}", acl_handle);
168     return;
169   }
170 
171   // Wrap packet and enqueue it
172   uint16_t handle = acl_queue_handler->first;
173   auto packet = acl_queue_handler->second.queue_->GetDownEnd()->TryDequeue();
174   log::assert_that(packet != nullptr, "assert failed: packet != nullptr");
175 
176   ConnectionType connection_type = acl_queue_handler->second.connection_type_;
177   size_t mtu = connection_type == ConnectionType::CLASSIC ? hci_mtu_ : le_hci_mtu_;
178   PacketBoundaryFlag packet_boundary_flag =
179           (packet->IsFlushable()) ? PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE
180                                   : PacketBoundaryFlag::FIRST_NON_AUTOMATICALLY_FLUSHABLE;
181 
182   int acl_priority = acl_queue_handler->second.high_priority_ ? 1 : 0;
183   if (packet->size() <= mtu) {
184     fragments_to_send_.push(packet_fragment{connection_type, handle, acl_priority,
185                                             AclBuilder::Create(handle, packet_boundary_flag,
186                                                                broadcast_flag, std::move(packet))},
187                             acl_priority);
188   } else {
189     auto fragments = AclFragmenter(mtu, std::move(packet)).GetFragments();
190     for (size_t i = 0; i < fragments.size(); i++) {
191       fragments_to_send_.push(
192               packet_fragment{connection_type, handle, acl_priority,
193                               AclBuilder::Create(handle, packet_boundary_flag, broadcast_flag,
194                                                  std::move(fragments[i]))},
195               acl_priority);
196       packet_boundary_flag = PacketBoundaryFlag::CONTINUING_FRAGMENT;
197     }
198   }
199   log::assert_that(fragments_to_send_.size() > 0, "assert failed: fragments_to_send_.size() > 0");
200   unregister_all_connections();
201 
202   acl_queue_handler->second.number_of_sent_packets_ += fragments_to_send_.size();
203   send_next_fragment();
204 }
205 
206 // Drops packet fragments associated with the given handle.
drop_packet_fragments(uint16_t acl_handle)207 void RoundRobinScheduler::drop_packet_fragments(uint16_t acl_handle) {
208   if (fragments_to_send_.empty()) {
209     return;
210   }
211   auto acl_queue_handler = acl_queue_handlers_.find(acl_handle);
212 
213   decltype(fragments_to_send_) new_fragments_to_send;
214   while (!fragments_to_send_.empty()) {
215     auto& fragment = fragments_to_send_.front();
216 
217     if (fragment.handle_ == acl_handle) {
218       // This fragment is not sent to the controller.
219       acl_queue_handler->second.number_of_sent_packets_--;
220     } else {
221       new_fragments_to_send.push(packet_fragment{fragment.connection_type_, fragment.handle_,
222                                                  fragment.priority_, std::move(fragment.packet_)},
223                                  fragment.priority_);
224     }
225     fragments_to_send_.pop();
226   }
227 
228   if (new_fragments_to_send.empty()) {
229     if (enqueue_registered_.exchange(false)) {
230       hci_queue_end_->UnregisterEnqueue();
231     }
232   }
233   fragments_to_send_.swap(new_fragments_to_send);
234 }
235 
unregister_all_connections()236 void RoundRobinScheduler::unregister_all_connections() {
237   for (auto acl_queue_handler = acl_queue_handlers_.begin();
238        acl_queue_handler != acl_queue_handlers_.end();
239        acl_queue_handler = std::next(acl_queue_handler)) {
240     if (acl_queue_handler->second.dequeue_is_registered_) {
241       acl_queue_handler->second.dequeue_is_registered_ = false;
242       acl_queue_handler->second.queue_->GetDownEnd()->UnregisterDequeue();
243     }
244   }
245 }
246 
send_next_fragment()247 void RoundRobinScheduler::send_next_fragment() {
248   if (!enqueue_registered_.exchange(true)) {
249     hci_queue_end_->RegisterEnqueue(handler_,
250                                     common::Bind(&RoundRobinScheduler::handle_enqueue_next_fragment,
251                                                  common::Unretained(this)));
252   }
253 }
254 
255 // Invoked from some external Queue Reactable context 1
handle_enqueue_next_fragment()256 std::unique_ptr<AclBuilder> RoundRobinScheduler::handle_enqueue_next_fragment() {
257   ConnectionType connection_type = fragments_to_send_.front().connection_type_;
258 
259   if (connection_type == ConnectionType::CLASSIC) {
260     log::assert_that(acl_packet_credits_ > 0, "assert failed: acl_packet_credits_ > 0");
261     acl_packet_credits_ -= 1;
262   } else {
263     log::assert_that(le_acl_packet_credits_ > 0, "assert failed: le_acl_packet_credits_ > 0");
264     le_acl_packet_credits_ -= 1;
265   }
266 
267   auto raw_pointer = fragments_to_send_.front().packet_.release();
268   fragments_to_send_.pop();
269   if (fragments_to_send_.empty()) {
270     if (enqueue_registered_.exchange(false)) {
271       hci_queue_end_->UnregisterEnqueue();
272     }
273     handler_->Post(
274             common::BindOnce(&RoundRobinScheduler::start_round_robin, common::Unretained(this)));
275   } else {
276     ConnectionType next_connection_type = fragments_to_send_.front().connection_type_;
277     bool classic_buffer_full =
278             next_connection_type == ConnectionType::CLASSIC && acl_packet_credits_ == 0;
279     bool le_buffer_full = next_connection_type == ConnectionType::LE && le_acl_packet_credits_ == 0;
280     if ((classic_buffer_full || le_buffer_full) && enqueue_registered_.exchange(false)) {
281       hci_queue_end_->UnregisterEnqueue();
282     }
283   }
284   return std::unique_ptr<AclBuilder>(raw_pointer);
285 }
286 
incoming_acl_credits(uint16_t handle,uint16_t credits)287 void RoundRobinScheduler::incoming_acl_credits(uint16_t handle, uint16_t credits) {
288   auto acl_queue_handler = acl_queue_handlers_.find(handle);
289   if (acl_queue_handler == acl_queue_handlers_.end()) {
290     return;
291   }
292 
293   if (acl_queue_handler->second.number_of_sent_packets_ >= credits) {
294     acl_queue_handler->second.number_of_sent_packets_ -= credits;
295   } else {
296     log::warn("receive more credits than we sent");
297     acl_queue_handler->second.number_of_sent_packets_ = 0;
298   }
299 
300   bool credit_was_zero = false;
301   if (acl_queue_handler->second.connection_type_ == ConnectionType::CLASSIC) {
302     if (acl_packet_credits_ == 0) {
303       credit_was_zero = true;
304     }
305     acl_packet_credits_ += credits;
306     if (acl_packet_credits_ > max_acl_packet_credits_) {
307       acl_packet_credits_ = max_acl_packet_credits_;
308       log::warn("acl packet credits overflow due to receive {} credits", credits);
309     }
310   } else {
311     if (le_acl_packet_credits_ == 0) {
312       credit_was_zero = true;
313     }
314     le_acl_packet_credits_ += credits;
315     if (le_acl_packet_credits_ > le_max_acl_packet_credits_) {
316       le_acl_packet_credits_ = le_max_acl_packet_credits_;
317       log::warn("le acl packet credits overflow due to receive {} credits", credits);
318     }
319   }
320   if (credit_was_zero) {
321     start_round_robin();
322   }
323 }
324 
325 }  // namespace acl_manager
326 }  // namespace hci
327 }  // namespace bluetooth
328