OSDN Git Service

bluez a2dp - fix state machine synchronization
authorIan Kent <raven@themaw.net>
Mon, 28 Sep 2009 15:47:44 +0000 (23:47 +0800)
committerIan Kent <raven@themaw.net>
Tue, 29 Sep 2009 05:14:10 +0000 (13:14 +0800)
Using a worker thread implementation for A2DP means that if we don't
have some way to syncroniize state transitions we can get overlap of
requested command functions or lost signals. In order for the A2DP
state machine to function each command operation must complete before
the next is initiated or we will get errors caused by these out of
sequence commands. And if we signal the thread when it is not waiting
on the condition the signal will be missed.

This could be partly resolved by implementing a queue but then there
is an overhead with also implementing a wait mechamism for state
transitions. It's much easier and simpler to just hold the mutex
during command processing which also deals with the lost signals issue.
This may well not achieve the original goal of the worker thread
implementation but neither would a queue implementation. It looks
like this is just the way things are!

utils/audio/liba2dp.c

index 34038ea..a30c369 100644 (file)
@@ -818,10 +818,8 @@ error:
 
 static void set_state(struct bluetooth_data *data, a2dp_state_t state)
 {
-       pthread_mutex_lock(&data->mutex);
        data->state = state;
        pthread_cond_signal(&data->client_wait);
-       pthread_mutex_unlock(&data->mutex);
 }
 
 static void set_command(struct bluetooth_data *data, a2dp_command_t command)
@@ -881,18 +879,17 @@ static void* a2dp_thread(void *d)
        DBG("a2dp_thread started");
        prctl(PR_SET_NAME, "a2dp_thread", 0, 0, 0);
 
+       pthread_mutex_lock(&data->mutex);
+
+       data->started = 1;
+       pthread_cond_signal(&data->thread_start);
+
        while (1)
        {
                a2dp_command_t command;
 
-               pthread_mutex_lock(&data->mutex);
-               if (!data->started) {
-                       data->started = 1;
-                       pthread_cond_signal(&data->thread_start);
-               }
                pthread_cond_wait(&data->thread_wait, &data->mutex);
                command = data->command;
-               pthread_mutex_unlock(&data->mutex);
 
                if (data->state == A2DP_STATE_NONE && command != A2DP_CMD_QUIT)
                        bluetooth_init(data);
@@ -928,6 +925,7 @@ static void* a2dp_thread(void *d)
        }
 
 done:
+       pthread_mutex_unlock(&data->mutex);
        DBG("a2dp_thread finished");
        return NULL;
 }
@@ -974,10 +972,14 @@ int a2dp_init(int rate, int channels, a2dpData* dataPtr)
                goto error;
        }
 
+       /* Make sure the state machine is ready and waiting */
        while (!data->started) {
                pthread_cond_wait(&data->thread_start, &data->mutex);
        }
 
+       /* Poke the state machine to get it going */
+       pthread_cond_signal(&data->thread_wait);
+
        pthread_mutex_unlock(&data->mutex);
 
        *dataPtr = data;