audio HAL: fix thread starvation
Fix thread starvation issue where the capture or playback threads
running in FIFO priority would constantly acquire the stream mutex preventing
other threads to complete routing commands.
Change-Id: I8d1befa0791ae9a3bce868c1c3ef262ff489f052
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 3f3f967..de645bd 100755
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -1157,6 +1157,20 @@
return ret;
}
+void lock_input_stream(struct stream_in *in)
+{
+ pthread_mutex_lock(&in->pre_lock);
+ pthread_mutex_lock(&in->lock);
+ pthread_mutex_unlock(&in->pre_lock);
+}
+
+void lock_output_stream(struct stream_out *out)
+{
+ pthread_mutex_lock(&out->pre_lock);
+ pthread_mutex_lock(&out->lock);
+ pthread_mutex_unlock(&out->pre_lock);
+}
+
/* must be called with out->lock locked */
static int send_offload_cmd_l(struct stream_out* out, int command)
{
@@ -1245,7 +1259,7 @@
prctl(PR_SET_NAME, (unsigned long)"Offload Callback", 0, 0, 0);
ALOGV("%s", __func__);
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
for (;;) {
struct offload_cmd *cmd = NULL;
stream_callback_event_t event;
@@ -1324,7 +1338,7 @@
ALOGE("%s unknown command received: %d", __func__, cmd->cmd);
break;
}
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
out->offload_thread_blocked = false;
pthread_cond_signal(&out->cond);
if (send_callback && out->offload_callback) {
@@ -1356,7 +1370,7 @@
static int destroy_offload_callback_thread(struct stream_out *out)
{
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
stop_compressed_output_l(out);
send_offload_cmd_l(out, OFFLOAD_CMD_EXIT);
@@ -1804,7 +1818,7 @@
return 0;
}
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
if (!out->standby) {
if (adev->adm_deregister_stream)
adev->adm_deregister_stream(adev->adm_data, out->handle);
@@ -1893,7 +1907,7 @@
err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
if (err >= 0) {
val = atoi(value);
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
pthread_mutex_lock(&adev->lock);
/*
@@ -1957,7 +1971,7 @@
pthread_mutex_unlock(&adev->lock);
}
if (is_offload_usecase(out->usecase)) {
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
parse_compress_metadata(out, parms);
audio_extn_dts_create_state_notifier_node(out->usecase);
@@ -2113,7 +2127,7 @@
int snd_scard_state = get_snd_card_state(adev);
ssize_t ret = 0;
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
if (SND_CARD_STATE_OFFLINE == snd_scard_state) {
// increase written size during SSR to avoid mismatch
@@ -2258,7 +2272,7 @@
*dsp_frames = 0;
if (is_offload_usecase(out->usecase)) {
ssize_t ret = 0;
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
if (out->compr != NULL) {
ret = compress_get_tstamp(out->compr, (unsigned long *)dsp_frames,
&out->sample_rate);
@@ -2317,7 +2331,7 @@
int ret = -1;
unsigned long dsp_frames;
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
if (is_offload_usecase(out->usecase)) {
if (out->compr != NULL) {
@@ -2369,7 +2383,7 @@
struct stream_out *out = (struct stream_out *)stream;
ALOGV("%s", __func__);
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
out->offload_callback = callback;
out->offload_cookie = cookie;
pthread_mutex_unlock(&out->lock);
@@ -2383,7 +2397,7 @@
ALOGV("%s", __func__);
if (is_offload_usecase(out->usecase)) {
ALOGD("copl(%p):pause compress driver", out);
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PLAYING) {
struct audio_device *adev = out->dev;
int snd_scard_state = get_snd_card_state(adev);
@@ -2411,7 +2425,7 @@
if (is_offload_usecase(out->usecase)) {
ALOGD("copl(%p):resume compress driver", out);
status = 0;
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PAUSED) {
struct audio_device *adev = out->dev;
int snd_scard_state = get_snd_card_state(adev);
@@ -2436,7 +2450,7 @@
int status = -ENOSYS;
ALOGV("%s", __func__);
if (is_offload_usecase(out->usecase)) {
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
if (type == AUDIO_DRAIN_EARLY_NOTIFY)
status = send_offload_cmd_l(out, OFFLOAD_CMD_PARTIAL_DRAIN);
else
@@ -2452,7 +2466,7 @@
ALOGV("%s", __func__);
if (is_offload_usecase(out->usecase)) {
ALOGD("copl(%p):calling compress flush", out);
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
stop_compressed_output_l(out);
pthread_mutex_unlock(&out->lock);
ALOGD("copl(%p):out of compress flush", out);
@@ -2524,7 +2538,7 @@
return status;
}
- pthread_mutex_lock(&in->lock);
+ lock_input_stream(in);
if (!in->standby && in->is_st_session) {
ALOGD("%s: sound trigger pcm stop lab", __func__);
audio_extn_sound_trigger_stop_lab(in);
@@ -2569,7 +2583,7 @@
if (!parms)
goto error;
- pthread_mutex_lock(&in->lock);
+ lock_input_stream(in);
pthread_mutex_lock(&adev->lock);
err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_INPUT_SOURCE, value, sizeof(value));
@@ -2653,7 +2667,7 @@
int i, ret = -1;
int snd_scard_state = get_snd_card_state(adev);
- pthread_mutex_lock(&in->lock);
+ lock_input_stream(in);
if (in->is_st_session) {
ALOGVV(" %s: reading on st session bytes=%zu", __func__, bytes);
@@ -2753,7 +2767,7 @@
if (status != 0)
return status;
- pthread_mutex_lock(&in->lock);
+ lock_input_stream(in);
pthread_mutex_lock(&in->dev->lock);
if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) &&
in->enable_aec != enable &&
@@ -2821,6 +2835,7 @@
}
pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL);
+ pthread_mutex_init(&out->pre_lock, (const pthread_mutexattr_t *) NULL);
pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL);
if (devices == AUDIO_DEVICE_NONE)
@@ -3475,6 +3490,7 @@
devices, &in->stream, handle, source);
pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *) NULL);
+ pthread_mutex_init(&in->pre_lock, (const pthread_mutexattr_t *) NULL);
in->stream.common.get_sample_rate = in_get_sample_rate;
in->stream.common.set_sample_rate = in_set_sample_rate;
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 542a3f1..59d6a89 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -181,6 +181,7 @@
struct stream_out {
struct audio_stream_out stream;
pthread_mutex_t lock; /* see note below on mutex acquisition order */
+ pthread_mutex_t pre_lock; /* acquire before lock to avoid DOS by playback thread */
pthread_cond_t cond;
struct pcm_config config;
struct compr_config compr_config;
@@ -225,6 +226,7 @@
struct stream_in {
struct audio_stream_in stream;
pthread_mutex_t lock; /* see note below on mutex acquisition order */
+ pthread_mutex_t pre_lock; /* acquire before lock to avoid DOS by playback thread */
struct pcm_config config;
struct pcm *pcm;
int standby;