OSDN Git Service

Fixed pcm_plug race condition
authorAbramo Bagnara <abramo@alsa-project.org>
Mon, 22 Jan 2001 16:07:11 +0000 (16:07 +0000)
committerAbramo Bagnara <abramo@alsa-project.org>
Mon, 22 Jan 2001 16:07:11 +0000 (16:07 +0000)
src/pcm/interval.c
src/pcm/interval.h
src/pcm/pcm_params.c
src/pcm/pcm_plug.c

index c7967bc..f4e7e0c 100644 (file)
@@ -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);
+}
+
index d78fe4e..3d57f3a 100644 (file)
@@ -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);
index 7b37fca..772d98b 100644 (file)
 #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, &params1, 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, &params1, 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 {
index 67f6b09..ebf7a52 100644 (file)
@@ -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);