extmod/modbluetooth: Don't hold atomic section during mp_sched_schedule.

Because, for example, on unix the atomic section isn't re-entrant, and
mp_sched_schedule() will try to re-acquire the atomic section.
This commit is contained in:
Jim Mussared 2020-04-07 14:58:50 +10:00 committed by Damien George
parent 0da47ecc93
commit 8119ec0765
5 changed files with 35 additions and 37 deletions

View File

@ -160,29 +160,30 @@ STATIC void btstack_packet_handler(uint8_t packet_type, uint16_t channel, uint8_
uint16_t value_handle = gatt_event_characteristic_value_query_result_get_value_handle(packet); uint16_t value_handle = gatt_event_characteristic_value_query_result_get_value_handle(packet);
uint16_t len = gatt_event_characteristic_value_query_result_get_value_length(packet); uint16_t len = gatt_event_characteristic_value_query_result_get_value_length(packet);
const uint8_t *data = gatt_event_characteristic_value_query_result_get_value(packet); const uint8_t *data = gatt_event_characteristic_value_query_result_get_value(packet);
MICROPY_PY_BLUETOOTH_ENTER mp_uint_t atomic_state;
len = mp_bluetooth_gattc_on_data_available_start(MP_BLUETOOTH_IRQ_GATTC_READ_RESULT, conn_handle, value_handle, len); len = mp_bluetooth_gattc_on_data_available_start(MP_BLUETOOTH_IRQ_GATTC_READ_RESULT, conn_handle, value_handle, len, &atomic_state);
mp_bluetooth_gattc_on_data_available_chunk(data, len); mp_bluetooth_gattc_on_data_available_chunk(data, len);
mp_bluetooth_gattc_on_data_available_end(); mp_bluetooth_gattc_on_data_available_end(atomic_state);
MICROPY_PY_BLUETOOTH_EXIT
} else if (event_type == GATT_EVENT_NOTIFICATION) { } else if (event_type == GATT_EVENT_NOTIFICATION) {
DEBUG_EVENT_printf(" --> gatt notification\n"); DEBUG_EVENT_printf(" --> gatt notification\n");
uint16_t conn_handle = gatt_event_notification_get_handle(packet); uint16_t conn_handle = gatt_event_notification_get_handle(packet);
uint16_t value_handle = gatt_event_notification_get_value_handle(packet); uint16_t value_handle = gatt_event_notification_get_value_handle(packet);
uint16_t len = gatt_event_notification_get_value_length(packet); uint16_t len = gatt_event_notification_get_value_length(packet);
const uint8_t *data = gatt_event_notification_get_value(packet); const uint8_t *data = gatt_event_notification_get_value(packet);
len = mp_bluetooth_gattc_on_data_available_start(MP_BLUETOOTH_IRQ_GATTC_NOTIFY, conn_handle, value_handle, len); mp_uint_t atomic_state;
len = mp_bluetooth_gattc_on_data_available_start(MP_BLUETOOTH_IRQ_GATTC_NOTIFY, conn_handle, value_handle, len, &atomic_state);
mp_bluetooth_gattc_on_data_available_chunk(data, len); mp_bluetooth_gattc_on_data_available_chunk(data, len);
mp_bluetooth_gattc_on_data_available_end(); mp_bluetooth_gattc_on_data_available_end(atomic_state);
} else if (event_type == GATT_EVENT_INDICATION) { } else if (event_type == GATT_EVENT_INDICATION) {
DEBUG_EVENT_printf(" --> gatt indication\n"); DEBUG_EVENT_printf(" --> gatt indication\n");
uint16_t conn_handle = gatt_event_indication_get_handle(packet); uint16_t conn_handle = gatt_event_indication_get_handle(packet);
uint16_t value_handle = gatt_event_indication_get_value_handle(packet); uint16_t value_handle = gatt_event_indication_get_value_handle(packet);
uint16_t len = gatt_event_indication_get_value_length(packet); uint16_t len = gatt_event_indication_get_value_length(packet);
const uint8_t *data = gatt_event_indication_get_value(packet); const uint8_t *data = gatt_event_indication_get_value(packet);
len = mp_bluetooth_gattc_on_data_available_start(MP_BLUETOOTH_IRQ_GATTC_INDICATE, conn_handle, value_handle, len); mp_uint_t atomic_state;
len = mp_bluetooth_gattc_on_data_available_start(MP_BLUETOOTH_IRQ_GATTC_INDICATE, conn_handle, value_handle, len, &atomic_state);
mp_bluetooth_gattc_on_data_available_chunk(data, len); mp_bluetooth_gattc_on_data_available_chunk(data, len);
mp_bluetooth_gattc_on_data_available_end(); mp_bluetooth_gattc_on_data_available_end(atomic_state);
#endif #endif
} else { } else {
DEBUG_EVENT_printf(" --> hci event type: unknown (0x%02x)\n", event_type); DEBUG_EVENT_printf(" --> hci event type: unknown (0x%02x)\n", event_type);

View File

@ -918,11 +918,15 @@ STATIC bool enqueue_irq(mp_obj_bluetooth_ble_t *o, size_t len, uint16_t event) {
return true; return true;
} }
STATIC void schedule_ringbuf(void) { // Must hold the atomic section before calling this (MICROPY_PY_BLUETOOTH_ENTER).
STATIC void schedule_ringbuf(mp_uint_t atomic_state) {
mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
if (!o->irq_scheduled) { if (!o->irq_scheduled) {
o->irq_scheduled = true; o->irq_scheduled = true;
MICROPY_PY_BLUETOOTH_EXIT
mp_sched_schedule(MP_OBJ_FROM_PTR(&bluetooth_ble_invoke_irq_obj), mp_const_none); mp_sched_schedule(MP_OBJ_FROM_PTR(&bluetooth_ble_invoke_irq_obj), mp_const_none);
} else {
MICROPY_PY_BLUETOOTH_EXIT
} }
} }
@ -936,8 +940,7 @@ void mp_bluetooth_gap_on_connected_disconnected(uint16_t event, uint16_t conn_ha
ringbuf_put(&o->ringbuf, addr[i]); ringbuf_put(&o->ringbuf, addr[i]);
} }
} }
schedule_ringbuf(); schedule_ringbuf(atomic_state);
MICROPY_PY_BLUETOOTH_EXIT
} }
void mp_bluetooth_gatts_on_write(uint16_t conn_handle, uint16_t value_handle) { void mp_bluetooth_gatts_on_write(uint16_t conn_handle, uint16_t value_handle) {
@ -947,8 +950,7 @@ void mp_bluetooth_gatts_on_write(uint16_t conn_handle, uint16_t value_handle) {
ringbuf_put16(&o->ringbuf, conn_handle); ringbuf_put16(&o->ringbuf, conn_handle);
ringbuf_put16(&o->ringbuf, value_handle); ringbuf_put16(&o->ringbuf, value_handle);
} }
schedule_ringbuf(); schedule_ringbuf(atomic_state);
MICROPY_PY_BLUETOOTH_EXIT
} }
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
@ -957,8 +959,7 @@ void mp_bluetooth_gap_on_scan_complete(void) {
mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
if (enqueue_irq(o, 0, MP_BLUETOOTH_IRQ_SCAN_COMPLETE)) { if (enqueue_irq(o, 0, MP_BLUETOOTH_IRQ_SCAN_COMPLETE)) {
} }
schedule_ringbuf(); schedule_ringbuf(atomic_state);
MICROPY_PY_BLUETOOTH_EXIT
} }
void mp_bluetooth_gap_on_scan_result(uint8_t addr_type, const uint8_t *addr, uint8_t adv_type, const int8_t rssi, const uint8_t *data, size_t data_len) { void mp_bluetooth_gap_on_scan_result(uint8_t addr_type, const uint8_t *addr, uint8_t adv_type, const int8_t rssi, const uint8_t *data, size_t data_len) {
@ -979,8 +980,7 @@ void mp_bluetooth_gap_on_scan_result(uint8_t addr_type, const uint8_t *addr, uin
ringbuf_put(&o->ringbuf, data[i]); ringbuf_put(&o->ringbuf, data[i]);
} }
} }
schedule_ringbuf(); schedule_ringbuf(atomic_state);
MICROPY_PY_BLUETOOTH_EXIT
} }
void mp_bluetooth_gattc_on_primary_service_result(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, mp_obj_bluetooth_uuid_t *service_uuid) { void mp_bluetooth_gattc_on_primary_service_result(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, mp_obj_bluetooth_uuid_t *service_uuid) {
@ -992,8 +992,7 @@ void mp_bluetooth_gattc_on_primary_service_result(uint16_t conn_handle, uint16_t
ringbuf_put16(&o->ringbuf, end_handle); ringbuf_put16(&o->ringbuf, end_handle);
ringbuf_put_uuid(&o->ringbuf, service_uuid); ringbuf_put_uuid(&o->ringbuf, service_uuid);
} }
schedule_ringbuf(); schedule_ringbuf(atomic_state);
MICROPY_PY_BLUETOOTH_EXIT
} }
void mp_bluetooth_gattc_on_characteristic_result(uint16_t conn_handle, uint16_t def_handle, uint16_t value_handle, uint8_t properties, mp_obj_bluetooth_uuid_t *characteristic_uuid) { void mp_bluetooth_gattc_on_characteristic_result(uint16_t conn_handle, uint16_t def_handle, uint16_t value_handle, uint8_t properties, mp_obj_bluetooth_uuid_t *characteristic_uuid) {
@ -1006,8 +1005,7 @@ void mp_bluetooth_gattc_on_characteristic_result(uint16_t conn_handle, uint16_t
ringbuf_put(&o->ringbuf, properties); ringbuf_put(&o->ringbuf, properties);
ringbuf_put_uuid(&o->ringbuf, characteristic_uuid); ringbuf_put_uuid(&o->ringbuf, characteristic_uuid);
} }
schedule_ringbuf(); schedule_ringbuf(atomic_state);
MICROPY_PY_BLUETOOTH_EXIT
} }
void mp_bluetooth_gattc_on_descriptor_result(uint16_t conn_handle, uint16_t handle, mp_obj_bluetooth_uuid_t *descriptor_uuid) { void mp_bluetooth_gattc_on_descriptor_result(uint16_t conn_handle, uint16_t handle, mp_obj_bluetooth_uuid_t *descriptor_uuid) {
@ -1018,11 +1016,12 @@ void mp_bluetooth_gattc_on_descriptor_result(uint16_t conn_handle, uint16_t hand
ringbuf_put16(&o->ringbuf, handle); ringbuf_put16(&o->ringbuf, handle);
ringbuf_put_uuid(&o->ringbuf, descriptor_uuid); ringbuf_put_uuid(&o->ringbuf, descriptor_uuid);
} }
schedule_ringbuf(); schedule_ringbuf(atomic_state);
MICROPY_PY_BLUETOOTH_EXIT
} }
size_t mp_bluetooth_gattc_on_data_available_start(uint16_t event, uint16_t conn_handle, uint16_t value_handle, size_t data_len) { size_t mp_bluetooth_gattc_on_data_available_start(uint16_t event, uint16_t conn_handle, uint16_t value_handle, size_t data_len, mp_uint_t *atomic_state_out) {
MICROPY_PY_BLUETOOTH_ENTER
*atomic_state_out = atomic_state;
mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth)); mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
data_len = MIN(o->irq_data_data_alloc, data_len); data_len = MIN(o->irq_data_data_alloc, data_len);
if (enqueue_irq(o, 2 + 2 + 1 + data_len, event)) { if (enqueue_irq(o, 2 + 2 + 1 + data_len, event)) {
@ -1042,8 +1041,8 @@ void mp_bluetooth_gattc_on_data_available_chunk(const uint8_t *data, size_t data
} }
} }
void mp_bluetooth_gattc_on_data_available_end(void) { void mp_bluetooth_gattc_on_data_available_end(mp_uint_t atomic_state) {
schedule_ringbuf(); schedule_ringbuf(atomic_state);
} }
void mp_bluetooth_gattc_on_write_status(uint16_t conn_handle, uint16_t value_handle, uint16_t status) { void mp_bluetooth_gattc_on_write_status(uint16_t conn_handle, uint16_t value_handle, uint16_t status) {
@ -1054,8 +1053,7 @@ void mp_bluetooth_gattc_on_write_status(uint16_t conn_handle, uint16_t value_han
ringbuf_put16(&o->ringbuf, value_handle); ringbuf_put16(&o->ringbuf, value_handle);
ringbuf_put16(&o->ringbuf, status); ringbuf_put16(&o->ringbuf, status);
} }
schedule_ringbuf(); schedule_ringbuf(atomic_state);
MICROPY_PY_BLUETOOTH_EXIT
} }
#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE #endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE

