]> git.droids-corp.org - dpdk.git/commitdiff
eal: add generic thread-local-storage functions
authorTal Shnaiderman <talshn@nvidia.com>
Wed, 6 Jan 2021 20:35:53 +0000 (22:35 +0200)
committerThomas Monjalon <thomas@monjalon.net>
Mon, 11 Jan 2021 22:28:12 +0000 (23:28 +0100)
Add support for TLS functionality in EAL.

The following functions are added:
rte_thread_tls_key_create - create a TLS data key.
rte_thread_tls_key_delete - delete a TLS data key.
rte_thread_tls_value_set - set value bound to the TLS key
rte_thread_tls_value_get - get value bound to the TLS key

TLS key is defined by the new type rte_tls_key.

The API allocates the thread local storage (TLS) key.
Any thread of the process can subsequently use this key
to store and retrieve values that are local to the thread.

Those functions are added in addition to TLS capability
in rte_per_lcore.h to allow abstraction of the pthread
layer for all operating systems.

Windows implementation is under librte_eal/windows and
implemented using WIN32 API for Windows only.

Unix implementation is under librte_eal/unix and
implemented using pthread for UNIX compilation.

Signed-off-by: Tal Shnaiderman <talshn@nvidia.com>
Acked-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
Acked-by: Thomas Monjalon <thomas@monjalon.net>
lib/librte_eal/include/rte_thread.h
lib/librte_eal/rte_eal_exports.def
lib/librte_eal/unix/meson.build
lib/librte_eal/unix/rte_thread.c [new file with mode: 0644]
lib/librte_eal/version.map
lib/librte_eal/windows/meson.build
lib/librte_eal/windows/rte_thread.c [new file with mode: 0644]

index a1ced3cf728b031d8786a4c7892d5018d9a856a3..f1ae2d32cc621d17c0bc91173d3d84d16315ba67 100644 (file)
 extern "C" {
 #endif
 
+/**
+ * TLS key type, an opaque pointer.
+ */
+typedef struct eal_tls_key *rte_tls_key;
+
 /**
  * Set core affinity of the current thread.
  * Support both EAL and non-EAL thread and update TLS.
@@ -40,6 +45,66 @@ int rte_thread_set_affinity(rte_cpuset_t *cpusetp);
  */
 void rte_thread_get_affinity(rte_cpuset_t *cpusetp);
 
+/**
+ * Create a TLS data key visible to all threads in the process.
+ * the created key is later used to get/set a value.
+ * and optional destructor can be set to be called when a thread exits.
+ *
+ * @param key
+ *   Pointer to store the allocated key.
+ * @param destructor
+ *   The function to be called when the thread exits.
+ *   Ignored on Windows OS.
+ *
+ * @return
+ *   On success, zero.
+ *   On failure, a negative number.
+ */
+
+__rte_experimental
+int rte_thread_tls_key_create(rte_tls_key *key, void (*destructor)(void *));
+
+/**
+ * Delete a TLS data key visible to all threads in the process.
+ *
+ * @param key
+ *   The key allocated by rte_thread_tls_key_create().
+ *
+ * @return
+ *   On success, zero.
+ *   On failure, a negative number.
+ */
+__rte_experimental
+int rte_thread_tls_key_delete(rte_tls_key key);
+
+/**
+ * Set value bound to the TLS key on behalf of the calling thread.
+ *
+ * @param key
+ *   The key allocated by rte_thread_tls_key_create().
+ * @param value
+ *   The value bound to the rte_tls_key key for the calling thread.
+ *
+ * @return
+ *   On success, zero.
+ *   On failure, a negative number.
+ */
+__rte_experimental
+int rte_thread_tls_value_set(rte_tls_key key, const void *value);
+
+/**
+ * Get value bound to the TLS key on behalf of the calling thread.
+ *
+ * @param key
+ *   The key allocated by rte_thread_tls_key_create().
+ *
+ * @return
+ *   On success, value data pointer (can also be NULL).
+ *   On failure, NULL and an error number is set in rte_errno.
+ */
+__rte_experimental
+void *rte_thread_tls_value_get(rte_tls_key key);
+
 #ifdef __cplusplus
 }
 #endif
index 4597eb8cd5622013e954f33ff09fdf421409e9ea..f12832cab53012699be9d735878b2d39f3b0b67e 100644 (file)
@@ -322,6 +322,11 @@ EXPORTS
        rte_vect_get_max_simd_bitwidth
        rte_vect_set_max_simd_bitwidth
 
+       rte_thread_tls_key_create
+       rte_thread_tls_key_delete
+       rte_thread_tls_value_get
+       rte_thread_tls_value_set
+
        rte_mem_lock
        rte_mem_map
        rte_mem_page_size
index d3af6b6fe294b82ecdb62eb9494010139ae9a9ef..71221b84a4fea12a4f849faeebe856d8f7c6f689 100644 (file)
@@ -5,4 +5,5 @@ sources += files(
        'eal_file.c',
        'eal_unix_memory.c',
        'eal_unix_timer.c',
+       'rte_thread.c',
 )
