examples/l3fwd: merge l3fwd-acl example
[dpdk.git] / lib / eal / unix / rte_thread.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2021 Mellanox Technologies, Ltd
3  * Copyright (C) 2022 Microsoft Corporation
4  */
5
6 #include <errno.h>
7 #include <pthread.h>
8 #include <stdlib.h>
9 #include <string.h>
10
11 #include <rte_errno.h>
12 #include <rte_log.h>
13 #include <rte_thread.h>
14
15 struct eal_tls_key {
16         pthread_key_t thread_index;
17 };
18
19 static int
20 thread_map_priority_to_os_value(enum rte_thread_priority eal_pri, int *os_pri,
21         int *pol)
22 {
23         /* Clear the output parameters. */
24         *os_pri = sched_get_priority_min(SCHED_OTHER) - 1;
25         *pol = -1;
26
27         switch (eal_pri) {
28         case RTE_THREAD_PRIORITY_NORMAL:
29                 *pol = SCHED_OTHER;
30
31                 /*
32                  * Choose the middle of the range to represent the priority
33                  * 'normal'.
34                  * On Linux, this should be 0, since both
35                  * sched_get_priority_min/_max return 0 for SCHED_OTHER.
36                  */
37                 *os_pri = (sched_get_priority_min(SCHED_OTHER) +
38                         sched_get_priority_max(SCHED_OTHER)) / 2;
39                 break;
40         case RTE_THREAD_PRIORITY_REALTIME_CRITICAL:
41                 *pol = SCHED_RR;
42                 *os_pri = sched_get_priority_max(SCHED_RR);
43                 break;
44         default:
45                 RTE_LOG(DEBUG, EAL, "The requested priority value is invalid.\n");
46                 return EINVAL;
47         }
48
49         return 0;
50 }
51
52 static int
53 thread_map_os_priority_to_eal_priority(int policy, int os_pri,
54         enum rte_thread_priority *eal_pri)
55 {
56         switch (policy) {
57         case SCHED_OTHER:
58                 if (os_pri == (sched_get_priority_min(SCHED_OTHER) +
59                                 sched_get_priority_max(SCHED_OTHER)) / 2) {
60                         *eal_pri = RTE_THREAD_PRIORITY_NORMAL;
61                         return 0;
62                 }
63                 break;
64         case SCHED_RR:
65                 if (os_pri == sched_get_priority_max(SCHED_RR)) {
66                         *eal_pri = RTE_THREAD_PRIORITY_REALTIME_CRITICAL;
67                         return 0;
68                 }
69                 break;
70         default:
71                 RTE_LOG(DEBUG, EAL, "The OS priority value does not map to an EAL-defined priority.\n");
72                 return EINVAL;
73         }
74
75         return 0;
76 }
77
78 rte_thread_t
79 rte_thread_self(void)
80 {
81         RTE_BUILD_BUG_ON(sizeof(pthread_t) > sizeof(uintptr_t));
82
83         rte_thread_t thread_id;
84
85         thread_id.opaque_id = (uintptr_t)pthread_self();
86
87         return thread_id;
88 }
89
90 int
91 rte_thread_get_priority(rte_thread_t thread_id,
92         enum rte_thread_priority *priority)
93 {
94         struct sched_param param;
95         int policy;
96         int ret;
97
98         ret = pthread_getschedparam((pthread_t)thread_id.opaque_id, &policy,
99                 &param);
100         if (ret != 0) {
101                 RTE_LOG(DEBUG, EAL, "pthread_getschedparam failed\n");
102                 goto cleanup;
103         }
104
105         return thread_map_os_priority_to_eal_priority(policy,
106                 param.sched_priority, priority);
107
108 cleanup:
109         return ret;
110 }
111
112 int
113 rte_thread_set_priority(rte_thread_t thread_id,
114         enum rte_thread_priority priority)
115 {
116         struct sched_param param;
117         int policy;
118         int ret;
119
120         /* Realtime priority can cause crashes on non-Windows platforms. */
121         if (priority == RTE_THREAD_PRIORITY_REALTIME_CRITICAL)
122                 return ENOTSUP;
123
124         ret = thread_map_priority_to_os_value(priority, &param.sched_priority,
125                 &policy);
126         if (ret != 0)
127                 return ret;
128
129         return pthread_setschedparam((pthread_t)thread_id.opaque_id, policy,
130                 &param);
131 }
132
133 int
134 rte_thread_key_create(rte_thread_key *key, void (*destructor)(void *))
135 {
136         int err;
137
138         *key = malloc(sizeof(**key));
139         if ((*key) == NULL) {
140                 RTE_LOG(DEBUG, EAL, "Cannot allocate TLS key.\n");
141                 rte_errno = ENOMEM;
142                 return -1;
143         }
144         err = pthread_key_create(&((*key)->thread_index), destructor);
145         if (err) {
146                 RTE_LOG(DEBUG, EAL, "pthread_key_create failed: %s\n",
147                         strerror(err));
148                 free(*key);
149                 rte_errno = ENOEXEC;
150                 return -1;
151         }
152         return 0;
153 }
154
155 int
156 rte_thread_key_delete(rte_thread_key key)
157 {
158         int err;
159
160         if (!key) {
161                 RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n");
162                 rte_errno = EINVAL;
163                 return -1;
164         }
165         err = pthread_key_delete(key->thread_index);
166         if (err) {
167                 RTE_LOG(DEBUG, EAL, "pthread_key_delete failed: %s\n",
168                         strerror(err));
169                 free(key);
170                 rte_errno = ENOEXEC;
171                 return -1;
172         }
173         free(key);
174         return 0;
175 }
176
177 int
178 rte_thread_value_set(rte_thread_key key, const void *value)
179 {
180         int err;
181
182         if (!key) {
183                 RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n");
184                 rte_errno = EINVAL;
185                 return -1;
186         }
187         err = pthread_setspecific(key->thread_index, value);
188         if (err) {
189                 RTE_LOG(DEBUG, EAL, "pthread_setspecific failed: %s\n",
190                         strerror(err));
191                 rte_errno = ENOEXEC;
192                 return -1;
193         }
194         return 0;
195 }
196
197 void *
198 rte_thread_value_get(rte_thread_key key)
199 {
200         if (!key) {
201                 RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n");
202                 rte_errno = EINVAL;
203                 return NULL;
204         }
205         return pthread_getspecific(key->thread_index);
206 }
207
208 int
209 rte_thread_set_affinity_by_id(rte_thread_t thread_id,
210                 const rte_cpuset_t *cpuset)
211 {
212         return pthread_setaffinity_np((pthread_t)thread_id.opaque_id,
213                 sizeof(*cpuset), cpuset);
214 }
215
216 int
217 rte_thread_get_affinity_by_id(rte_thread_t thread_id,
218                 rte_cpuset_t *cpuset)
219 {
220         return pthread_getaffinity_np((pthread_t)thread_id.opaque_id,
221                 sizeof(*cpuset), cpuset);
222 }