[vlc-commits] [Git][videolan/vlc][master] 8 commits: rcu: add initial RCU implementation and docs

Rémi Denis-Courmont (@Courmisch) gitlab at videolan.org
Tue Nov 30 13:27:29 UTC 2021



Rémi Denis-Courmont pushed to branch master at VideoLAN / VLC


Commits:
e2649592 by Rémi Denis-Courmont at 2021-11-30T13:10:36+00:00
rcu: add initial RCU implementation and docs

See built-in Doxygen for details.

- - - - -
e8700cbd by Rémi Denis-Courmont at 2021-11-30T13:10:36+00:00
messages: remove bogus assignment

- - - - -
fc91bb73 by Rémi Denis-Courmont at 2021-11-30T13:10:36+00:00
messages: use RCU for switching log backend

...instead of read-write lock. This provides for lock-free wait-free
log output, which is orders of magnitude more frequent than switching
log backend.

- - - - -
6911b612 by Rémi Denis-Courmont at 2021-11-30T13:10:36+00:00
config: factor string item setter

This factors the common code to set a string variable value. This also
makes the handling of the empty string consistent across all paths.

- - - - -
51366d08 by Rémi Denis-Courmont at 2021-11-30T13:10:36+00:00
config: simplify expressions

No functional changes.

- - - - -
05d1bc33 by Rémi Denis-Courmont at 2021-11-30T13:10:36+00:00
config: use RCU for string items

This makes config_GetStr() lock-less.

- - - - -
f57ddf14 by Rémi Denis-Courmont at 2021-11-30T13:10:36+00:00
config: remove dead code

- - - - -
dbbe239f by Rémi Denis-Courmont at 2021-11-30T13:10:36+00:00
config: convert R/W lock to mutex

The lock is no longer taken for reading ever, so it is equivalent to a
mutex. In fact, the lock is only needed to prevent concurrent writes
to the same config_item_t::value.

- - - - -


9 changed files:

- src/Makefile.am
- src/config/configuration.h
- src/config/core.c
- src/config/file.c
- src/misc/messages.c
- + src/misc/rcu.c
- + src/misc/rcu.h
- src/modules/cache.c
- src/modules/entry.c


Changes:

=====================================
src/Makefile.am
=====================================
@@ -371,6 +371,8 @@ libvlccore_la_SOURCES = \
 	misc/interrupt.h \
 	misc/interrupt.c \
 	misc/keystore.c \
+	misc/rcu.h \
+	misc/rcu.c \
 	misc/renderer_discovery.c \
 	misc/threads.c \
 	misc/cpu.c \