View File

@ -263,9 +263,9 @@ void mp_bluetooth_gattc_on_descriptor_result(uint16_t conn_handle, uint16_t hand
// Notify modbluetooth that a read has completed with data (or notify/indicate data available, use `event` to disambiguate). // Notify modbluetooth that a read has completed with data (or notify/indicate data available, use `event` to disambiguate).
// Note: these functions are to be called in a group protected by MICROPY_PY_BLUETOOTH_ENTER/EXIT. // Note: these functions are to be called in a group protected by MICROPY_PY_BLUETOOTH_ENTER/EXIT.
// _start returns the number of bytes to submit to the calls to _chunk, followed by a call to _end. // _start returns the number of bytes to submit to the calls to _chunk, followed by a call to _end.
size_t mp_bluetooth_gattc_on_data_available_start(uint16_t event, uint16_t conn_handle, uint16_t value_handle, size_t data_len); size_t mp_bluetooth_gattc_on_data_available_start(uint16_t event, uint16_t conn_handle, uint16_t value_handle, size_t data_len, mp_uint_t *atomic_state_out);
void mp_bluetooth_gattc_on_data_available_chunk(const uint8_t *data, size_t data_len); void mp_bluetooth_gattc_on_data_available_chunk(const uint8_t *data, size_t data_len);
void mp_bluetooth_gattc_on_data_available_end(void); void mp_bluetooth_gattc_on_data_available_end(mp_uint_t atomic_state);
// Notify modbluetooth that a write has completed. // Notify modbluetooth that a write has completed.
void mp_bluetooth_gattc_on_write_status(uint16_t conn_handle, uint16_t value_handle, uint16_t status); void mp_bluetooth_gattc_on_write_status(uint16_t conn_handle, uint16_t value_handle, uint16_t status);

View File

@ -613,17 +613,16 @@ int mp_bluetooth_gatts_set_buffer(uint16_t value_handle, size_t len, bool append
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
STATIC void gattc_on_data_available(uint16_t event, uint16_t conn_handle, uint16_t value_handle, const struct os_mbuf *om) { STATIC void gattc_on_data_available(uint16_t event, uint16_t conn_handle, uint16_t value_handle, const struct os_mbuf *om) {
MICROPY_PY_BLUETOOTH_ENTER
size_t len = OS_MBUF_PKTLEN(om); size_t len = OS_MBUF_PKTLEN(om);
len = mp_bluetooth_gattc_on_data_available_start(event, conn_handle, value_handle, len); mp_uint_t atomic_state;
len = mp_bluetooth_gattc_on_data_available_start(event, conn_handle, value_handle, len, &atomic_state);
while (len > 0 && om != NULL) { while (len > 0 && om != NULL) {
size_t n = MIN(om->om_len, len); size_t n = MIN(om->om_len, len);
mp_bluetooth_gattc_on_data_available_chunk(OS_MBUF_DATA(om, const uint8_t *), n); mp_bluetooth_gattc_on_data_available_chunk(OS_MBUF_DATA(om, const uint8_t *), n);
len -= n; len -= n;
om = SLIST_NEXT(om, om_next); om = SLIST_NEXT(om, om_next);
} }
mp_bluetooth_gattc_on_data_available_end(); mp_bluetooth_gattc_on_data_available_end(atomic_state);
MICROPY_PY_BLUETOOTH_EXIT
} }
STATIC int gap_scan_cb(struct ble_gap_event *event, void *arg) { STATIC int gap_scan_cb(struct ble_gap_event *event, void *arg) {

View File

@ -402,9 +402,9 @@ static inline mp_uint_t disable_irq(void) {
#endif #endif
// The LwIP interface must run at a raised IRQ priority // The LwIP interface must run at a raised IRQ priority
#define MICROPY_PY_LWIP_ENTER uint32_t irq_state = raise_irq_pri(IRQ_PRI_PENDSV); #define MICROPY_PY_LWIP_ENTER uint32_t atomic_state = raise_irq_pri(IRQ_PRI_PENDSV);
#define MICROPY_PY_LWIP_REENTER irq_state = raise_irq_pri(IRQ_PRI_PENDSV); #define MICROPY_PY_LWIP_REENTER atomic_state = raise_irq_pri(IRQ_PRI_PENDSV);
#define MICROPY_PY_LWIP_EXIT restore_irq_pri(irq_state); #define MICROPY_PY_LWIP_EXIT restore_irq_pri(atomic_state);
// Bluetooth calls must run at a raised IRQ priority // Bluetooth calls must run at a raised IRQ priority
#define MICROPY_PY_BLUETOOTH_ENTER MICROPY_PY_LWIP_ENTER #define MICROPY_PY_BLUETOOTH_ENTER MICROPY_PY_LWIP_ENTER