[v9,05/10] eal: implement thread priority management functions

Message ID 1622850274-6946-6-git-send-email-navasile@linux.microsoft.com (mailing list archive)
State Superseded, archived
Delegated to: David Marchand
Headers
Series eal: Add EAL API for threading |

Checks

Context Check Description
ci/checkpatch warning coding style issues

Commit Message

Narcisa Ana Maria Vasile June 4, 2021, 11:44 p.m. UTC
  From: Narcisa Vasile <navasile@microsoft.com>

Add function for setting the priority for a thread.
Priorities on multiple platforms are similarly determined by
a priority value and a priority class/policy.

On Linux, the following mapping is created:
RTE_THREAD_PRIORITY_NORMAL corresponds to
* policy SCHED_OTHER
* priority value:   (sched_get_priority_min(SCHED_OTHER) +
                     sched_get_priority_max(SCHED_OTHER))/2;
RTE_THREAD_PRIORITY_REALTIME_CRITICAL corresponds to
* policy SCHED_RR
* priority value: sched_get_priority_max(SCHED_RR);

On Windows, the following mapping is created:
RTE_THREAD_PRIORITY_NORMAL corresponds to
* class NORMAL_PRIORITY_CLASS
* priority THREAD_PRIORITY_NORMAL
RTE_THREAD_PRIORITY_REALTIME_CRITICAL corresponds to
* class REALTIME_PRIORITY_CLASS
* priority THREAD_PRIORITY_TIME_CRITICAL

Signed-off-by: Narcisa Vasile <navasile@microsoft.com>
---
 lib/eal/common/rte_thread.c                   | 51 ++++++++++
 lib/eal/include/rte_thread.h                  | 17 ++++
 lib/eal/include/rte_thread_types.h            |  3 -
 .../include/rte_windows_thread_types.h        |  3 -
 lib/eal/windows/rte_thread.c                  | 92 +++++++++++++++++++
 5 files changed, 160 insertions(+), 6 deletions(-)
  

Comments

Dmitry Kozlyuk June 8, 2021, 11:04 p.m. UTC | #1
2021-06-04 16:44 (UTC-0700), Narcisa Ana Maria Vasile:
> From: Narcisa Vasile <navasile@microsoft.com>
[...]
> diff --git a/lib/eal/windows/rte_thread.c b/lib/eal/windows/rte_thread.c
> index 9e74a538c2..6dc3d575c0 100644
> --- a/lib/eal/windows/rte_thread.c
> +++ b/lib/eal/windows/rte_thread.c
> @@ -202,6 +202,98 @@ rte_thread_get_affinity_by_id(rte_thread_t thread_id,
>  	return ret;
>  }
>  
> +static HANDLE
> +get_process_handle_from_thread_handle(HANDLE thread_handle)
> +{
> +	DWORD process_id = 0;
> +
> +	process_id = GetProcessIdOfThread(thread_handle);
> +	if (process_id == 0) {
> +		RTE_LOG_WIN32_ERR("GetProcessIdOfThread()");
> +		return NULL;
> +	}
> +
> +	return OpenProcess(PROCESS_SET_INFORMATION, FALSE, process_id);
> +}
> +

It is assumed all DPDK threads are created in current process,
existing code uses GetCurrentProcess(), so this can be dropped.
  

Patch

diff --git a/lib/eal/common/rte_thread.c b/lib/eal/common/rte_thread.c
index ceb27feaa7..5cee19bb7d 100644
--- a/lib/eal/common/rte_thread.c
+++ b/lib/eal/common/rte_thread.c
@@ -48,6 +48,57 @@  rte_thread_get_affinity_by_id(rte_thread_t thread_id,
 	return pthread_getaffinity_np(thread_id.opaque_id, sizeof(*cpuset), cpuset);
 }
 