=====================================
src/config/configuration.h
=====================================
@@ -29,6 +29,7 @@ struct vlc_param {
     union {
         _Atomic int64_t i; /**< Current value (if integer or boolean) */
         _Atomic float f; /**< Current value (if floating point) */
+        char *_Atomic str; /**< Current value (if character string) */
     } value;
 
     struct vlc_plugin_t *owner;
@@ -47,6 +48,8 @@ struct vlc_param {
  */
 struct vlc_param *vlc_param_Find(const char *name);
 
+int vlc_param_SetString(struct vlc_param *param, const char *value);
+
 int  config_AutoSaveConfigFile( vlc_object_t * );
 
 void config_Free(struct vlc_param *, size_t);
@@ -60,7 +63,7 @@ bool config_PrintHelp (vlc_object_t *);
 int config_SortConfig (void);
 void config_UnsortConfig (void);
 
-extern vlc_rwlock_t config_lock;
+extern vlc_mutex_t config_lock;
 extern _Atomic bool config_dirty;
 
 bool config_IsSafe (const char *);


=====================================
src/config/core.c
=====================================
@@ -37,8 +37,9 @@
 
 #include "configuration.h"
 #include "modules/modules.h"
+#include "misc/rcu.h"
 
-vlc_rwlock_t config_lock = VLC_STATIC_RWLOCK;
+vlc_mutex_t config_lock = VLC_STATIC_MUTEX;
 atomic_bool config_dirty = ATOMIC_VAR_INIT(false);
 
 static inline char *strdupnull (const char *src)
@@ -75,16 +76,6 @@ bool config_IsSafe( const char *name )
     return (param != NULL) ? param->safe : false;
 }
 
-static module_config_t * config_FindConfigChecked( const char *psz_name )
-{
-    module_config_t *p_config = config_FindConfig( psz_name );
-#ifndef NDEBUG
-    if (p_config == NULL)
-        fprintf(stderr, "Unknown vlc configuration variable named %s\n", psz_name);
-#endif
-    return p_config;
-}
-
 int64_t config_GetInt(const char *name)
 {
     const struct vlc_param *param = vlc_param_Find(name);
@@ -107,43 +98,51 @@ float config_GetFloat(const char *name)
     return atomic_load_explicit(&param->value.f, memory_order_relaxed);
 }
 
-char *config_GetPsz(const char *psz_name)
+char *config_GetPsz(const char *name)
 {
-    module_config_t *p_config = config_FindConfigChecked( psz_name );
+    const struct vlc_param *param = vlc_param_Find(name);
+    char *str;
 
     /* sanity checks */
-    assert(p_config != NULL);
-    assert(IsConfigStringType (p_config->i_type));
+    assert(param != NULL);
+    assert(IsConfigStringType(param->item.i_type));
 
     /* return a copy of the string */
-    vlc_rwlock_rdlock (&config_lock);
-    char *psz_value = strdupnull (p_config->value.psz);
-    vlc_rwlock_unlock (&config_lock);
+    vlc_rcu_read_lock();
+    str = atomic_load_explicit(&param->value.str, memory_order_acquire);
+    if (str != NULL)
+        str = strdup(str);
+    vlc_rcu_read_unlock();
+    return str;
+}
+
+int vlc_param_SetString(struct vlc_param *param, const char *value)
+{
+    char *str = NULL, *oldstr;
 
-    return psz_value;
+    assert(param != NULL);
+    assert(IsConfigStringType(param->item.i_type));
+
+    if (value != NULL && value[0] != '\0') {
+        str = strdup(value);
+        if (unlikely(str == NULL))
+            return -1;
+    }
+
+    oldstr = atomic_load_explicit(&param->value.str, memory_order_relaxed);
+    atomic_store_explicit(&param->value.str, str, memory_order_release);
+    param->item.value.psz = str;
+    vlc_rcu_synchronize();
+    free(oldstr);
+    return 0;
 }
 
 void config_PutPsz(const char *psz_name, const char *psz_value)
 {
-    module_config_t *p_config = config_FindConfigChecked( psz_name );
-
-    /* sanity checks */
-    assert(p_config != NULL);
-    assert(IsConfigStringType(p_config->i_type));
-
-    char *str, *oldstr;
-    if ((psz_value != NULL) && *psz_value)
-        str = strdup (psz_value);
-    else
-        str = NULL;
-
-    vlc_rwlock_wrlock (&config_lock);
-    oldstr = (char *)p_config->value.psz;
-    p_config->value.psz = str;
-    vlc_rwlock_unlock (&config_lock);
+    vlc_mutex_lock(&config_lock);
+    vlc_param_SetString(vlc_param_Find(psz_name), psz_value);
+    vlc_mutex_unlock(&config_lock);
     atomic_store_explicit(&config_dirty, true, memory_order_release);
-
-    free (oldstr);
 }
 
 void config_PutInt(const char *name, int64_t i_value)
@@ -161,9 +160,9 @@ void config_PutInt(const char *name, int64_t i_value)
         i_value = p_config->max.i;
 
     atomic_store_explicit(&param->value.i, i_value, memory_order_relaxed);
-    vlc_rwlock_wrlock (&config_lock);
+    vlc_mutex_lock(&config_lock);
     p_config->value.i = i_value;
-    vlc_rwlock_unlock (&config_lock);
+    vlc_mutex_unlock(&config_lock);
     atomic_store_explicit(&config_dirty, true, memory_order_release);
 }
 
@@ -185,9 +184,9 @@ void config_PutFloat(const char *name, float f_value)
         f_value = p_config->max.f;
 
     atomic_store_explicit(&param->value.f, f_value, memory_order_relaxed);
-    vlc_rwlock_wrlock (&config_lock);
+    vlc_mutex_lock(&config_lock);
     p_config->value.f = f_value;
-    vlc_rwlock_unlock (&config_lock);
+    vlc_mutex_unlock(&config_lock);
     atomic_store_explicit(&config_dirty, true, memory_order_release);
 }
 
