Skip to content

Commit eb0badd

Browse files
Avoid malloc/free while in HCI callbacks (#2219)
Bluetooth operates at IRQ level, so using std::list (which needs to new and delete objects) is not legal. Use a fixed, preallocated vector instead.
1 parent f272995 commit eb0badd

File tree

7 files changed

+47
-30
lines changed

7 files changed

+47
-30
lines changed

docs/hidmaster.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ BTDeviceInfo Class
1111
------------------
1212

1313
The ``BluetoothHCI`` class implements a scanning function for classic
14-
and BLE devices and can return a ``std::list`` of discovered devices to an application.
14+
and BLE devices and can return a ``std::vector`` of discovered devices to an application.
1515
Iterate over the list using any of the STL iteration methods (i.e. ``for (auto e : list)``).
1616
The elements of this list are ``BTDeviceInfo`` objects which have the following
1717
member functions:
@@ -179,7 +179,7 @@ bool BluetoothHIDMaster::hciRunning()
179179
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
180180
Returns if the Bluetooth stack has passed the initial HCI start up phase. Until this returns ``true`` no Bluetooth operations can be performed.
181181

182-
std::list<BTDeviceInfo> BluetoothHIDMaster::scan(uint32_t mask, int scanTimeSec, bool async)
182+
std::vector<BTDeviceInfo> BluetoothHIDMaster::scan(uint32_t mask, int scanTimeSec, bool async)
183183
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
184184
Passes through the ``BluetoothHCI::scan()`` function to manually scan for a list of nearby devices. If you want to connect to the first found device, this is not needed.
185185

libraries/BluetoothAudio/src/A2DPSource.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ class A2DPSource : public Stream {
104104

105105
bool begin();
106106

107-
std::list<BTDeviceInfo> scan(uint32_t mask = BluetoothHCI::speaker_cod, int scanTimeSec = 5, bool async = false) {
107+
std::vector<BTDeviceInfo> scan(uint32_t mask = BluetoothHCI::speaker_cod, int scanTimeSec = 5, bool async = false) {
108108
return _hci.scan(mask, scanTimeSec, async);
109109
}
110110

libraries/BluetoothHCI/src/BluetoothDevice.h

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,59 +24,60 @@
2424

2525
class BTDeviceInfo {
2626
public:
27+
// Classic Bluetooth Device
2728
BTDeviceInfo(uint32_t dc, const uint8_t addr[6], int rssi, const char *name) {
2829
_deviceClass = dc;
2930
memcpy(_address, addr, sizeof(_address));
3031
_addressType = -1;
3132
sprintf(_addressString, "%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
3233
_rssi = rssi;
33-
_name = strdup(name);
34+
strncpy(_name, name, sizeof(_name));
35+
_name[sizeof(_name) - 1] = 0;
3436
}
37+
38+
// Bluetooth BLE Device
3539
BTDeviceInfo(uint32_t dc, const uint8_t addr[6], int addressType, int rssi, const char *name, size_t nameLen) {
3640
_deviceClass = dc;
3741
memcpy(_address, addr, sizeof(_address));
3842
sprintf(_addressString, "%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
3943
_addressType = addressType;
4044
_rssi = rssi;
41-
_name = (char *)malloc(nameLen + 1);
42-
memcpy(_name, name, nameLen);
43-
_name[nameLen] = 0;
44-
}
45-
// Copy constructor to ensure we deep-copy the string
46-
BTDeviceInfo(const BTDeviceInfo &b) {
47-
_deviceClass = b._deviceClass;
48-
memcpy(_address, b._address, sizeof(_address));
49-
_addressType = b._addressType;
50-
memcpy(_addressString, b._addressString, sizeof(_addressString));
51-
_rssi = b._rssi;
52-
_name = strdup(b._name);
45+
memcpy(_name, name, std::min(nameLen, sizeof(_name)));
46+
_name[std::min(nameLen, sizeof(_name) - 1)] = 0;
5347
}
48+
5449
~BTDeviceInfo() {
55-
free(_name);
5650
}
51+
5752
uint32_t deviceClass() {
5853
return _deviceClass;
5954
}
55+
6056
const uint8_t *address() {
6157
return _address;
6258
}
59+
6360
const char *addressString() {
6461
return _addressString;
6562
}
63+
6664
int rssi() {
6765
return _rssi;
6866
}
67+
6968
const char *name() {
7069
return _name;
7170
}
71+
7272
int addressType() {
7373
return _addressType;
7474
}
75+
7576
private:
7677
uint32_t _deviceClass;
7778
uint8_t _address[6];
7879
int _addressType;
7980
char _addressString[18];
8081
int8_t _rssi;
81-
char *_name;
82+
char _name[241];
8283
};

libraries/BluetoothHCI/src/BluetoothHCI.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,9 @@ bool BluetoothHCI::running() {
103103
return _hciRunning;
104104
}
105105

106-
std::list<BTDeviceInfo> BluetoothHCI::scan(uint32_t mask, int scanTimeSec, bool async) {
106+
std::vector<BTDeviceInfo> BluetoothHCI::scan(uint32_t mask, int scanTimeSec, bool async) {
107107
_scanMask = mask;
108+
_btdList.reserve(MAX_DEVICES_TO_DISCOVER);
108109
_btdList.clear();
109110
if (!_running) {
110111
return _btdList;
@@ -135,8 +136,9 @@ std::list<BTDeviceInfo> BluetoothHCI::scan(uint32_t mask, int scanTimeSec, bool
135136
return _btdList;
136137
}
137138

138-
std::list<BTDeviceInfo> BluetoothHCI::scanBLE(uint32_t uuid, int scanTimeSec) {
139+
std::vector<BTDeviceInfo> BluetoothHCI::scanBLE(uint32_t uuid, int scanTimeSec) {
139140
_scanMask = uuid;
141+
_btdList.reserve(MAX_DEVICES_TO_DISCOVER);
140142
_btdList.clear();
141143
if (!_running) {
142144
return _btdList;
@@ -168,6 +170,10 @@ std::list<BTDeviceInfo> BluetoothHCI::scanBLE(uint32_t uuid, int scanTimeSec) {
168170
return _btdList;
169171
}
170172

173+
void BluetoothHCI::scanFree() {
174+
_btdList.clear();
175+
_btdList.shrink_to_fit();
176+
}
171177

172178
void BluetoothHCI::parse_advertisement_data(uint8_t *packet) {
173179
bd_addr_t address;
@@ -298,7 +304,9 @@ void BluetoothHCI::parse_advertisement_data(uint8_t *packet) {
298304
}
299305
if (!seen) {
300306
BTDeviceInfo btd(uuid, address, address_type, rssi, nameptr ? nameptr : "", nameptr ? namelen : 0);
301-
_btdList.push_back(btd);
307+
if (_btdList.size() < MAX_DEVICES_TO_DISCOVER) {
308+
_btdList.push_back(btd);
309+
}
302310
}
303311
}
304312
}
@@ -394,7 +402,9 @@ void BluetoothHCI::hci_packet_handler(uint8_t packet_type, uint16_t channel, uin
394402
}
395403
}
396404
BTDeviceInfo btd(cod, address, rssi, name);
397-
_btdList.push_back(btd);
405+
if (_btdList.size() < MAX_DEVICES_TO_DISCOVER) {
406+
_btdList.push_back(btd);
407+
}
398408
}
399409
break;
400410
case GAP_EVENT_INQUIRY_COMPLETE:

libraries/BluetoothHCI/src/BluetoothHCI.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,13 @@ class BluetoothHCI {
3939

4040
static const uint32_t speaker_cod = 0x200000 | 0x040000 | 0x000400; // Service Class: Rendering | Audio, Major Device Class: Audio
4141
static const uint32_t any_cod = 0;
42-
std::list<BTDeviceInfo> scan(uint32_t mask, int scanTimeSec = 5, bool async = false);
42+
std::vector<BTDeviceInfo> scan(uint32_t mask, int scanTimeSec = 5, bool async = false);
4343
bool scanAsyncDone();
44-
std::list<BTDeviceInfo> scanAsyncResult();
44+
std::vector<BTDeviceInfo> scanAsyncResult();
4545

46-
std::list<BTDeviceInfo> scanBLE(uint32_t uuid, int scanTimeSec = 5);
46+
std::vector<BTDeviceInfo> scanBLE(uint32_t uuid, int scanTimeSec = 5);
47+
48+
void scanFree(); // Free allocated scan buffers
4749

4850
friend class BluetoothHIDMaster;
4951

@@ -60,7 +62,11 @@ class BluetoothHCI {
6062
btstack_packet_callback_registration_t hci_event_callback_registration;
6163
volatile bool _hciRunning = false;
6264
uint32_t _scanMask;
63-
std::list<BTDeviceInfo> _btdList;
65+
// Use a .reserve()'d vector to avoid any memory allocations in the
66+
// HCI callback, since the callback happens at IRQ time. Any more
67+
// elements than MAX_DEVICES_TO_DISCOVER will be thrown out
68+
enum { MAX_DEVICES_TO_DISCOVER = 32 };
69+
std::vector<BTDeviceInfo> _btdList;
6470
volatile bool _scanning = false;
6571
bool _running = false;
6672

libraries/BluetoothHIDMaster/src/BluetoothHIDMaster.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,14 +166,14 @@ void BluetoothHIDMaster::onJoystick(void (*cb)(void *, int, int, int, int, uint8
166166
_joystickData = cbData;
167167
}
168168

169-
std::list<BTDeviceInfo> BluetoothHIDMaster::scan(uint32_t mask, int scanTimeSec, bool async) {
169+
std::vector<BTDeviceInfo> BluetoothHIDMaster::scan(uint32_t mask, int scanTimeSec, bool async) {
170170
return _hci.scan(mask, scanTimeSec, async);
171171
}
172172

173173
bool BluetoothHIDMaster::scanAsyncDone() {
174174
return _hci.scanAsyncDone();
175175
}
176-
std::list<BTDeviceInfo> BluetoothHIDMaster::scanAsyncResult() {
176+
std::vector<BTDeviceInfo> BluetoothHIDMaster::scanAsyncResult() {
177177
return _hci.scanAsyncResult();
178178
}
179179

libraries/BluetoothHIDMaster/src/BluetoothHIDMaster.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ class BluetoothHIDMaster {
8080
static const uint32_t mouse_cod = 0x2540;
8181
static const uint32_t joystick_cod = 0x2508;
8282
static const uint32_t any_cod = 0;
83-
std::list<BTDeviceInfo> scan(uint32_t mask, int scanTimeSec = 5, bool async = false);
83+
std::vector<BTDeviceInfo> scan(uint32_t mask, int scanTimeSec = 5, bool async = false);
8484
bool scanAsyncDone();
85-
std::list<BTDeviceInfo> scanAsyncResult();
85+
std::vector<BTDeviceInfo> scanAsyncResult();
8686

8787
bool connect(const uint8_t *addr);
8888
bool connectKeyboard();

0 commit comments

Comments
 (0)