Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 121984ff authored by Sharvil Nanavati's avatar Sharvil Nanavati
Browse files

Work around race condition between thread shutdown and vendor lib shutdown.

This race condition occurs because of a structural bug - the userial
thread depends on the HCI thread and the HCI thread depends on the
userial thread but both are independently owned and torn down. This
change fixes a crash bug due to the race condition (NULL pointer
access in userial thread).

http://b/16483216

Change-Id: I91ea274856ac72e9d72b92f0dc5c94e53aaf22f4
parent 064e5350
Loading
Loading
Loading
Loading
+33 −5
Original line number Diff line number Diff line
@@ -83,6 +83,7 @@ volatile bool fwcfg_acked;
typedef struct
{
    thread_t        *worker_thread;
    pthread_mutex_t worker_thread_lock;
    bool            epilog_timer_created;
    timer_t         epilog_timer_id;
} bt_hc_cb_t;
@@ -213,17 +214,33 @@ static void event_tx_cmd(void *msg) {
}

void bthc_rx_ready(void) {
  pthread_mutex_lock(&hc_cb.worker_thread_lock);

  if (hc_cb.worker_thread)
    thread_post(hc_cb.worker_thread, event_rx, NULL);

  pthread_mutex_unlock(&hc_cb.worker_thread_lock);
}

void bthc_tx(HC_BT_HDR *buf) {
  pthread_mutex_lock(&hc_cb.worker_thread_lock);

  if (hc_cb.worker_thread) {
    if (buf)
      utils_enqueue(&tx_q, buf);
    thread_post(hc_cb.worker_thread, event_tx, NULL);
  }

  pthread_mutex_unlock(&hc_cb.worker_thread_lock);
}

void bthc_idle_timeout(void) {
  pthread_mutex_lock(&hc_cb.worker_thread_lock);

  if (hc_cb.worker_thread)
    thread_post(hc_cb.worker_thread, event_lpm_idle_timeout, NULL);

  pthread_mutex_unlock(&hc_cb.worker_thread_lock);
}

/*******************************************************************************
@@ -238,8 +255,12 @@ void bthc_idle_timeout(void) {
static void epilog_wait_timeout(UNUSED_ATTR union sigval arg)
{
    ALOGI("...epilog_wait_timeout...");

    thread_free(hc_cb.worker_thread);

    pthread_mutex_lock(&hc_cb.worker_thread_lock);
    hc_cb.worker_thread = NULL;
    pthread_mutex_unlock(&hc_cb.worker_thread_lock);
}

/*******************************************************************************
@@ -305,6 +326,8 @@ static int init(const bt_hc_callbacks_t* p_cb, unsigned char *local_bdaddr)
    hc_cb.epilog_timer_created = false;
    fwcfg_acked = false;

    pthread_mutex_init(&hc_cb.worker_thread_lock, NULL);

    /* store reference to user callbacks */
    bt_hc_cbacks = (bt_hc_callbacks_t *) p_cb;

@@ -437,7 +460,10 @@ static void cleanup( void )
        }

        thread_free(hc_cb.worker_thread);

        pthread_mutex_lock(&hc_cb.worker_thread_lock);
        hc_cb.worker_thread = NULL;
        pthread_mutex_unlock(&hc_cb.worker_thread_lock);

        if (hc_cb.epilog_timer_created)
        {
@@ -454,6 +480,8 @@ static void cleanup( void )
    set_power(BT_VND_PWR_OFF);
    vendor_close();

    pthread_mutex_destroy(&hc_cb.worker_thread_lock);

    fwcfg_acked = false;
    bt_hc_cbacks = NULL;
}