@@ -474,11 +473,13 @@ void config_Free(struct vlc_param *tab, size_t confsize)
 {
     for (size_t j = 0; j < confsize; j++)
     {
-        module_config_t *p_item = &tab[j].item;
+        struct vlc_param *param = &tab[j];
+        module_config_t *p_item = &param->item;
 
         if (IsConfigStringType (p_item->i_type))
         {
-            free (p_item->value.psz);
+            free(atomic_load_explicit(&param->value.str,
+                                      memory_order_relaxed));
             if (p_item->list_count)
                 free (p_item->list.psz);
         }
@@ -491,7 +492,7 @@ void config_Free(struct vlc_param *tab, size_t confsize)
 
 void config_ResetAll(void)
 {
-    vlc_rwlock_wrlock (&config_lock);
+    vlc_mutex_lock(&config_lock);
     for (vlc_plugin_t *p = vlc_plugins; p != NULL; p = p->next)
     {
         for (size_t i = 0; i < p->conf.size; i++ )
@@ -514,13 +515,9 @@ void config_ResetAll(void)
             }
             else
             if (IsConfigStringType (p_config->i_type))
-            {
-                free ((char *)p_config->value.psz);
-                p_config->value.psz =
-                        strdupnull (p_config->orig.psz);
-            }
+                vlc_param_SetString(param, p_config->orig.psz);
         }
     }
-    vlc_rwlock_unlock (&config_lock);
+    vlc_mutex_lock(&config_lock);
     atomic_store_explicit(&config_dirty, true, memory_order_release);
 }


=====================================
src/config/file.c
=====================================
@@ -47,6 +47,7 @@
 
 #include "configuration.h"
 #include "modules/modules.h"
+#include "misc/rcu.h"
 
 static inline char *strdupnull (const char *src)
 {
@@ -185,7 +186,7 @@ int config_LoadConfigFile( vlc_object_t *p_this )
     locale_t loc = newlocale (LC_NUMERIC_MASK, "C", NULL);
     locale_t baseloc = uselocale (loc);
 
-    vlc_rwlock_wrlock (&config_lock);
+    vlc_mutex_lock(&config_lock);
     while ((linelen = getline (&line, &bufsize, file)) != -1)
     {
         line[linelen - 1] = '\0'; /* trim newline */
@@ -252,12 +253,11 @@ int config_LoadConfigFile( vlc_object_t *p_this )
             }
 
             default:
-                free (item->value.psz);
-                item->value.psz = strdupnull (psz_option_value);
+                vlc_param_SetString(param, psz_option_value);
                 break;
         }
     }
-    vlc_rwlock_unlock (&config_lock);
+    vlc_mutex_unlock(&config_lock);
     free (line);
 
     if (ferror (file))
@@ -391,9 +391,6 @@ int config_SaveConfigFile (vlc_object_t *p_this)
         }
     }
 
-    /* Configuration lock must be taken before vlcrc serializer below. */
-    vlc_rwlock_rdlock (&config_lock);
-
     /* The temporary configuration file is per-PID. Therefore this function
      * should be serialized against itself within a given process. */
     static vlc_mutex_t lock = VLC_STATIC_MUTEX;
@@ -402,7 +399,6 @@ int config_SaveConfigFile (vlc_object_t *p_this)
     int fd = vlc_open (temporary, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR);
     if (fd == -1)
     {
-        vlc_rwlock_unlock (&config_lock);
         vlc_mutex_unlock (&lock);
         goto error;
     }
@@ -411,7 +407,6 @@ int config_SaveConfigFile (vlc_object_t *p_this)
     {
         msg_Err (p_this, "cannot create configuration file: %s",
                  vlc_strerror_c(errno));
-        vlc_rwlock_unlock (&config_lock);
         vlc_close (fd);
         vlc_mutex_unlock (&lock);
         goto error;
@@ -431,9 +426,7 @@ int config_SaveConfigFile (vlc_object_t *p_this)
     locale_t loc = newlocale (LC_NUMERIC_MASK, "C", NULL);
     locale_t baseloc = uselocale (loc);
 
-    /* We would take the config lock here. But this would cause a lock
-     * inversion with the serializer above and config_AutoSaveConfigFile().
-    vlc_rwlock_rdlock (&config_lock);*/
+    vlc_rcu_read_lock(); /* preserve string values */
 
     /* Look for the selected module, if NULL then save everything */
     for (vlc_plugin_t *p = vlc_plugins; p != NULL; p = p->next)
@@ -482,20 +475,23 @@ int config_SaveConfigFile (vlc_object_t *p_this)
             }
             else
             {
-                const char *psz_value = p_item->value.psz;
-                bool modified;
-
-                assert (IsConfigStringType (p_item->i_type));
-
-                modified = !!strcmp (psz_value ? psz_value : "",
-                                     p_item->orig.psz ? p_item->orig.psz : "");
-                config_Write (file, p_item->psz_text, N_("string"),
-                              !modified, p_item->psz_name, "%s",
-                              psz_value ? psz_value : "");
+                const char *val = atomic_load_explicit(&param->value.str,
+                                                       memory_order_relaxed);
+                const char *orig = p_item->orig.psz;
+
+                if (val == NULL)
+                    val = "";
+                if (orig == NULL)
+                    orig = "";
+
+                assert(IsConfigStringType(p_item->i_type));
+                config_Write(file, p_item->psz_text, N_("string"),
+                             strcmp(val, orig) == 0, p_item->psz_name, "%s",
+                             val);
             }
         }
     }