+static int
+thread_map_priority_to_os_value(enum rte_thread_priority eal_pri, int *os_pri, int *pol)
+{
+	RTE_VERIFY(os_pri != NULL);
+	RTE_VERIFY(pol != NULL);
+
+	/* Clear the output parameters */
+	*os_pri = sched_get_priority_min(SCHED_OTHER) - 1;
+	*pol = -1;
+
+	switch (eal_pri)
+	{
+		case RTE_THREAD_PRIORITY_NORMAL:
+			*pol = SCHED_OTHER;
+
+			/*
+			 * Choose the middle of the range to represent
+			 * the priority 'normal'.
+			 * On Linux, this should be 0, since both
+			 * sched_get_priority_min/_max return 0 for SCHED_OTHER.
+			 */
+			*os_pri = (sched_get_priority_min(SCHED_OTHER) +
+				sched_get_priority_max(SCHED_OTHER))/2;
+			break;
+		case RTE_THREAD_PRIORITY_REALTIME_CRITICAL:
+			*pol = SCHED_RR;
+			*os_pri = sched_get_priority_max(SCHED_RR);
+			break;
+		default:
+			RTE_LOG(DEBUG, EAL, "The requested priority value is invalid.\n");
+			return EINVAL;
+	}
+	return 0;
+}
+
+int
+rte_thread_set_priority(rte_thread_t thread_id,
+		enum rte_thread_priority priority)
+{
+	int ret;
+	int policy;
+	struct sched_param param;
+
+	ret = thread_map_priority_to_os_value(priority, &param.sched_priority, &policy);
+	if (ret != 0) {
+		return ret;
+	}
+
+	return pthread_setschedparam(thread_id.opaque_id, policy, &param);
+}
+
 int
 rte_thread_attr_init(rte_thread_attr_t *attr)
 {
diff --git a/lib/eal/include/rte_thread.h b/lib/eal/include/rte_thread.h
index 1f02962146..5c54cd9d67 100644
--- a/lib/eal/include/rte_thread.h
+++ b/lib/eal/include/rte_thread.h
@@ -122,6 +122,23 @@  __rte_experimental
 int rte_thread_get_affinity_by_id(rte_thread_t thread_id,
 		rte_cpuset_t *cpuset);
 
+/**
+ * Set the priority of a thread.
+ *
+ * @param thread_id
+ *    Id of the thread for which to set priority.
+ *
+ * @param priority
+ *   Priority value to be set.
+ *
+ * @return
+ *   On success, return 0.
+ *   On failure, return a positive errno-style error number.
+ */
+__rte_experimental
+int rte_thread_set_priority(rte_thread_t thread_id,
+			    enum rte_thread_priority priority);
+
 /**
  * Initialize the attributes of a thread.
  * These attributes can be passed to the rte_thread_create() function
diff --git a/lib/eal/include/rte_thread_types.h b/lib/eal/include/rte_thread_types.h
index 996232c636..d67b24a563 100644
--- a/lib/eal/include/rte_thread_types.h
+++ b/lib/eal/include/rte_thread_types.h
@@ -7,7 +7,4 @@ 
 
 #include <pthread.h>
 
-#define EAL_THREAD_PRIORITY_NORMAL               0
-#define EAL_THREAD_PRIORITY_REALTIME_CIRTICAL    99
-
 #endif /* _RTE_THREAD_TYPES_H_ */
diff --git a/lib/eal/windows/include/rte_windows_thread_types.h b/lib/eal/windows/include/rte_windows_thread_types.h
index 5bdeaad3d4..60e6d94553 100644
--- a/lib/eal/windows/include/rte_windows_thread_types.h
+++ b/lib/eal/windows/include/rte_windows_thread_types.h
@@ -7,7 +7,4 @@ 
 
 #include <rte_windows.h>
 
-#define EAL_THREAD_PRIORITY_NORMAL             THREAD_PRIORITY_NORMAL
-#define EAL_THREAD_PRIORITY_REALTIME_CIRTICAL  THREAD_PRIORITY_TIME_CRITICAL
-
 #endif /* _RTE_THREAD_TYPES_H_ */
diff --git a/lib/eal/windows/rte_thread.c b/lib/eal/windows/rte_thread.c
index 9e74a538c2..6dc3d575c0 100644
--- a/lib/eal/windows/rte_thread.c
+++ b/lib/eal/windows/rte_thread.c
@@ -202,6 +202,98 @@  rte_thread_get_affinity_by_id(rte_thread_t thread_id,
 	return ret;
 }
 
+static HANDLE
+get_process_handle_from_thread_handle(HANDLE thread_handle)
+{
+	DWORD process_id = 0;
+
+	process_id = GetProcessIdOfThread(thread_handle);
+	if (process_id == 0) {
+		RTE_LOG_WIN32_ERR("GetProcessIdOfThread()");
+		return NULL;
+	}
+
+	return OpenProcess(PROCESS_SET_INFORMATION, FALSE, process_id);
+}
+
+static int
+thread_map_priority_to_os_value(enum rte_thread_priority eal_pri,
+		int *os_pri, int *pri_class)
+{
+	RTE_VERIFY(os_pri != NULL);
+	RTE_VERIFY(pri_class != NULL);
+
+	/* Clear the output parameters */
+	*os_pri = -1;
+	*pri_class = -1;
+
+	switch (eal_pri)
+	{
+		case RTE_THREAD_PRIORITY_NORMAL:
+			*pri_class = NORMAL_PRIORITY_CLASS;
+			*os_pri = THREAD_PRIORITY_NORMAL;
+			break;
+		case RTE_THREAD_PRIORITY_REALTIME_CRITICAL:
+			*pri_class = REALTIME_PRIORITY_CLASS;
+			*os_pri = THREAD_PRIORITY_TIME_CRITICAL;
+			break;
+		default:
+			RTE_LOG(DEBUG, EAL, "The requested priority value is invalid.\n");
+			return EINVAL;
+	}
+
+	return 0;
+}
+
+int
+rte_thread_set_priority(rte_thread_t thread_id,
+			enum rte_thread_priority priority)
+{
+	HANDLE thread_handle = NULL;
+	HANDLE process_handle = NULL;
+	int priority_class = NORMAL_PRIORITY_CLASS;
+	int os_priority = THREAD_PRIORITY_NORMAL;
+	int ret = 0;
+
+	thread_handle = OpenThread(THREAD_SET_INFORMATION |
+				   THREAD_QUERY_INFORMATION, FALSE, thread_id.opaque_id);
+	if (thread_handle == NULL) {
+		ret = thread_log_last_error("OpenThread()");
+		goto cleanup;
+	}
+
+	ret = thread_map_priority_to_os_value(priority, &os_priority, &priority_class);
+	if (ret != 0) {
+		return ret;
+	}
+	process_handle = get_process_handle_from_thread_handle(thread_handle);
+	if (process_handle == NULL) {
+		ret = thread_log_last_error("OpenProcess()");
+		goto cleanup;
+	}
+
+	if (!SetPriorityClass(process_handle, priority_class)) {
+		ret = thread_log_last_error("SetPriorityClass()");
+		goto cleanup;
+	}
+
+	if (!SetThreadPriority(thread_handle, os_priority)) {
+		ret = thread_log_last_error("SetThreadPriority()");
+		goto cleanup;
+	}
+
+cleanup:
+	if (thread_handle != NULL) {
+		CloseHandle(thread_handle);
+		thread_handle = NULL;
+	}
+	if (process_handle != NULL) {
+		CloseHandle(process_handle);
+		process_handle = NULL;
+	}
+	return ret;
+}
+
 int
 rte_thread_attr_init(rte_thread_attr_t *attr)
 {