[vlc-devel] [PATCH] modules: split module sorting from probing

Alexandre Janniaux ajanni at videolabs.io
Mon Jul 20 10:58:02 CEST 2020


Hi,

This is quit neat. :)

I haven't reviewed yet but it can be really useful.

Regards,
--
Alexandre Janniaux
Videolabs

On Sat, Jul 18, 2020 at 10:47:49AM +0300, RĂ©mi Denis-Courmont wrote:
> This adds a separate function to determine the order in which modules
> should be probed. The vlc_module_load() function now only does the
> probing.
> ---
>  src/modules/modules.c | 190 ++++++++++++++++++++++++++----------------
>  1 file changed, 117 insertions(+), 73 deletions(-)
>
> diff --git a/src/modules/modules.c b/src/modules/modules.c
> index 700f1ca36b..702931f978 100644
> --- a/src/modules/modules.c
> +++ b/src/modules/modules.c
> @@ -94,10 +94,6 @@ const char *module_gettext (const module_t *m, const char *str)
>
>  static bool module_match_name(const module_t *m, const char *name, size_t len)
>  {
> -     /* Plugins with zero score must be matched explicitly. */
> -     if (len == 3 && strncasecmp("any", name, len) == 0)
> -         return m->i_score > 0;
> -
>       for (size_t i = 0; i < m->i_shortcuts; i++)
>            if (strncasecmp(m->pp_shortcuts[i], name, len) == 0
>             && m->pp_shortcuts[i][len] == '\0')
> @@ -106,6 +102,100 @@ static bool module_match_name(const module_t *m, const char *name, size_t len)
>       return false;
>  }
>
> +/**
> + * Finds the candidate modules for given criteria.
> + *
> + * All candidates modules having the specified capability and name will be
> + * sorted in decreasing order of priority and returned in a heap-allocated
> + * table.
> + *
> + * \param capability capability, i.e. class of module
> + * \param names string of comma-separated requested module shortcut names
> + * \param strict whether to exclude modules with no unmatching shortcut names
> + * \param modules storage location for the base address of a sorted table
> + *                of candidate modules [OUT]
> + * \param strict_matches storage location for the count of strictly matched
> + *                       modules (optional) [OUT]
> + * \return number of modules found or a strictly negative value on error
> + */
> +static
> +ssize_t vlc_module_match(const char *capability, const char *names,
> +                         bool strict, module_t ***restrict modules,
> +                         size_t *restrict strict_matches)
> +{
> +    module_t *const *tab;
> +    size_t total = module_list_cap(&tab, capability);
> +    module_t **unsorted = malloc(total * sizeof (*unsorted));
> +    module_t **sorted = malloc(total * sizeof (*sorted));
> +    size_t matches = 0;
> +
> +    *modules = sorted;
> +
> +    if (total > 0) {
> +        if (unlikely(unsorted == NULL || sorted == NULL)) {
> +            free(unsorted);
> +            free(sorted);
> +            return -1;
> +        }
> +        memcpy(unsorted, tab, total * sizeof (*unsorted));
> +    }
> +
> +    /* Go through the list of module shortcut names. */
> +    while (names[0] != '\0') {
> +        const char *shortcut = names;
> +        size_t slen = strcspn(names, ",");
> +
> +        names += slen;
> +        names += strspn(names, ",");
> +
> +        /* "none" matches nothing and ends the search */
> +        if (slen == 4 && strncasecmp("none", shortcut, 4) == 0) {
> +            total = 0;
> +            break;
> +        }
> +
> +        /* "any" matches everything with strictly positive score */
> +        if (slen == 3 && strncasecmp("any", shortcut, 3) == 0) {
> +            strict = false;
> +            break;
> +        }
> +
> +        for (size_t i = 0; i < total; i++) {
> +            module_t *cand = unsorted[i];
> +
> +            if (cand != NULL && module_match_name(cand, shortcut, slen)) {
> +                assert(matches < total);
> +                sorted[matches++] = cand;
> +                unsorted[i] = NULL;
> +            }
> +        }
> +    }
> +
> +    if (strict_matches != NULL)
> +        *strict_matches = matches;
> +
> +    if (!strict) {
> +        /* List remaining modules with strictly positive score. */
> +        for (size_t i = 0; i < total; i++) {
> +            module_t *cand = unsorted[i];
> +
> +            if (cand != NULL) {
> +                /* Modules are sorted by decreasing score, so there is no point
> +                 * carrying on after the first zero score is found.
> +                 */
> +                if (module_get_score(cand) <= 0)
> +                    break;
> +
> +                assert(matches < total);
> +                sorted[matches++] = cand;
> +            }
> +        }
> +    }
> +
> +    free(unsorted);
> +    return matches;
> +}
> +
>  static int module_load(vlc_logger_t *log, module_t *m,
>                         vlc_activate_t init, bool forced, va_list args)
>  {
> @@ -154,89 +244,43 @@ module_t *(vlc_module_load)(struct vlc_logger *log, const char *capability,
>          name = "any";
>
>      /* Find matching modules */
> -    module_t *const *tab;
> -    size_t total = module_list_cap(&tab, capability);
> -
> -    vlc_debug(log, "looking for %s module matching \"%s\": %zu candidates",
> -              capability, name, total);
> -    if (total == 0)
> -    {
> -        vlc_debug(log, "no %s modules", capability);
> -        return NULL;
> -    }
> +    module_t **mods;
> +    size_t strict_total;
> +    ssize_t total = vlc_module_match(capability, name, strict,
> +                                     &mods, &strict_total);
>
> -    module_t **mods = malloc(total * sizeof (*mods));
> -    if (unlikely(mods == NULL))
> +    if (unlikely(total < 0))
>          return NULL;
>
> -    memcpy(mods, tab, total * sizeof (*mods));
> +    vlc_debug(log, "looking for %s module matching \"%s\": %zd candidates",
> +              capability, name, total);
>
>      module_t *module = NULL;
>      va_list args;
>
>      va_start(args, probe);
> -    while (*name)
> -    {
> -        const char *shortcut = name;
> -        size_t slen = strcspn (name, ",");
> -
> -        name += slen;
> -        name += strspn (name, ",");
> -
> -        if (!strcasecmp ("none", shortcut))
> -            goto done;
>
> -        bool force = strict && strcasecmp ("any", shortcut);
> -        for (size_t i = 0; i < total; i++)
> -        {
> -            module_t *cand = mods[i];
> -            if (cand == NULL)
> -                continue; // module failed in previous iteration
> -            if (!module_match_name(cand, shortcut, slen))
> -                continue;
> -            mods[i] = NULL; // only try each module once at most...
> -
> -            int ret = module_load(log, cand, probe, force, args);
> -            switch (ret)
> -            {
> -                case VLC_SUCCESS:
> -                    module = cand;
> -                    /* fall through */
> -                case VLC_ETIMEOUT:
> -                    goto done;
> -            }
> +    for (size_t i = 0; i < (size_t)total; i++) {
> +        module_t *cand = mods[i];
> +        int ret = module_load(log, cand, probe, i < strict_total, args);
> +
> +        switch (ret) {
> +            case VLC_SUCCESS:
> +                vlc_debug(log, "using %s module \"%s\"", capability,
> +                          module_get_object(cand));
> +                module = cand;
> +                /* fall through */
> +            case VLC_ETIMEOUT:
> +                goto done;
>          }
>      }
>
> -    /* None of the shortcuts matched, fall back to any module */
> -    if (!strict)
> -    {
> -        for (size_t i = 0; i < total; i++)
> -        {
> -            module_t *cand = mods[i];
> -            if (cand == NULL || module_get_score (cand) <= 0)
> -                continue;
> -
> -            int ret = module_load(log, cand, probe, false, args);
> -            switch (ret)
> -            {
> -                case VLC_SUCCESS:
> -                    module = cand;
> -                    /* fall through */
> -                case VLC_ETIMEOUT:
> -                    goto done;
> -            }
> -        }
> -    }
> -done:
>      va_end (args);
> -    free(mods);
>
> -    if (module != NULL)
> -        vlc_debug(log, "using %s module \"%s\"", capability,
> -                  module_get_object (module));
> -    else
> -        vlc_debug(log, "no %s modules matched", capability);
> +    if (module == NULL)
> +done:   vlc_debug(log, "no %s modules matched", capability);
> +
> +    free(mods);
>      return module;
>  }
>
> --
> 2.28.0.rc0
>
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel


More information about the vlc-devel mailing list