mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 11:10:54 +03:00
fix(ble/bluedroid): allow osi_event re-post during POSTING window
Do not reject osi_thread_post_event() when only POSTING is set. QUEUED already prevents double-queueing; rejecting POSTING caused HCI downstream lost wakeup. Add generic osi_event and hci downstream diagnostics for post failures.
This commit is contained in:
@@ -534,13 +534,30 @@ static bool osi_event_can_bind_locked(const struct osi_event *event, osi_thread_
|
|||||||
static bool osi_event_can_post_locked(const struct osi_event *event)
|
static bool osi_event_can_post_locked(const struct osi_event *event)
|
||||||
{
|
{
|
||||||
if (event->thread == NULL || event->queue_idx >= event->thread->work_queue_num) {
|
if (event->thread == NULL || event->queue_idx >= event->thread->work_queue_num) {
|
||||||
|
OSI_TRACE_EVENT("%s deny ev=%p flags=0x%x qidx=%u",
|
||||||
|
__func__, event, event ? event->flags : 0,
|
||||||
|
event ? event->queue_idx : 0);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return !OSI_EVENT_HAS_FLAG(event, OSI_EVENT_FLAG_DELETING) &&
|
if (OSI_EVENT_HAS_FLAG(event, OSI_EVENT_FLAG_DELETING) ||
|
||||||
event->item.func != NULL &&
|
event->item.func == NULL ||
|
||||||
!OSI_EVENT_HAS_FLAG(event, OSI_EVENT_FLAG_QUEUED) &&
|
OSI_EVENT_HAS_FLAG(event, OSI_EVENT_FLAG_QUEUED)) {
|
||||||
!OSI_EVENT_HAS_FLAG(event, OSI_EVENT_FLAG_POSTING);
|
OSI_TRACE_EVENT("%s deny ev=%p flags=0x%x qidx=%u wq_len=%d",
|
||||||
|
__func__, event, event->flags, event->queue_idx,
|
||||||
|
osi_thread_queue_wait_size(event->thread, event->queue_idx));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do NOT gate on OSI_EVENT_FLAG_POSTING here. POSTING marks the window in
|
||||||
|
* osi_thread_post_event() between osi_thread_post() (enqueue) and the
|
||||||
|
* poster clearing the flag. During that window the generic event handler
|
||||||
|
* may already have run and cleared QUEUED. A concurrent post that arrives
|
||||||
|
* after QUEUED is cleared is a legitimate re-post (new work arrived while
|
||||||
|
* the handler was draining) and must be accepted; rejecting it causes a
|
||||||
|
* lost wakeup. QUEUED alone prevents genuine double-queueing. POSTING is
|
||||||
|
* retained only for osi_event_is_idle()/osi_event_should_free(). */
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool osi_event_is_alive_locked(const struct osi_event *event)
|
static bool osi_event_is_alive_locked(const struct osi_event *event)
|
||||||
@@ -714,6 +731,7 @@ static void osi_thread_generic_event_handler(void *context)
|
|||||||
OSI_EVENT_SET_FLAG(event, OSI_EVENT_FLAG_RUNNING);
|
OSI_EVENT_SET_FLAG(event, OSI_EVENT_FLAG_RUNNING);
|
||||||
func = event->item.func;
|
func = event->item.func;
|
||||||
func_context = event->item.context;
|
func_context = event->item.context;
|
||||||
|
OSI_TRACE_DEBUG("%s enter ev=%p flags=0x%x", __func__, event, event->flags);
|
||||||
osi_mutex_unlock(&event->lock);
|
osi_mutex_unlock(&event->lock);
|
||||||
|
|
||||||
if (func != NULL) {
|
if (func != NULL) {
|
||||||
@@ -722,6 +740,7 @@ static void osi_thread_generic_event_handler(void *context)
|
|||||||
|
|
||||||
osi_mutex_lock(&event->lock, OSI_MUTEX_MAX_TIMEOUT);
|
osi_mutex_lock(&event->lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||||
OSI_EVENT_CLEAR_FLAG(event, OSI_EVENT_FLAG_RUNNING);
|
OSI_EVENT_CLEAR_FLAG(event, OSI_EVENT_FLAG_RUNNING);
|
||||||
|
OSI_TRACE_DEBUG("%s exit ev=%p flags=0x%x", __func__, event, event->flags);
|
||||||
osi_mutex_unlock(&event->lock);
|
osi_mutex_unlock(&event->lock);
|
||||||
|
|
||||||
osi_event_release(event);
|
osi_event_release(event);
|
||||||
@@ -755,6 +774,7 @@ bool osi_thread_post_event(struct osi_event *event, uint32_t timeout)
|
|||||||
uint8_t queue_idx = 0;
|
uint8_t queue_idx = 0;
|
||||||
|
|
||||||
if (!osi_event_acquire(event)) {
|
if (!osi_event_acquire(event)) {
|
||||||
|
OSI_TRACE_EVENT("%s acquire fail ev=%p", __func__, event);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -782,6 +802,9 @@ bool osi_thread_post_event(struct osi_event *event, uint32_t timeout)
|
|||||||
osi_mutex_unlock(&event->lock);
|
osi_mutex_unlock(&event->lock);
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
|
OSI_TRACE_EVENT("%s enqueue fail ev=%p qidx=%u wq_len=%d",
|
||||||
|
__func__, event, queue_idx,
|
||||||
|
osi_thread_queue_wait_size(thread, queue_idx));
|
||||||
osi_event_release(event);
|
osi_event_release(event);
|
||||||
}
|
}
|
||||||
osi_event_release(event);
|
osi_event_release(event);
|
||||||
|
|||||||
@@ -155,11 +155,21 @@ void hci_shut_down(void)
|
|||||||
|
|
||||||
bool hci_downstream_data_post(uint32_t timeout)
|
bool hci_downstream_data_post(uint32_t timeout)
|
||||||
{
|
{
|
||||||
|
bool ret;
|
||||||
|
|
||||||
if (hci_host_env.downstream_data_ready == NULL) {
|
if (hci_host_env.downstream_data_ready == NULL) {
|
||||||
HCI_TRACE_WARNING("%s downstream_data_ready event not created", __func__);
|
HCI_TRACE_WARNING("%s downstream_data_ready event not created", __func__);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return osi_thread_post_event(hci_host_env.downstream_data_ready, timeout);
|
|
||||||
|
ret = osi_thread_post_event(hci_host_env.downstream_data_ready, timeout);
|
||||||
|
if (!ret) {
|
||||||
|
HCI_TRACE_DEBUG("%s post fail credits=%d cmdq=%u pktq=%u",
|
||||||
|
__func__, hci_host_env.command_credits,
|
||||||
|
(unsigned)fixed_pkt_queue_length(hci_host_env.command_queue),
|
||||||
|
(unsigned)fixed_queue_length(hci_host_env.packet_queue));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hci_layer_init_env(void)
|
static int hci_layer_init_env(void)
|
||||||
@@ -249,6 +259,8 @@ static void hci_downstream_data_handler(void *arg)
|
|||||||
* All packets will be directly copied to single queue in driver layer with
|
* All packets will be directly copied to single queue in driver layer with
|
||||||
* H4 type header added (1 byte).
|
* H4 type header added (1 byte).
|
||||||
*/
|
*/
|
||||||
|
UNUSED(arg);
|
||||||
|
|
||||||
while (hci_host_check_send_available()) {
|
while (hci_host_check_send_available()) {
|
||||||
/*Now Target only allowed one packet per TX*/
|
/*Now Target only allowed one packet per TX*/
|
||||||
BT_HDR *pkt = packet_fragmenter->fragment_current_packet();
|
BT_HDR *pkt = packet_fragmenter->fragment_current_packet();
|
||||||
@@ -264,6 +276,11 @@ static void hci_downstream_data_handler(void *arg)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HCI_TRACE_DEBUG("%s done credits=%d cmdq=%u pktq=%u",
|
||||||
|
__func__, hci_host_env.command_credits,
|
||||||
|
(unsigned)fixed_pkt_queue_length(hci_host_env.command_queue),
|
||||||
|
(unsigned)fixed_queue_length(hci_host_env.packet_queue));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void transmit_command(
|
static void transmit_command(
|
||||||
|
|||||||
Reference in New Issue
Block a user