summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2015-06-19 16:30:44 -0700
committerArne Coucheron <arco68@gmail.com>2016-05-11 00:12:22 +0200
commit52a8a8b2e29caa33b837d44ae363e05339eff417 (patch)
tree9500d0ad0a410ea1c3313e4929195c1ebfc57c2b
parent09948fc8c8b267244e0f7086ed7e3016eedc62b6 (diff)
downloadhardware_qcom_audio-52a8a8b2e29caa33b837d44ae363e05339eff417.tar.gz
hardware_qcom_audio-52a8a8b2e29caa33b837d44ae363e05339eff417.tar.bz2
hardware_qcom_audio-52a8a8b2e29caa33b837d44ae363e05339eff417.zip
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. Bug: 21880828. Change-Id: I99fcbb94da8f918f63b31e5bf713f3456a735869
-rw-r--r--hal/audio_hw.c52
-rw-r--r--hal/audio_hw.h2
2 files changed, 35 insertions, 19 deletions
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 308d3e27..4eeb4d4d 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -961,6 +961,20 @@ error_config:
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)
{
@@ -1004,7 +1018,7 @@ static void *offload_thread_loop(void *context)
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;
@@ -1067,7 +1081,7 @@ static void *offload_thread_loop(void *context)
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) {
@@ -1098,7 +1112,7 @@ static int create_offload_callback_thread(struct stream_out *out)
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);
@@ -1484,7 +1498,7 @@ static int out_standby(struct audio_stream *stream)
return 0;
}
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
if (!out->standby) {
pthread_mutex_lock(&adev->lock);
out->standby = true;
@@ -1597,7 +1611,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
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);
/*
@@ -1665,7 +1679,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
pthread_mutex_unlock(&adev->lock);
}
if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
parse_compress_metadata(out, parms);
pthread_mutex_unlock(&out->lock);
}
@@ -1779,7 +1793,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
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) {
if (out->pcm) {
@@ -1886,7 +1900,7 @@ static int out_get_render_position(const struct audio_stream_out *stream,
if ((out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) && (dsp_frames != NULL)) {
ssize_t ret = 0;
*dsp_frames = 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);
@@ -1935,7 +1949,7 @@ static int out_get_presentation_position(const struct audio_stream_out *stream,
int ret = -1;
unsigned long dsp_frames;
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
if (out->compr != NULL) {
@@ -1979,7 +1993,7 @@ static int out_set_callback(struct audio_stream_out *stream,
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);
@@ -1992,7 +2006,7 @@ static int out_pause(struct audio_stream_out* stream)
int status = -ENOSYS;
ALOGV("%s", __func__);
if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
- 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);
@@ -2014,7 +2028,7 @@ static int out_resume(struct audio_stream_out* stream)
ALOGV("%s", __func__);
if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
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);
@@ -2035,7 +2049,7 @@ static int out_drain(struct audio_stream_out* stream, audio_drain_type_t type )
int status = -ENOSYS;
ALOGV("%s", __func__);
if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
- 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
@@ -2050,7 +2064,7 @@ static int out_flush(struct audio_stream_out* stream)
struct stream_out *out = (struct stream_out *)stream;
ALOGV("%s", __func__);
if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
- pthread_mutex_lock(&out->lock);
+ lock_output_stream(out);
stop_compressed_output_l(out);
pthread_mutex_unlock(&out->lock);
return 0;
@@ -2113,7 +2127,6 @@ static int in_standby(struct audio_stream *stream)
ALOGD("%s: enter: stream (%p) usecase(%d: %s)", __func__,
stream, in->usecase, use_case_table[in->usecase]);
-
if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
/* Ignore standby in case of voip call because the voip input
* stream is closed in adev_close_input_stream()
@@ -2122,7 +2135,7 @@ static int in_standby(struct audio_stream *stream)
return status;
}
- pthread_mutex_lock(&in->lock);
+ lock_input_stream(in);
if (!in->standby) {
pthread_mutex_lock(&adev->lock);
in->standby = true;
@@ -2158,7 +2171,7 @@ static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
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));
@@ -2242,7 +2255,7 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
int i, ret = -1;
int snd_scard_state = get_snd_card_state(adev);
- pthread_mutex_lock(&in->lock);
+ lock_input_stream(in);
if (in->pcm) {
if(SND_CARD_STATE_OFFLINE == snd_scard_state) {
@@ -2328,7 +2341,7 @@ static int add_remove_audio_effect(const struct audio_stream *stream,
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 &&
@@ -2949,6 +2962,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev,
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 71831692..8b4b5f0d 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -144,6 +144,7 @@ struct offload_cmd {
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;
@@ -183,6 +184,7 @@ struct stream_out {
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 capture thread */
struct pcm_config config;
struct pcm *pcm;
int standby;