-    vlc_rwlock_unlock (&config_lock);
+    vlc_rcu_read_unlock();
 
     if (loc != (locale_t)0)
     {


=====================================
src/misc/messages.c
=====================================
@@ -40,6 +40,7 @@
 #include <vlc_interface.h>
 #include <vlc_charset.h>
 #include <vlc_modules.h>
+#include "rcu.h"
 #include "../libvlc.h"
 
 static void vlc_LogSpam(vlc_object_t *obj)
@@ -303,9 +304,8 @@ static struct vlc_logger discard_log = { &discard_ops };
  * A message log that can be redirected live.
  */
 struct vlc_logger_switch {
-    struct vlc_logger *backend;
+    struct vlc_logger *_Atomic backend;
     struct vlc_logger frontend;
-    vlc_rwlock_t lock;
 };
 
 static void vlc_vaLogSwitch(void *d, int type, const vlc_log_t *item,
@@ -316,10 +316,10 @@ static void vlc_vaLogSwitch(void *d, int type, const vlc_log_t *item,
         container_of(logger, struct vlc_logger_switch, frontend);
     struct vlc_logger *backend;
 
-    vlc_rwlock_rdlock(&logswitch->lock);
-    backend = logswitch->backend;
+    vlc_rcu_read_lock();
+    backend = atomic_load_explicit(&logswitch->backend, memory_order_acquire);
     backend->ops->log(backend, type, item, format, ap);
-    vlc_rwlock_unlock(&logswitch->lock);
+    vlc_rcu_read_unlock();
 }
 
 static void vlc_LogSwitchClose(void *d)
@@ -327,11 +327,10 @@ static void vlc_LogSwitchClose(void *d)
     struct vlc_logger *logger = d;
     struct vlc_logger_switch *logswitch =
         container_of(logger, struct vlc_logger_switch, frontend);
-    struct vlc_logger *backend = logswitch->backend;
+    struct vlc_logger *backend = atomic_load_explicit(&logswitch->backend,
+                                                      memory_order_relaxed);
 
-    logswitch->backend = &discard_log;
     backend->ops->destroy(backend);
-
     free(logswitch);
 }
 
@@ -351,11 +350,9 @@ static void vlc_LogSwitch(vlc_logger_t *logger, vlc_logger_t *new_logger)
     if (new_logger == NULL)
         new_logger = &discard_log;
 
-    vlc_rwlock_wrlock(&logswitch->lock);
-    old_logger = logswitch->backend;
-    logswitch->backend = new_logger;
-    vlc_rwlock_unlock(&logswitch->lock);
-
+    old_logger = atomic_exchange_explicit(&logswitch->backend, new_logger,
+                                          memory_order_acq_rel);
+    vlc_rcu_synchronize();
     old_logger->ops->destroy(old_logger);
 }
 
@@ -366,8 +363,7 @@ static struct vlc_logger *vlc_LogSwitchCreate(void)
         return NULL;
 
     logswitch->frontend.ops = &switch_ops;
-    logswitch->backend = &discard_log;
-    vlc_rwlock_init(&logswitch->lock);
+    atomic_init(&logswitch->backend, &discard_log);
     return &logswitch->frontend;
 }
 


