DPDK patches and discussions
 help / color / mirror / Atom feed
From: Tal Shnaiderman <talshn@nvidia.com>
To: dev@dpdk.org
Cc: thomas@monjalon.net, pallavi.kadam@intel.com,
	dmitry.kozliuk@gmail.com, navasile@linux.microsoft.com,
	dmitrym@microsoft.com, david.marchand@redhat.com
Subject: [dpdk-dev] [PATCH v7 2/2] eal: add generic thread-local-storage functions
Date: Tue,  5 Jan 2021 19:06:35 +0200
Message-ID: <20210105170635.6212-3-talshn@nvidia.com> (raw)
In-Reply-To: <20210105170635.6212-1-talshn@nvidia.com>

Add support for TLS functionality in EAL.

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

TLS key will be 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 user to use the thread reasouce
destruction capability in rte_thread_tls_key_create.

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

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

Signed-off-by: Tal Shnaiderman <talshn@nvidia.com>
---
v3: switch from pthread shim to generic eal implementation [DmitryK]
v4: modify file names, function names, move unix code to common
for future external pthreads support [DmitryK]
v5: rename var used for external pthreads, add description in
meson_options.txt. [DmitryK]
v6: remove external_pthread support as it collide with pthread
shim implementation [DmitryK]
v7: move unix code to unix instead of common, rename functions
add more documentation [Thomas]
---
 lib/librte_eal/include/rte_thread.h | 68 +++++++++++++++++++++++++++++
 lib/librte_eal/rte_eal_exports.def  |  5 +++
 lib/librte_eal/unix/meson.build     |  1 +
 lib/librte_eal/unix/rte_thread.c    | 86 +++++++++++++++++++++++++++++++++++++
 lib/librte_eal/version.map          |  6 +++
 lib/librte_eal/windows/meson.build  |  1 +
 lib/librte_eal/windows/rte_thread.c | 83 +++++++++++++++++++++++++++++++++++
 7 files changed, 250 insertions(+)
 create mode 100644 lib/librte_eal/unix/rte_thread.c
 create mode 100644 lib/librte_eal/windows/rte_thread.c

diff --git a/lib/librte_eal/include/rte_thread.h b/lib/librte_eal/include/rte_thread.h
index dbc4b3adf8..f5c5290ffc 100644
--- a/lib/librte_eal/include/rte_thread.h
+++ b/lib/librte_eal/include/rte_thread.h
@@ -15,6 +15,11 @@
  * Simple threads functionality supplied by EAL.
  */
 
+/**
+ * Opaque pointer for TLS key.
+ */
+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.
@@ -36,4 +41,67 @@ int rte_thread_set_affinity(rte_cpuset_t *cpusetp);
  */
 void rte_thread_get_affinity(rte_cpuset_t *cpusetp);
 
+/**
+ * Function to create a TLS data key visible to all threads in the process
+ * function need to be called once to create a key usable by all threads.
+ * rte_tls_key is an opaque pointer used to store the allocated key.
+ * which is later used to get/set a value.
+ * and optional destructor can be set to be called when a thread expires.
+ *
+ * @param key
+ *   Pointer to store the allocated rte_tls_key
+ * @param destructor
+ *   The function to be called when the thread expires.
+ *   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 *));
+
+/**
+ * Function to delete a TLS data key visible to all threads in the process
+ * rte_tls_key is the opaque pointer allocated by rte_thread_tls_key_create.
+ *
+ * @param key
+ *   The rte_tls_key will contain the allocated key
+ *
+ * @return
+ *   On success, zero.
+ *   On failure, a negative number.
+ */
+__rte_experimental
+int rte_thread_tls_key_delete(rte_tls_key key);
+
+/**
+ * Function to set value bound to the tls key on behalf of the calling thread
+ *
+ * @param key
+ *   The rte_tls_key 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);
+
+/**
+ * Function to get value bound to the tls key on behalf of the calling thread
+ *
+ * @param key
+ *   The rte_tls_key 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);
+
 #endif /* _RTE_THREAD_H_ */
diff --git a/lib/librte_eal/rte_eal_exports.def b/lib/librte_eal/rte_eal_exports.def
index 6a6be1cfa6..a11b078ac6 100644
--- a/lib/librte_eal/rte_eal_exports.def
+++ b/lib/librte_eal/rte_eal_exports.def
@@ -306,6 +306,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_set
+	rte_thread_tls_value_get
+
 	rte_mem_lock
 	rte_mem_map
 	rte_mem_page_size