diff --git a/lib/librte_eal/unix/rte_thread.c b/lib/librte_eal/unix/rte_thread.c
new file mode 100644 (file)
index 0000000..86ffeeb
--- /dev/null
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2021 Mellanox Technologies, Ltd
+ */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_errno.h>
+#include <rte_log.h>
+#include <rte_thread.h>
+
+struct eal_tls_key {
+       pthread_key_t thread_index;
+};
+
+int
+rte_thread_tls_key_create(rte_tls_key *key, void (*destructor)(void *))
+{
+       int err;
+
+       *key = malloc(sizeof(**key));
+       if ((*key) == NULL) {
+               RTE_LOG(DEBUG, EAL, "Cannot allocate TLS key.\n");
+               return -1;
+       }
+       err = pthread_key_create(&((*key)->thread_index), destructor);
+       if (err) {
+               RTE_LOG(DEBUG, EAL, "pthread_key_create failed: %s\n",
+                        strerror(err));
+               free(*key);
+               return -1;
+       }
+       return 0;
+}
+
+int
+rte_thread_tls_key_delete(rte_tls_key key)
+{
+       int err;
+
+       if (!key) {
+               RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n");
+               return -1;
+       }
+       err = pthread_key_delete(key->thread_index);
+       if (err) {
+               RTE_LOG(DEBUG, EAL, "pthread_key_delete failed: %s\n",
+                        strerror(err));
+               free(key);
+               return -1;
+       }
+       free(key);
+       return 0;
+}
+
+int
+rte_thread_tls_value_set(rte_tls_key key, const void *value)
+{
+       int err;
+
+       if (!key) {
+               RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n");
+               return -1;
+       }
+       err = pthread_setspecific(key->thread_index, value);
+       if (err) {
+               RTE_LOG(DEBUG, EAL, "pthread_setspecific failed: %s\n",
+                       strerror(err));
+               return -1;
+       }
+       return 0;
+}
+
+void *
+rte_thread_tls_value_get(rte_tls_key key)
+{
+       if (!key) {
+               RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n");
+               rte_errno = EINVAL;
+               return NULL;
+       }
+       return pthread_getspecific(key->thread_index);
+}
index 354c068f318847be5b65dd8e59264361bfc664f0..b1db7ec79505feca751af3c0b5ccd2d5a06ff1be 100644 (file)
@@ -403,6 +403,12 @@ EXPERIMENTAL {
        rte_service_lcore_may_be_active;
        rte_vect_get_max_simd_bitwidth;
        rte_vect_set_max_simd_bitwidth;
+
+       # added in 21.02
+       rte_thread_tls_key_create;
+       rte_thread_tls_key_delete;
+       rte_thread_tls_value_get;
+       rte_thread_tls_value_set;
 };
 
 INTERNAL {
index 3b2faf29ebade3eee5687d750de70d5ea9336a58..42ff5c2d59412604fa335e094a41075f6bb9c77e 100644 (file)
@@ -19,6 +19,7 @@ sources += files(
        'eal_timer.c',
        'fnmatch.c',
        'getopt.c',
+       'rte_thread.c',
 )
 
 dpdk_conf.set10('RTE_EAL_NUMA_AWARE_HUGEPAGES', true)
diff --git a/lib/librte_eal/windows/rte_thread.c b/lib/librte_eal/windows/rte_thread.c
new file mode 100644 (file)
index 0000000..2e2ab29
--- /dev/null
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2021 Mellanox Technologies, Ltd
+ */
+
+#include <rte_common.h>
+#include <rte_errno.h>
+#include <rte_thread.h>
+#include <rte_windows.h>
+
+struct eal_tls_key {
+       DWORD thread_index;
+};
+
+int
+rte_thread_tls_key_create(rte_tls_key *key,
+               __rte_unused void (*destructor)(void *))
+{
+       *key = malloc(sizeof(**key));
+       if ((*key) == NULL) {
+               RTE_LOG(DEBUG, EAL, "Cannot allocate TLS key.\n");
+               return -1;
+       }
+       (*key)->thread_index = TlsAlloc();
+       if ((*key)->thread_index == TLS_OUT_OF_INDEXES) {
+               RTE_LOG_WIN32_ERR("TlsAlloc()");
+               free(*key);
+               return -1;
+       }
+       return 0;
+}
+
+int
+rte_thread_tls_key_delete(rte_tls_key key)
+{
+       if (!key) {
+               RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n");
+               return -1;
+       }
+       if (!TlsFree(key->thread_index)) {
+               RTE_LOG_WIN32_ERR("TlsFree()");
+               free(key);
+               return -1;
+       }
+       free(key);
+       return 0;
+}
+
+int
+rte_thread_tls_value_set(rte_tls_key key, const void *value)
+{
+       char *p;
+
+       if (!key) {
+               RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n");
+               return -1;
+       }
+       /* discard const qualifier */
+       p = (char *) (uintptr_t) value;
+       if (!TlsSetValue(key->thread_index, p)) {
+               RTE_LOG_WIN32_ERR("TlsSetValue()");
+               return -1;
+       }
+       return 0;
+}
+
+void *
+rte_thread_tls_value_get(rte_tls_key key)
+{
+       void *output;
+
+       if (!key) {
+               RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n");
+               rte_errno = EINVAL;
+               return NULL;
+       }
+       output = TlsGetValue(key->thread_index);
+       if (GetLastError() != ERROR_SUCCESS) {
+               RTE_LOG_WIN32_ERR("TlsGetValue()");
+               rte_errno = ENOEXEC;
+               return NULL;
+       }
+       return output;
+}