=====================================
src/misc/rcu.c
=====================================
@@ -0,0 +1,119 @@
+/**
+ * \file rcu.c Read-Copy-Update (RCU) definitions
+ * \ingroup rcu
+ */
+/*****************************************************************************
+ * Copyright © 2021 Rémi Denis-Courmont
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <stdint.h>
+#include <vlc_common.h>
+#include <vlc_atomic.h>
+#include "rcu.h"
+
+struct vlc_rcu_generation {
+    atomic_uintptr_t readers;
+    atomic_uint writer;
+};
+
+struct vlc_rcu_thread {
+    struct vlc_rcu_generation *generation;
+    uintptr_t recursion;
+};
+
+static _Thread_local struct vlc_rcu_thread current;
+
+bool vlc_rcu_read_held(void)
+{
+    const struct vlc_rcu_thread *const self = ¤t;
+
+    return self->recursion > 0;
+}
+
+static struct vlc_rcu_generation *_Atomic generation;
+
+void vlc_rcu_read_lock(void)
+{
+    struct vlc_rcu_thread *const self = ¤t;
+    struct vlc_rcu_generation *gen;
+
+    if (self->recursion++ > 0)
+        return; /* recursion: nothing to do */
+
+    assert(self->generation == NULL);
+    gen = atomic_load_explicit(&generation, memory_order_acquire);
+    self->generation = gen;
+    atomic_fetch_add_explicit(&gen->readers, 1, memory_order_relaxed);
+}
+
+void vlc_rcu_read_unlock(void)
+{
+    struct vlc_rcu_thread *const self = ¤t;
+    struct vlc_rcu_generation *gen;
+
+    assert(vlc_rcu_read_held());
+
+    if (--self->recursion > 0)
+        return; /* recursion: nothing to do */
+
+    gen = self->generation;
+    self->generation = NULL;
+
+    uintptr_t readers = atomic_fetch_sub_explicit(&gen->readers, 1,
+                                                  memory_order_relaxed);
+    if (readers == 0)
+        vlc_assert_unreachable();
+    if (readers > 1)
+        return; /* Other reader threads remain: nothing to do */
+
+    if (unlikely(atomic_exchange_explicit(&gen->writer, 0,
+                                          memory_order_release)))
+        vlc_atomic_notify_one(&gen->writer); /* Last reader wakes writer up */
+}
+
+static vlc_mutex_t writer_lock = VLC_STATIC_MUTEX;
+static struct vlc_rcu_generation gens[2];
+static struct vlc_rcu_generation *_Atomic generation = &gens[0];
+
+void vlc_rcu_synchronize(void)
+{
+    struct vlc_rcu_generation *gen;
+    size_t idx;
+
+    assert(!vlc_rcu_read_held()); /* cannot wait for thyself */
+    vlc_mutex_lock(&writer_lock);
+
+    /* Start a new generation for (and synchronise with) future readers */
+    gen = atomic_load_explicit(&generation, memory_order_relaxed);
+    idx = gen - gens;
+    idx = (idx + 1) % ARRAY_SIZE(gens);
+    atomic_store_explicit(&generation, &gens[idx], memory_order_release);
+
+    /* Let old generation readers know that we are waiting for them. */ 
+    atomic_exchange_explicit(&gen->writer, 1, memory_order_acquire);
+
+    while (atomic_load_explicit(&gen->readers, memory_order_relaxed) > 0)
+        vlc_atomic_wait(&gen->writer, 1);
+
+    atomic_store_explicit(&gen->writer, 0, memory_order_relaxed);
+    vlc_mutex_unlock(&writer_lock);
+}


