diff options
author | Abramo Bagnara <abramo@alsa-project.org> | 2001-01-22 16:07:11 +0000 |
---|---|---|
committer | Abramo Bagnara <abramo@alsa-project.org> | 2001-01-22 16:07:11 +0000 |
commit | c6f6c231c0b98b8bc4ed1b54da2ecc69a73bc52b (patch) | |
tree | f1a7e9bbf876c2b3a133e0021feceba816433c48 /src/pcm | |
parent | 5c84940c1f587782de2212fe3977bcc0dba0c8d0 (diff) | |
download | alsa-lib-c6f6c231c0b98b8bc4ed1b54da2ecc69a73bc52b.tar.gz |
Fixed pcm_plug race condition
Diffstat (limited to 'src/pcm')
-rw-r--r-- | src/pcm/interval.c | 54 | ||||
-rw-r--r-- | src/pcm/interval.h | 3 | ||||
-rw-r--r-- | src/pcm/pcm_params.c | 57 | ||||
-rw-r--r-- | src/pcm/pcm_plug.c | 11 |
4 files changed, 73 insertions, 52 deletions
diff --git a/src/pcm/interval.c b/src/pcm/interval.c index c7967bc6..f4e7e0cb 100644 --- a/src/pcm/interval.c +++ b/src/pcm/interval.c @@ -381,3 +381,57 @@ void interval_print(const interval_t *i, snd_output_t *out) i->min, i->max, i->openmax ? ')' : ']'); } + +void boundary_abs(int a, int adir, int *b, int *bdir) +{ + if (a < 0 || (a == 0 && adir < 0)) { + *b = -a; + *bdir = -adir; + } else { + *b = a; + *bdir = adir; + } +} + +void boundary_sub(int a, int adir, int b, int bdir, int *c, int *cdir) +{ + adir = adir < 0 ? -1 : (adir > 0 ? 1 : 0); + bdir = bdir < 0 ? -1 : (bdir > 0 ? 1 : 0); + *c = a - b; + *cdir = adir - bdir; + if (*cdir == -2) { + assert(*c > INT_MIN); + (*c)--; + } else if (*cdir == 2) { + assert(*c < INT_MAX); + (*c)++; + } +} + +int boundary_lt(unsigned int a, int adir, unsigned int b, int bdir) +{ + assert(a > 0 || adir >= 0); + assert(b > 0 || bdir >= 0); + if (adir < 0) { + a--; + adir = 1; + } else if (adir > 0) + adir = 1; + if (bdir < 0) { + b--; + bdir = 1; + } else if (bdir > 0) + bdir = 1; + return a < b || (a == b && adir < bdir); +} + +/* Return 1 if min is nearer to best than max */ +int boundary_nearer(int min, int mindir, int best, int bestdir, int max, int maxdir) +{ + int dmin, dmindir; + int dmax, dmaxdir; + boundary_sub(best, bestdir, min, mindir, &dmin, &dmindir); + boundary_sub(max, maxdir, best, bestdir, &dmax, &dmaxdir); + return boundary_lt(dmin, dmindir, dmax, dmaxdir); +} + diff --git a/src/pcm/interval.h b/src/pcm/interval.h index d78fe4e5..3d57f3a8 100644 --- a/src/pcm/interval.h +++ b/src/pcm/interval.h @@ -57,3 +57,6 @@ int interval_refine(interval_t *i, const interval_t *v); int interval_refine_first(interval_t *i); int interval_refine_last(interval_t *i); int interval_refine_set(interval_t *i, unsigned int val); +void boundary_sub(int a, int adir, int b, int bdir, int *c, int *cdir); +int boundary_lt(unsigned int a, int adir, unsigned int b, int bdir); +int boundary_nearer(int min, int mindir, int best, int bestdir, int max, int maxdir); diff --git a/src/pcm/pcm_params.c b/src/pcm/pcm_params.c index 7b37fcac..772d98b2 100644 --- a/src/pcm/pcm_params.c +++ b/src/pcm/pcm_params.c @@ -25,53 +25,6 @@ #include "interval.h" #include "mask.h" -static void approx_sub(int a, int adir, - int b, int bdir, - int *c, int *cdir) -{ - adir = adir < 0 ? -1 : (adir > 0 ? 1 : 0); - bdir = bdir < 0 ? -1 : (bdir > 0 ? 1 : 0); - *c = a - b; - *cdir = adir - bdir; - if (*cdir == -2) { - assert(*c > INT_MIN); - (*c)--; - } else if (*cdir == 2) { - assert(*c < INT_MAX); - (*c)++; - } -} - -static int approx_lt(unsigned int a, int adir, - unsigned int b, int bdir) -{ - assert(a > 0 || adir >= 0); - assert(b > 0 || bdir >= 0); - if (adir < 0) { - a--; - adir = 1; - } else if (adir > 0) - adir = 1; - if (bdir < 0) { - b--; - bdir = 1; - } else if (bdir > 0) - bdir = 1; - return a < b || (a == b && adir < bdir); -} - -/* Return 1 if min is nearer to best than max */ -static int approx_nearer(int min, int mindir, - int best, int bestdir, - int max, int maxdir) -{ - int dmin, dmindir; - int dmax, dmaxdir; - approx_sub(best, bestdir, min, mindir, &dmin, &dmindir); - approx_sub(max, maxdir, best, bestdir, &dmax, &dmaxdir); - return approx_lt(dmin, dmindir, dmax, dmaxdir); -} - static inline int hw_is_mask(int var) { return var >= SND_PCM_HW_PARAM_FIRST_MASK && @@ -771,7 +724,7 @@ int snd_pcm_hw_param_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, max = snd_pcm_hw_param_max(pcm, ¶ms1, var, max, &maxdir); if (max < 0) goto _end; - if (approx_nearer(max, maxdir, best, valdir, min, mindir)) { + if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) { *params = params1; last = 1; } @@ -813,7 +766,7 @@ int snd_pcm_hw_param_next(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, /* FIXME */ if (best > INT_MAX) best = INT_MAX; - approx_sub(val, valdir, best, bestdir, &diff, &diffdir); + boundary_sub(val, valdir, best, bestdir, &diff, &diffdir); if (diff < 0 || (diff == 0 && diffdir < 0)) { min = best - diff; mindir = bestdir - diffdir; @@ -839,7 +792,7 @@ int snd_pcm_hw_param_next(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, max = snd_pcm_hw_param_max(pcm, ¶ms1, var, max, &maxdir); if (max < 0) goto _end; - if (approx_nearer(max, maxdir, best, bestdir, min, mindir)) { + if (boundary_nearer(max, maxdir, best, bestdir, min, mindir)) { *params = params1; last = 1; } @@ -869,13 +822,13 @@ void snd_pcm_hw_param_near_minmax(snd_pcm_t *pcm, { snd_pcm_hw_params_t tmp; int err; - if (!approx_lt(min, *mindir, max, *maxdir)) { + if (!boundary_lt(min, *mindir, max, *maxdir)) { snd_pcm_hw_param_near(pcm, params, var, min, mindir); return; } tmp = *params; min = snd_pcm_hw_param_near(pcm, &tmp, var, min, mindir); - if (approx_lt(min, *mindir, max, *maxdir)) { + if (boundary_lt(min, *mindir, max, *maxdir)) { tmp = *params; max = snd_pcm_hw_param_near(pcm, &tmp, var, max, maxdir); } else { diff --git a/src/pcm/pcm_plug.c b/src/pcm/pcm_plug.c index 67f6b097..ebf7a526 100644 --- a/src/pcm/pcm_plug.c +++ b/src/pcm/pcm_plug.c @@ -488,6 +488,8 @@ static int snd_pcm_plug_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, interval_t t; const interval_t *sbuffer_size; const interval_t *srate, *crate; + unsigned int rate_min, srate_min; + int rate_mindir, srate_mindir; format_mask = snd_pcm_hw_param_value_mask(params, SND_PCM_HW_PARAM_FORMAT); sformat_mask = snd_pcm_hw_param_value_mask(sparams, @@ -512,6 +514,15 @@ static int snd_pcm_plug_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, if (err < 0) return err; + /* This is a temporary hack, waiting for a better solution */ + rate_min = snd_pcm_hw_param_value_min(params, SND_PCM_HW_PARAM_RATE, &rate_mindir); + srate_min = snd_pcm_hw_param_value_min(sparams, SND_PCM_HW_PARAM_RATE, &srate_mindir); + if (rate_min == srate_min && srate_mindir > rate_mindir) { + err = _snd_pcm_hw_param_min(params, SND_PCM_HW_PARAM_RATE, srate_min, srate_mindir); + if (err < 0) + return err; + } + sbuffer_size = snd_pcm_hw_param_value_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE); crate = snd_pcm_hw_param_value_interval(params, SND_PCM_HW_PARAM_RATE); srate = snd_pcm_hw_param_value_interval(sparams, SND_PCM_HW_PARAM_RATE); |