diff --git a/lib/librte_eal/unix/meson.build b/lib/librte_eal/unix/meson.build
index d3af6b6fe2..71221b84a4 100644
--- a/lib/librte_eal/unix/meson.build
+++ b/lib/librte_eal/unix/meson.build
@@ -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
index 0000000000..2a88aea6a6
--- /dev/null
+++ b/lib/librte_eal/unix/rte_thread.c
@@ -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(struct eal_tls_key));
+	if ((*key) == NULL) {
+		RTE_LOG(DEBUG, EAL, "Cannot allocate tls key.");
+		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 passed to function.\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 passed to function.\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 passed to function.\n");
+		rte_errno = EINVAL;
+		return NULL;
+	}
+	return pthread_getspecific(key->thread_index);
+}
diff --git a/lib/librte_eal/version.map b/lib/librte_eal/version.map
index 354c068f31..272db0504a 100644
--- a/lib/librte_eal/version.map
+++ b/lib/librte_eal/version.map
@@ -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_set;
+	rte_thread_tls_value_get;
 };
 
 INTERNAL {
diff --git a/lib/librte_eal/windows/meson.build b/lib/librte_eal/windows/meson.build
index 3b2faf29eb..42ff5c2d59 100644
--- a/lib/librte_eal/windows/meson.build
+++ b/lib/librte_eal/windows/meson.build
@@ -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
index 0000000000..4ced283c62
--- /dev/null
+++ b/lib/librte_eal/windows/rte_thread.c
@@ -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(struct eal_tls_key));
+	if ((*key) == NULL) {
+		RTE_LOG(DEBUG, EAL, "Cannot allocate tls key.");
+		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 passed to function.\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 passed to function.\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 passed to function.\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;
+}
-- 
2.16.1.windows.4


  parent reply	other threads:[~2021-01-05 17:07 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-13 20:24 [dpdk-dev] [PATCH v2] eal/windows: add pthread TLS function support Tal Shnaiderman
2020-12-15 22:36 ` Dmitry Kozlyuk
2020-12-17 17:49 ` [dpdk-dev] [PATCH v3] eal: add generic thread-local-storage functions Tal Shnaiderman
2020-12-17 20:56   ` Dmitry Kozlyuk
2020-12-18 19:37     ` Tal Shnaiderman
2020-12-22  7:30   ` [dpdk-dev] [PATCH v4] " Tal Shnaiderman
2020-12-23  1:18     ` Dmitry Kozlyuk
2020-12-23 11:44       ` Tal Shnaiderman
2020-12-23 11:58         ` Dmitry Kozlyuk
2020-12-23 18:16           ` [dpdk-dev] [EXTERNAL] " Dmitry Malloy (MESHCHANINOV)
2020-12-26 16:08     ` [dpdk-dev] [PATCH v5] " Tal Shnaiderman
2020-12-29 23:13       ` Dmitry Kozlyuk
2020-12-30 10:04         ` Tal Shnaiderman
2020-12-30 11:12       ` [dpdk-dev] [PATCH v6] " Tal Shnaiderman
2021-01-01 22:16         ` Dmitry Kozlyuk
2021-01-05 11:53         ` Thomas Monjalon
2021-01-05 17:06       ` [dpdk-dev] [PATCH v7 0/2] support generic threading functions Tal Shnaiderman
2021-01-05 17:06         ` [dpdk-dev] [PATCH v7 1/2] eal: move thread affinity functions to new file Tal Shnaiderman
2021-01-06 14:40           ` Dmitry Kozlyuk
2021-01-06 19:45           ` [dpdk-dev] [PATCH v8 0/2] support generic threading functions Tal Shnaiderman
2021-01-06 19:45             ` [dpdk-dev] [PATCH v8 1/2] eal: move thread affinity functions to new file Tal Shnaiderman
2021-01-06 19:45             ` [dpdk-dev] [PATCH v8 2/2] eal: add generic thread-local-storage functions Tal Shnaiderman
2021-01-06 20:10               ` Dmitry Kozlyuk
2021-01-06 20:33                 ` Tal Shnaiderman
2021-01-06 20:35             ` [dpdk-dev] [PATCH v9 0/2] support generic threading functions Tal Shnaiderman
2021-01-06 20:35               ` [dpdk-dev] [PATCH v9 1/2] eal: move thread affinity functions to new file Tal Shnaiderman
2021-01-06 20:35               ` [dpdk-dev] [PATCH v9 2/2] eal: add generic thread-local-storage functions Tal Shnaiderman
2021-01-07 14:46                 ` Dmitry Kozlyuk
2021-02-10 13:33                 ` Burakov, Anatoly
2021-02-10 14:26                   ` Medvedkin, Vladimir
2021-02-11  7:34                     ` Tal Shnaiderman
2021-02-11  7:26                   ` Tal Shnaiderman
2021-01-11 22:33               ` [dpdk-dev] [PATCH v9 0/2] support generic threading functions Thomas Monjalon
2021-01-05 17:06         ` Tal Shnaiderman [this message]
2021-01-06 15:05           ` [dpdk-dev] [PATCH v7 2/2] eal: add generic thread-local-storage functions Dmitry Kozlyuk
2021-01-06 16:04             ` Tal Shnaiderman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210105170635.6212-3-talshn@nvidia.com \
    --to=talshn@nvidia.com \
    --cc=david.marchand@redhat.com \
    --cc=dev@dpdk.org \
    --cc=dmitry.kozliuk@gmail.com \
    --cc=dmitrym@microsoft.com \
    --cc=navasile@linux.microsoft.com \
    --cc=pallavi.kadam@intel.com \
    --cc=thomas@monjalon.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

DPDK patches and discussions

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://inbox.dpdk.org/dev/0 dev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 dev dev/ https://inbox.dpdk.org/dev \
		dev@dpdk.org
	public-inbox-index dev

Example config snippet for mirrors.
Newsgroup available over NNTP:
	nntp://inbox.dpdk.org/inbox.dpdk.dev


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git