=====================================
src/misc/rcu.h
=====================================
@@ -0,0 +1,116 @@
+/**
+ * \file rcu.h Read-Copy-Update (RCU) declarations
+ * \ingroup rcu
+ */
+/*****************************************************************************
+ * Copyright © 2021 Rémi Denis-Courmont
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef VLC_RCU_H_
+#define VLC_RCU_H_
+
+#include <stdatomic.h>
+
+/**
+ * \defgroup rcu Read-Copy-Update synchronisation
+ * \ingroup threads
+ * The Read-Copy-Update (RCU) mechanism is a paradigm of memory synchronisation
+ * first popularised by the Linux kernel.
+ * It is essentially a mean to safely use atomic pointers, without encountering
+ * use-after-free and other lifecycle bugs.
+ *
+ * It is an advantageous substitute for
+ * the classic reader/writer lock with the following notable differences:
+ * - The read side is completely lock-free and wait-free.
+ * - The write side is guaranteed to make forward progress even if there are
+ *   perpetually active readers, provided that all read sides are each
+ *   individually finitely long.
+ * - The protected data consists of a single atomic object,
+ *   typically an atomic pointer
+ *   (not to be confused with a pointer to an atomic object).
+ * - There is no synchronisation object. RCU maintains its state globally,
+ *   and with a modicum of per-thread state.
+ *
+ * The practical use of RCU differs from reader/writer lock in the following
+ * ways:
+ * - There is no synchronisation object, so there are no needs for
+ *   initialisation and destruction.
+ * - The directly protected objects are atom, so they must be accessed with
+ *   atomic type-generics. Specifically:
+ *   - Objects are read with atomic load-acquire.
+ *   - Objects are written with atomic store-release.
+ * - There are no writer lock and unlock functions. Instead there is a
+ *   synchronisation function, vlc_rcu_synchronize(), which waits for all
+ *   earlier read-side critical sections to complete.
+ * - Synchronisation between concurrent writers is not provided. If multiple
+ *   writers can race against each other, a separate mutual exclusion lock
+ *   for interlocking.
+ *
+ * @{
+ */
+
+/**
+ * Begins a read-side RCU critical section.
+ *
+ * This function marks the beginning of a read-side RCU critical section..
+ * For the duration of the critical section, RCU-protected data is guaranteed
+ * to remain valid, although it might be slightly stale.
+ *
+ * To access RCU-protect data, an atomic load-acquire should be used.
+ *
+ * \note Read-side RCU critical section can be nested.
+ */
+void vlc_rcu_read_lock(void);
+
+/**
+ * Ends a read-side RCU critical section.
+ *
+ * This function marks the end of a read-side RCU critical section. After this
+ * function is called, RCU-protected data may be destroyed and can no longer
+ * be accessed safely.
+ *
+ * \note In the case of nested critical sections, this function notionally ends
+ * the inner-most critical section. In practice, this makes no differences, as
+ * the calling thread remains in a critical section until the number of
+ * vlc_rcu_read_unlock() calls equals that of vlc_rcu_read_lock() calls.
+ */
+void vlc_rcu_read_unlock(void);
+
+/**
+ * Checks if the thread is in an read-side RCU critical section.
+ *
+ * This function checks if the thread is in a middle of one or more read-side
+ * RCU critical section(s). It has no side effects and is primarily meant for
+ * self-debugging.
+ *
+ * \retval true the calling thread is in a read-side RCU critical section.
+ * \retval false the calling thread is not in a read-side RCU critical section.
+ */
+VLC_USED
+bool vlc_rcu_read_held(void);
+
+/**
+ * Waits for completion of earlier read-side RCU critical section.
+ *
+ * This functions waits until all read-side RCU critical sections that had
+ * begun before to complete. Then it is safe to release resources associated
+ * with the earlier value(s) of any RCU-protected atomic object.
+ */
+void vlc_rcu_synchronize(void);
+
+/** @} */
+#endif /* !VLC_RCU_H_ */


=====================================
src/modules/cache.c
=====================================
@@ -200,7 +200,8 @@ static int vlc_cache_load_config(struct vlc_param *param, block_t *file)
         const char *psz;
         LOAD_STRING(psz);
         cfg->orig.psz = (char *)psz;
-        cfg->value.psz = (psz != NULL) ? strdup (cfg->orig.psz) : NULL;
+        atomic_init(&param->value.str, NULL);
+        vlc_param_SetString(param, psz);
 
         if (cfg->list_count)
             cfg->list.psz = xmalloc (cfg->list_count * sizeof (char *));


=====================================
src/modules/entry.c
=====================================
@@ -169,6 +169,8 @@ static struct vlc_param *vlc_config_create(vlc_plugin_t *plugin, int type)
         item->max.f = FLT_MAX;
         item->min.f = -FLT_MAX;
     }
+    else
+        atomic_init(&param->value.str, NULL);
     item->i_type = type;
 
     if (CONFIG_ITEM(type))
@@ -347,8 +349,8 @@ static int vlc_plugin_desc_cb(void *ctx, void *tgt, int propid, ...)
             if (IsConfigStringType (item->i_type))
             {
                 const char *value = va_arg (ap, const char *);
-                item->value.psz = value ? strdup (value) : NULL;
                 item->orig.psz = (char *)value;
+                vlc_param_SetString(param, value);
             }
             break;
         }



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/3e47a7cb8bff9135e08c8ff6731fac0afe87facd...dbbe239ff36f2da9339a8f2a6198ca91284c9e55

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/3e47a7cb8bff9135e08c8ff6731fac0afe87facd...dbbe239ff36f2da9339a8f2a6198ca91284c9e55
You're receiving this email because of your account on code.videolan.org.




More information about the vlc-commits mailing list