[vlc-devel] [PATCH] modules: split module sorting from probing
RĂ©mi Denis-Courmont
remi at remlab.net
Sat Jul 18 09:47:49 CEST 2020
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
More information about the vlc-devel
mailing list