xref: /dpdk/lib/eal/unix/rte_thread.c (revision ca04c78b6262145ce8b878ec5a5b824fd118b55f)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright 2021 Mellanox Technologies, Ltd
356539289STyler Retzlaff  * Copyright (C) 2022 Microsoft Corporation
499a2dd95SBruce Richardson  */
599a2dd95SBruce Richardson 
699a2dd95SBruce Richardson #include <errno.h>
799a2dd95SBruce Richardson #include <pthread.h>
899a2dd95SBruce Richardson #include <stdlib.h>
999a2dd95SBruce Richardson #include <string.h>
1099a2dd95SBruce Richardson 
1199a2dd95SBruce Richardson #include <rte_errno.h>
1299a2dd95SBruce Richardson #include <rte_log.h>
1399a2dd95SBruce Richardson #include <rte_thread.h>
1499a2dd95SBruce Richardson 
1599a2dd95SBruce Richardson struct eal_tls_key {
1699a2dd95SBruce Richardson 	pthread_key_t thread_index;
1799a2dd95SBruce Richardson };
1899a2dd95SBruce Richardson 
19*ca04c78bSTyler Retzlaff static int
20*ca04c78bSTyler Retzlaff thread_map_priority_to_os_value(enum rte_thread_priority eal_pri, int *os_pri,
21*ca04c78bSTyler Retzlaff 	int *pol)
22*ca04c78bSTyler Retzlaff {
23*ca04c78bSTyler Retzlaff 	/* Clear the output parameters. */
24*ca04c78bSTyler Retzlaff 	*os_pri = sched_get_priority_min(SCHED_OTHER) - 1;
25*ca04c78bSTyler Retzlaff 	*pol = -1;
26*ca04c78bSTyler Retzlaff 
27*ca04c78bSTyler Retzlaff 	switch (eal_pri) {
28*ca04c78bSTyler Retzlaff 	case RTE_THREAD_PRIORITY_NORMAL:
29*ca04c78bSTyler Retzlaff 		*pol = SCHED_OTHER;
30*ca04c78bSTyler Retzlaff 
31*ca04c78bSTyler Retzlaff 		/*
32*ca04c78bSTyler Retzlaff 		 * Choose the middle of the range to represent the priority
33*ca04c78bSTyler Retzlaff 		 * 'normal'.
34*ca04c78bSTyler Retzlaff 		 * On Linux, this should be 0, since both
35*ca04c78bSTyler Retzlaff 		 * sched_get_priority_min/_max return 0 for SCHED_OTHER.
36*ca04c78bSTyler Retzlaff 		 */
37*ca04c78bSTyler Retzlaff 		*os_pri = (sched_get_priority_min(SCHED_OTHER) +
38*ca04c78bSTyler Retzlaff 			sched_get_priority_max(SCHED_OTHER)) / 2;
39*ca04c78bSTyler Retzlaff 		break;
40*ca04c78bSTyler Retzlaff 	case RTE_THREAD_PRIORITY_REALTIME_CRITICAL:
41*ca04c78bSTyler Retzlaff 		*pol = SCHED_RR;
42*ca04c78bSTyler Retzlaff 		*os_pri = sched_get_priority_max(SCHED_RR);
43*ca04c78bSTyler Retzlaff 		break;
44*ca04c78bSTyler Retzlaff 	default:
45*ca04c78bSTyler Retzlaff 		RTE_LOG(DEBUG, EAL, "The requested priority value is invalid.\n");
46*ca04c78bSTyler Retzlaff 		return EINVAL;
47*ca04c78bSTyler Retzlaff 	}
48*ca04c78bSTyler Retzlaff 
49*ca04c78bSTyler Retzlaff 	return 0;
50*ca04c78bSTyler Retzlaff }
51*ca04c78bSTyler Retzlaff 
52*ca04c78bSTyler Retzlaff static int
53*ca04c78bSTyler Retzlaff thread_map_os_priority_to_eal_priority(int policy, int os_pri,
54*ca04c78bSTyler Retzlaff 	enum rte_thread_priority *eal_pri)
55*ca04c78bSTyler Retzlaff {
56*ca04c78bSTyler Retzlaff 	switch (policy) {
57*ca04c78bSTyler Retzlaff 	case SCHED_OTHER:
58*ca04c78bSTyler Retzlaff 		if (os_pri == (sched_get_priority_min(SCHED_OTHER) +
59*ca04c78bSTyler Retzlaff 				sched_get_priority_max(SCHED_OTHER)) / 2) {
60*ca04c78bSTyler Retzlaff 			*eal_pri = RTE_THREAD_PRIORITY_NORMAL;
61*ca04c78bSTyler Retzlaff 			return 0;
62*ca04c78bSTyler Retzlaff 		}
63*ca04c78bSTyler Retzlaff 		break;
64*ca04c78bSTyler Retzlaff 	case SCHED_RR:
65*ca04c78bSTyler Retzlaff 		if (os_pri == sched_get_priority_max(SCHED_RR)) {
66*ca04c78bSTyler Retzlaff 			*eal_pri = RTE_THREAD_PRIORITY_REALTIME_CRITICAL;
67*ca04c78bSTyler Retzlaff 			return 0;
68*ca04c78bSTyler Retzlaff 		}
69*ca04c78bSTyler Retzlaff 		break;
70*ca04c78bSTyler Retzlaff 	default:
71*ca04c78bSTyler Retzlaff 		RTE_LOG(DEBUG, EAL, "The OS priority value does not map to an EAL-defined priority.\n");
72*ca04c78bSTyler Retzlaff 		return EINVAL;
73*ca04c78bSTyler Retzlaff 	}
74*ca04c78bSTyler Retzlaff 
75*ca04c78bSTyler Retzlaff 	return 0;
76*ca04c78bSTyler Retzlaff }
77*ca04c78bSTyler Retzlaff 
7856539289STyler Retzlaff rte_thread_t
7956539289STyler Retzlaff rte_thread_self(void)
8056539289STyler Retzlaff {
8156539289STyler Retzlaff 	RTE_BUILD_BUG_ON(sizeof(pthread_t) > sizeof(uintptr_t));
8256539289STyler Retzlaff 
8356539289STyler Retzlaff 	rte_thread_t thread_id;
8456539289STyler Retzlaff 
8556539289STyler Retzlaff 	thread_id.opaque_id = (uintptr_t)pthread_self();
8656539289STyler Retzlaff 
8756539289STyler Retzlaff 	return thread_id;
8856539289STyler Retzlaff }
8956539289STyler Retzlaff 
9099a2dd95SBruce Richardson int
91*ca04c78bSTyler Retzlaff rte_thread_get_priority(rte_thread_t thread_id,
92*ca04c78bSTyler Retzlaff 	enum rte_thread_priority *priority)
93*ca04c78bSTyler Retzlaff {
94*ca04c78bSTyler Retzlaff 	struct sched_param param;
95*ca04c78bSTyler Retzlaff 	int policy;
96*ca04c78bSTyler Retzlaff 	int ret;
97*ca04c78bSTyler Retzlaff 
98*ca04c78bSTyler Retzlaff 	ret = pthread_getschedparam((pthread_t)thread_id.opaque_id, &policy,
99*ca04c78bSTyler Retzlaff 		&param);
100*ca04c78bSTyler Retzlaff 	if (ret != 0) {
101*ca04c78bSTyler Retzlaff 		RTE_LOG(DEBUG, EAL, "pthread_getschedparam failed\n");
102*ca04c78bSTyler Retzlaff 		goto cleanup;
103*ca04c78bSTyler Retzlaff 	}
104*ca04c78bSTyler Retzlaff 
105*ca04c78bSTyler Retzlaff 	return thread_map_os_priority_to_eal_priority(policy,
106*ca04c78bSTyler Retzlaff 		param.sched_priority, priority);
107*ca04c78bSTyler Retzlaff 
108*ca04c78bSTyler Retzlaff cleanup:
109*ca04c78bSTyler Retzlaff 	return ret;
110*ca04c78bSTyler Retzlaff }
111*ca04c78bSTyler Retzlaff 
112*ca04c78bSTyler Retzlaff int
113*ca04c78bSTyler Retzlaff rte_thread_set_priority(rte_thread_t thread_id,
114*ca04c78bSTyler Retzlaff 	enum rte_thread_priority priority)
115*ca04c78bSTyler Retzlaff {
116*ca04c78bSTyler Retzlaff 	struct sched_param param;
117*ca04c78bSTyler Retzlaff 	int policy;
118*ca04c78bSTyler Retzlaff 	int ret;
119*ca04c78bSTyler Retzlaff 
120*ca04c78bSTyler Retzlaff 	/* Realtime priority can cause crashes on non-Windows platforms. */
121*ca04c78bSTyler Retzlaff 	if (priority == RTE_THREAD_PRIORITY_REALTIME_CRITICAL)
122*ca04c78bSTyler Retzlaff 		return ENOTSUP;
123*ca04c78bSTyler Retzlaff 
124*ca04c78bSTyler Retzlaff 	ret = thread_map_priority_to_os_value(priority, &param.sched_priority,
125*ca04c78bSTyler Retzlaff 		&policy);
126*ca04c78bSTyler Retzlaff 	if (ret != 0)
127*ca04c78bSTyler Retzlaff 		return ret;
128*ca04c78bSTyler Retzlaff 
129*ca04c78bSTyler Retzlaff 	return pthread_setschedparam((pthread_t)thread_id.opaque_id, policy,
130*ca04c78bSTyler Retzlaff 		&param);
131*ca04c78bSTyler Retzlaff }
132*ca04c78bSTyler Retzlaff 
133*ca04c78bSTyler Retzlaff int
13499a2dd95SBruce Richardson rte_thread_key_create(rte_thread_key *key, void (*destructor)(void *))
13599a2dd95SBruce Richardson {
13699a2dd95SBruce Richardson 	int err;
13799a2dd95SBruce Richardson 
13899a2dd95SBruce Richardson 	*key = malloc(sizeof(**key));
13999a2dd95SBruce Richardson 	if ((*key) == NULL) {
14099a2dd95SBruce Richardson 		RTE_LOG(DEBUG, EAL, "Cannot allocate TLS key.\n");
14199a2dd95SBruce Richardson 		rte_errno = ENOMEM;
14299a2dd95SBruce Richardson 		return -1;
14399a2dd95SBruce Richardson 	}
14499a2dd95SBruce Richardson 	err = pthread_key_create(&((*key)->thread_index), destructor);
14599a2dd95SBruce Richardson 	if (err) {
14699a2dd95SBruce Richardson 		RTE_LOG(DEBUG, EAL, "pthread_key_create failed: %s\n",
14799a2dd95SBruce Richardson 			strerror(err));
14899a2dd95SBruce Richardson 		free(*key);
14999a2dd95SBruce Richardson 		rte_errno = ENOEXEC;
15099a2dd95SBruce Richardson 		return -1;
15199a2dd95SBruce Richardson 	}
15299a2dd95SBruce Richardson 	return 0;
15399a2dd95SBruce Richardson }
15499a2dd95SBruce Richardson 
15599a2dd95SBruce Richardson int
15699a2dd95SBruce Richardson rte_thread_key_delete(rte_thread_key key)
15799a2dd95SBruce Richardson {
15899a2dd95SBruce Richardson 	int err;
15999a2dd95SBruce Richardson 
16099a2dd95SBruce Richardson 	if (!key) {
16199a2dd95SBruce Richardson 		RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n");
16299a2dd95SBruce Richardson 		rte_errno = EINVAL;
16399a2dd95SBruce Richardson 		return -1;
16499a2dd95SBruce Richardson 	}
16599a2dd95SBruce Richardson 	err = pthread_key_delete(key->thread_index);
16699a2dd95SBruce Richardson 	if (err) {
16799a2dd95SBruce Richardson 		RTE_LOG(DEBUG, EAL, "pthread_key_delete failed: %s\n",
16899a2dd95SBruce Richardson 			strerror(err));
16999a2dd95SBruce Richardson 		free(key);
17099a2dd95SBruce Richardson 		rte_errno = ENOEXEC;
17199a2dd95SBruce Richardson 		return -1;
17299a2dd95SBruce Richardson 	}
17399a2dd95SBruce Richardson 	free(key);
17499a2dd95SBruce Richardson 	return 0;
17599a2dd95SBruce Richardson }
17699a2dd95SBruce Richardson 
17799a2dd95SBruce Richardson int
17899a2dd95SBruce Richardson rte_thread_value_set(rte_thread_key key, const void *value)
17999a2dd95SBruce Richardson {
18099a2dd95SBruce Richardson 	int err;
18199a2dd95SBruce Richardson 
18299a2dd95SBruce Richardson 	if (!key) {
18399a2dd95SBruce Richardson 		RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n");
18499a2dd95SBruce Richardson 		rte_errno = EINVAL;
18599a2dd95SBruce Richardson 		return -1;
18699a2dd95SBruce Richardson 	}
18799a2dd95SBruce Richardson 	err = pthread_setspecific(key->thread_index, value);
18899a2dd95SBruce Richardson 	if (err) {
18999a2dd95SBruce Richardson 		RTE_LOG(DEBUG, EAL, "pthread_setspecific failed: %s\n",
19099a2dd95SBruce Richardson 			strerror(err));
19199a2dd95SBruce Richardson 		rte_errno = ENOEXEC;
19299a2dd95SBruce Richardson 		return -1;
19399a2dd95SBruce Richardson 	}
19499a2dd95SBruce Richardson 	return 0;
19599a2dd95SBruce Richardson }
19699a2dd95SBruce Richardson 
19799a2dd95SBruce Richardson void *
19899a2dd95SBruce Richardson rte_thread_value_get(rte_thread_key key)
19999a2dd95SBruce Richardson {
20099a2dd95SBruce Richardson 	if (!key) {
20199a2dd95SBruce Richardson 		RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n");
20299a2dd95SBruce Richardson 		rte_errno = EINVAL;
20399a2dd95SBruce Richardson 		return NULL;
20499a2dd95SBruce Richardson 	}
20599a2dd95SBruce Richardson 	return pthread_getspecific(key->thread_index);
20699a2dd95SBruce Richardson }
207b70a9b78STyler Retzlaff 
208b70a9b78STyler Retzlaff int
209b70a9b78STyler Retzlaff rte_thread_set_affinity_by_id(rte_thread_t thread_id,
210b70a9b78STyler Retzlaff 		const rte_cpuset_t *cpuset)
211b70a9b78STyler Retzlaff {
212b70a9b78STyler Retzlaff 	return pthread_setaffinity_np((pthread_t)thread_id.opaque_id,
213b70a9b78STyler Retzlaff 		sizeof(*cpuset), cpuset);
214b70a9b78STyler Retzlaff }
215b70a9b78STyler Retzlaff 
216b70a9b78STyler Retzlaff int
217b70a9b78STyler Retzlaff rte_thread_get_affinity_by_id(rte_thread_t thread_id,
218b70a9b78STyler Retzlaff 		rte_cpuset_t *cpuset)
219b70a9b78STyler Retzlaff {
220b70a9b78STyler Retzlaff 	return pthread_getaffinity_np((pthread_t)thread_id.opaque_id,
221b70a9b78STyler Retzlaff 		sizeof(*cpuset), cpuset);
222b70a9b78STyler Retzlaff }
223