@@ -94,6 +94,7 @@ static int transport_pcm_init(
94
94
ba_transport_pcm_volume_set (& pcm -> volume [1 ], NULL , NULL , NULL );
95
95
96
96
pthread_mutex_init (& pcm -> mutex , NULL );
97
+ pthread_mutex_init (& pcm -> client_mtx , NULL );
97
98
pthread_cond_init (& pcm -> cond , NULL );
98
99
99
100
pcm -> ba_dbus_path = g_strdup_printf ("%s/%s/%s" ,
@@ -111,6 +112,7 @@ static void transport_pcm_free(
111
112
pthread_mutex_unlock (& pcm -> mutex );
112
113
113
114
pthread_mutex_destroy (& pcm -> mutex );
115
+ pthread_mutex_destroy (& pcm -> client_mtx );
114
116
pthread_cond_destroy (& pcm -> cond );
115
117
116
118
if (pcm -> ba_dbus_path != NULL )
@@ -150,6 +152,48 @@ void ba_transport_pcm_volume_set(
150
152
151
153
}
152
154
155
+ static int ba_transport_pcms_full_lock (struct ba_transport * t ) {
156
+ if (t -> profile & BA_TRANSPORT_PROFILE_MASK_A2DP ) {
157
+ /* lock client mutexes first to avoid deadlock */
158
+ pthread_mutex_lock (& t -> a2dp .pcm .client_mtx );
159
+ pthread_mutex_lock (& t -> a2dp .pcm_bc .client_mtx );
160
+ /* lock PCM data mutexes */
161
+ pthread_mutex_lock (& t -> a2dp .pcm .mutex );
162
+ pthread_mutex_lock (& t -> a2dp .pcm_bc .mutex );
163
+ return 0 ;
164
+ }
165
+ if (t -> profile & BA_TRANSPORT_PROFILE_MASK_SCO ) {
166
+ /* lock client mutexes first to avoid deadlock */
167
+ pthread_mutex_lock (& t -> sco .spk_pcm .client_mtx );
168
+ pthread_mutex_lock (& t -> sco .mic_pcm .client_mtx );
169
+ /* lock PCM data mutexes */
170
+ pthread_mutex_lock (& t -> sco .spk_pcm .mutex );
171
+ pthread_mutex_lock (& t -> sco .mic_pcm .mutex );
172
+ return 0 ;
173
+ }
174
+ errno = EINVAL ;
175
+ return -1 ;
176
+ }
177
+
178
+ static int ba_transport_pcms_full_unlock (struct ba_transport * t ) {
179
+ if (t -> profile & BA_TRANSPORT_PROFILE_MASK_A2DP ) {
180
+ pthread_mutex_unlock (& t -> a2dp .pcm .mutex );
181
+ pthread_mutex_unlock (& t -> a2dp .pcm_bc .mutex );
182
+ pthread_mutex_unlock (& t -> a2dp .pcm .client_mtx );
183
+ pthread_mutex_unlock (& t -> a2dp .pcm_bc .client_mtx );
184
+ return 0 ;
185
+ }
186
+ if (t -> profile & BA_TRANSPORT_PROFILE_MASK_SCO ) {
187
+ pthread_mutex_unlock (& t -> sco .spk_pcm .mutex );
188
+ pthread_mutex_unlock (& t -> sco .mic_pcm .mutex );
189
+ pthread_mutex_unlock (& t -> sco .spk_pcm .client_mtx );
190
+ pthread_mutex_unlock (& t -> sco .mic_pcm .client_mtx );
191
+ return 0 ;
192
+ }
193
+ errno = EINVAL ;
194
+ return -1 ;
195
+ }
196
+
153
197
static int transport_thread_init (
154
198
struct ba_transport_thread * th ,
155
199
struct ba_transport * t ) {
@@ -392,9 +436,11 @@ static void transport_threads_cancel(struct ba_transport *t) {
392
436
393
437
static void transport_threads_cancel_if_no_clients (struct ba_transport * t ) {
394
438
395
- /* Hold PCM locks, so no client will open a PCM in
396
- * the middle of our PCM inactivity check. */
397
- ba_transport_pcms_lock (t );
439
+ /* Hold PCM client and data locks. The data lock is required because we
440
+ * are going to check the PCM FIFO file descriptor. The client lock is
441
+ * required to prevent PCM clients from opening PCM in the middle of our
442
+ * inactivity check. */
443
+ ba_transport_pcms_full_lock (t );
398
444
399
445
/* Hold BT lock, because we are going to modify
400
446
* the IO transports stopping flag. */
@@ -428,7 +474,7 @@ static void transport_threads_cancel_if_no_clients(struct ba_transport *t) {
428
474
429
475
final :
430
476
pthread_mutex_unlock (& t -> bt_fd_mtx );
431
- ba_transport_pcms_unlock (t );
477
+ ba_transport_pcms_full_unlock (t );
432
478
433
479
if (stop ) {
434
480
transport_threads_cancel (t );
@@ -900,7 +946,7 @@ void ba_transport_destroy(struct ba_transport *t) {
900
946
/* stop transport IO threads */
901
947
ba_transport_stop (t );
902
948
903
- ba_transport_pcms_lock (t );
949
+ ba_transport_pcms_full_lock (t );
904
950
905
951
/* terminate on-going PCM connections - exit PCM controllers */
906
952
if (t -> profile & BA_TRANSPORT_PROFILE_MASK_A2DP ) {
@@ -915,7 +961,7 @@ void ba_transport_destroy(struct ba_transport *t) {
915
961
/* make sure that transport is released */
916
962
ba_transport_release (t );
917
963
918
- ba_transport_pcms_unlock (t );
964
+ ba_transport_pcms_full_unlock (t );
919
965
920
966
ba_transport_unref (t );
921
967
}
@@ -992,36 +1038,6 @@ void ba_transport_pcm_unref(struct ba_transport_pcm *pcm) {
992
1038
ba_transport_unref (pcm -> t );
993
1039
}
994
1040
995
- int ba_transport_pcms_lock (struct ba_transport * t ) {
996
- if (t -> profile & BA_TRANSPORT_PROFILE_MASK_A2DP ) {
997
- pthread_mutex_lock (& t -> a2dp .pcm .mutex );
998
- pthread_mutex_lock (& t -> a2dp .pcm_bc .mutex );
999
- return 0 ;
1000
- }
1001
- if (t -> profile & BA_TRANSPORT_PROFILE_MASK_SCO ) {
1002
- pthread_mutex_lock (& t -> sco .spk_pcm .mutex );
1003
- pthread_mutex_lock (& t -> sco .mic_pcm .mutex );
1004
- return 0 ;
1005
- }
1006
- errno = EINVAL ;
1007
- return -1 ;
1008
- }
1009
-
1010
- int ba_transport_pcms_unlock (struct ba_transport * t ) {
1011
- if (t -> profile & BA_TRANSPORT_PROFILE_MASK_A2DP ) {
1012
- pthread_mutex_unlock (& t -> a2dp .pcm .mutex );
1013
- pthread_mutex_unlock (& t -> a2dp .pcm_bc .mutex );
1014
- return 0 ;
1015
- }
1016
- if (t -> profile & BA_TRANSPORT_PROFILE_MASK_SCO ) {
1017
- pthread_mutex_unlock (& t -> sco .spk_pcm .mutex );
1018
- pthread_mutex_unlock (& t -> sco .mic_pcm .mutex );
1019
- return 0 ;
1020
- }
1021
- errno = EINVAL ;
1022
- return -1 ;
1023
- }
1024
-
1025
1041
int ba_transport_select_codec_a2dp (
1026
1042
struct ba_transport * t ,
1027
1043
const struct a2dp_sep * sep ) {
@@ -1096,11 +1112,11 @@ int ba_transport_select_codec_sco(
1096
1112
/* stop transport IO threads */
1097
1113
ba_transport_stop (t );
1098
1114
1099
- ba_transport_pcms_lock (t );
1115
+ ba_transport_pcms_full_lock (t );
1100
1116
/* release ongoing PCM connections */
1101
1117
ba_transport_pcm_release (& t -> sco .spk_pcm );
1102
1118
ba_transport_pcm_release (& t -> sco .mic_pcm );
1103
- ba_transport_pcms_unlock (t );
1119
+ ba_transport_pcms_full_unlock (t );
1104
1120
1105
1121
r -> codec_selection_done = false;
1106
1122
/* delegate set codec to RFCOMM thread */
0 commit comments