File: | home/bhubbard/working/src/ceph/src/spdk/dpdk/lib/librte_eal/linux/eal/eal_alarm.c |
Warning: | line 219, column 17 Use of memory after it is freed |
[?] Use j/k keys for keyboard navigation
1 | /* SPDX-License-Identifier: BSD-3-Clause | |||
2 | * Copyright(c) 2010-2014 Intel Corporation | |||
3 | */ | |||
4 | #include <stdio.h> | |||
5 | #include <stdint.h> | |||
6 | #include <signal.h> | |||
7 | #include <errno(*__errno_location ()).h> | |||
8 | #include <string.h> | |||
9 | #include <sys/queue.h> | |||
10 | #include <sys/time.h> | |||
11 | #include <sys/timerfd.h> | |||
12 | ||||
13 | #include <rte_memory.h> | |||
14 | #include <rte_interrupts.h> | |||
15 | #include <rte_alarm.h> | |||
16 | #include <rte_common.h> | |||
17 | #include <rte_per_lcore.h> | |||
18 | #include <rte_eal.h> | |||
19 | #include <rte_launch.h> | |||
20 | #include <rte_lcore.h> | |||
21 | #include <rte_errno(per_lcore__rte_errno).h> | |||
22 | #include <rte_spinlock.h> | |||
23 | #include <eal_private.h> | |||
24 | ||||
25 | #ifndef TFD_NONBLOCKTFD_NONBLOCK | |||
26 | #include <fcntl.h> | |||
27 | #define TFD_NONBLOCKTFD_NONBLOCK O_NONBLOCK | |||
28 | #endif | |||
29 | ||||
30 | #define NS_PER_US1000 1000 | |||
31 | #define US_PER_MS1000 1000 | |||
32 | #define MS_PER_S1000 1000 | |||
33 | #ifndef US_PER_S1000000 | |||
34 | #define US_PER_S1000000 (US_PER_MS1000 * MS_PER_S1000) | |||
35 | #endif | |||
36 | ||||
37 | #ifdef CLOCK_MONOTONIC_RAW4 /* Defined in glibc bits/time.h */ | |||
38 | #define CLOCK_TYPE_ID4 CLOCK_MONOTONIC_RAW4 | |||
39 | #else | |||
40 | #define CLOCK_TYPE_ID4 CLOCK_MONOTONIC1 | |||
41 | #endif | |||
42 | ||||
43 | struct alarm_entry { | |||
44 | LIST_ENTRY(alarm_entry)struct { struct alarm_entry *le_next; struct alarm_entry **le_prev ; } next; | |||
45 | struct timeval time; | |||
46 | rte_eal_alarm_callback cb_fn; | |||
47 | void *cb_arg; | |||
48 | volatile uint8_t executing; | |||
49 | volatile pthread_t executing_id; | |||
50 | }; | |||
51 | ||||
52 | static LIST_HEAD(alarm_list, alarm_entry)struct alarm_list { struct alarm_entry *lh_first; } alarm_list = LIST_HEAD_INITIALIZER(){ ((void*)0) }; | |||
53 | static rte_spinlock_t alarm_list_lk = RTE_SPINLOCK_INITIALIZER{ 0 }; | |||
54 | ||||
55 | static struct rte_intr_handle intr_handle = {.fd = -1 }; | |||
56 | static int handler_registered = 0; | |||
57 | static void eal_alarm_callback(void *arg); | |||
58 | ||||
59 | int | |||
60 | rte_eal_alarm_init(void) | |||
61 | { | |||
62 | intr_handle.type = RTE_INTR_HANDLE_ALARM; | |||
63 | /* create a timerfd file descriptor */ | |||
64 | intr_handle.fd = timerfd_create(CLOCK_MONOTONIC1, TFD_NONBLOCKTFD_NONBLOCK); | |||
65 | if (intr_handle.fd == -1) | |||
66 | goto error; | |||
67 | ||||
68 | return 0; | |||
69 | ||||
70 | error: | |||
71 | rte_errno(per_lcore__rte_errno) = errno(*__errno_location ()); | |||
72 | return -1; | |||
73 | } | |||
74 | ||||
75 | static void | |||
76 | eal_alarm_callback(void *arg __rte_unused__attribute__((__unused__))) | |||
77 | { | |||
78 | struct timespec now; | |||
79 | struct alarm_entry *ap; | |||
80 | ||||
81 | rte_spinlock_lock(&alarm_list_lk); | |||
82 | while ((ap = LIST_FIRST(&alarm_list)((&alarm_list)->lh_first)) !=NULL((void*)0) && | |||
83 | clock_gettime(CLOCK_TYPE_ID4, &now) == 0 && | |||
84 | (ap->time.tv_sec < now.tv_sec || (ap->time.tv_sec == now.tv_sec && | |||
85 | (ap->time.tv_usec * NS_PER_US1000) <= now.tv_nsec))) { | |||
86 | ap->executing = 1; | |||
87 | ap->executing_id = pthread_self(); | |||
88 | rte_spinlock_unlock(&alarm_list_lk); | |||
89 | ||||
90 | ap->cb_fn(ap->cb_arg); | |||
91 | ||||
92 | rte_spinlock_lock(&alarm_list_lk); | |||
93 | ||||
94 | LIST_REMOVE(ap, next)do { if ((ap)->next.le_next != ((void*)0)) (ap)->next.le_next ->next.le_prev = (ap)->next.le_prev; *(ap)->next.le_prev = (ap)->next.le_next; } while ( 0); | |||
95 | free(ap); | |||
96 | } | |||
97 | ||||
98 | if (!LIST_EMPTY(&alarm_list)((&alarm_list)->lh_first == ((void*)0))) { | |||
99 | struct itimerspec atime = { .it_interval = { 0, 0 } }; | |||
100 | ||||
101 | ap = LIST_FIRST(&alarm_list)((&alarm_list)->lh_first); | |||
102 | atime.it_value.tv_sec = ap->time.tv_sec; | |||
103 | atime.it_value.tv_nsec = ap->time.tv_usec * NS_PER_US1000; | |||
104 | /* perform borrow for subtraction if necessary */ | |||
105 | if (now.tv_nsec > (ap->time.tv_usec * NS_PER_US1000)) | |||
106 | atime.it_value.tv_sec--, atime.it_value.tv_nsec += US_PER_S1000000 * NS_PER_US1000; | |||
107 | ||||
108 | atime.it_value.tv_sec -= now.tv_sec; | |||
109 | atime.it_value.tv_nsec -= now.tv_nsec; | |||
110 | timerfd_settime(intr_handle.fd, 0, &atime, NULL((void*)0)); | |||
111 | } | |||
112 | rte_spinlock_unlock(&alarm_list_lk); | |||
113 | } | |||
114 | ||||
115 | int | |||
116 | rte_eal_alarm_set(uint64_t us, rte_eal_alarm_callback cb_fn, void *cb_arg) | |||
117 | { | |||
118 | struct timespec now; | |||
119 | int ret = 0; | |||
120 | struct alarm_entry *ap, *new_alarm; | |||
121 | ||||
122 | /* Check parameters, including that us won't cause a uint64_t overflow */ | |||
123 | if (us < 1 || us > (UINT64_MAX(18446744073709551615UL) - US_PER_S1000000) || cb_fn == NULL((void*)0)) | |||
124 | return -EINVAL22; | |||
125 | ||||
126 | new_alarm = calloc(1, sizeof(*new_alarm)); | |||
127 | if (new_alarm == NULL((void*)0)) | |||
128 | return -ENOMEM12; | |||
129 | ||||
130 | /* use current time to calculate absolute time of alarm */ | |||
131 | clock_gettime(CLOCK_TYPE_ID4, &now); | |||
132 | ||||
133 | new_alarm->cb_fn = cb_fn; | |||
134 | new_alarm->cb_arg = cb_arg; | |||
135 | new_alarm->time.tv_usec = ((now.tv_nsec / NS_PER_US1000) + us) % US_PER_S1000000; | |||
136 | new_alarm->time.tv_sec = now.tv_sec + (((now.tv_nsec / NS_PER_US1000) + us) / US_PER_S1000000); | |||
137 | ||||
138 | rte_spinlock_lock(&alarm_list_lk); | |||
139 | if (!handler_registered) { | |||
140 | ret |= rte_intr_callback_register(&intr_handle, | |||
141 | eal_alarm_callback, NULL((void*)0)); | |||
142 | handler_registered = (ret == 0) ? 1 : 0; | |||
143 | } | |||
144 | ||||
145 | if (LIST_EMPTY(&alarm_list)((&alarm_list)->lh_first == ((void*)0))) | |||
146 | LIST_INSERT_HEAD(&alarm_list, new_alarm, next)do { if (((new_alarm)->next.le_next = (&alarm_list)-> lh_first) != ((void*)0)) (&alarm_list)->lh_first->next .le_prev = &(new_alarm)->next.le_next; (&alarm_list )->lh_first = (new_alarm); (new_alarm)->next.le_prev = & (&alarm_list)->lh_first; } while ( 0); | |||
147 | else { | |||
148 | LIST_FOREACH(ap, &alarm_list, next)for ((ap) = ((&alarm_list)->lh_first); (ap); (ap) = (( ap)->next.le_next)) { | |||
149 | if (ap->time.tv_sec > new_alarm->time.tv_sec || | |||
150 | (ap->time.tv_sec == new_alarm->time.tv_sec && | |||
151 | ap->time.tv_usec > new_alarm->time.tv_usec)){ | |||
152 | LIST_INSERT_BEFORE(ap, new_alarm, next)do { (new_alarm)->next.le_prev = (ap)->next.le_prev; (new_alarm )->next.le_next = (ap); *(ap)->next.le_prev = (new_alarm ); (ap)->next.le_prev = &(new_alarm)->next.le_next; } while ( 0); | |||
153 | break; | |||
154 | } | |||
155 | if (LIST_NEXT(ap, next)((ap)->next.le_next) == NULL((void*)0)) { | |||
156 | LIST_INSERT_AFTER(ap, new_alarm, next)do { if (((new_alarm)->next.le_next = (ap)->next.le_next ) != ((void*)0)) (ap)->next.le_next->next.le_prev = & (new_alarm)->next.le_next; (ap)->next.le_next = (new_alarm ); (new_alarm)->next.le_prev = &(ap)->next.le_next; } while ( 0); | |||
157 | break; | |||
158 | } | |||
159 | } | |||
160 | } | |||
161 | ||||
162 | if (LIST_FIRST(&alarm_list)((&alarm_list)->lh_first) == new_alarm) { | |||
163 | struct itimerspec alarm_time = { | |||
164 | .it_interval = {0, 0}, | |||
165 | .it_value = { | |||
166 | .tv_sec = us / US_PER_S1000000, | |||
167 | .tv_nsec = (us % US_PER_S1000000) * NS_PER_US1000, | |||
168 | }, | |||
169 | }; | |||
170 | ret |= timerfd_settime(intr_handle.fd, 0, &alarm_time, NULL((void*)0)); | |||
171 | } | |||
172 | rte_spinlock_unlock(&alarm_list_lk); | |||
173 | ||||
174 | return ret; | |||
175 | } | |||
176 | ||||
177 | int | |||
178 | rte_eal_alarm_cancel(rte_eal_alarm_callback cb_fn, void *cb_arg) | |||
179 | { | |||
180 | struct alarm_entry *ap, *ap_prev; | |||
181 | int count = 0; | |||
182 | int err = 0; | |||
183 | int executing; | |||
184 | ||||
185 | if (!cb_fn) { | |||
| ||||
186 | rte_errno(per_lcore__rte_errno) = EINVAL22; | |||
187 | return -1; | |||
188 | } | |||
189 | ||||
190 | do { | |||
191 | executing = 0; | |||
192 | rte_spinlock_lock(&alarm_list_lk); | |||
193 | /* remove any matches at the start of the list */ | |||
194 | while ((ap = LIST_FIRST(&alarm_list)((&alarm_list)->lh_first)) != NULL((void*)0) && | |||
195 | cb_fn == ap->cb_fn && | |||
196 | (cb_arg == (void *)-1 || cb_arg == ap->cb_arg)) { | |||
197 | ||||
198 | if (ap->executing == 0) { | |||
199 | LIST_REMOVE(ap, next)do { if ((ap)->next.le_next != ((void*)0)) (ap)->next.le_next ->next.le_prev = (ap)->next.le_prev; *(ap)->next.le_prev = (ap)->next.le_next; } while ( 0); | |||
200 | free(ap); | |||
201 | count++; | |||
202 | } else { | |||
203 | /* If calling from other context, mark that alarm is executing | |||
204 | * so loop can spin till it finish. Otherwise we are trying to | |||
205 | * cancel our self - mark it by EINPROGRESS */ | |||
206 | if (pthread_equal(ap->executing_id, pthread_self()) == 0) | |||
207 | executing++; | |||
208 | else | |||
209 | err = EINPROGRESS115; | |||
210 | ||||
211 | break; | |||
212 | } | |||
213 | } | |||
214 | ap_prev = ap; | |||
215 | ||||
216 | /* now go through list, removing entries not at start */ | |||
217 | LIST_FOREACH(ap, &alarm_list, next)for ((ap) = ((&alarm_list)->lh_first); (ap); (ap) = (( ap)->next.le_next)) { | |||
218 | /* this won't be true first time through */ | |||
219 | if (cb_fn == ap->cb_fn && | |||
| ||||
220 | (cb_arg == (void *)-1 || cb_arg == ap->cb_arg)) { | |||
221 | ||||
222 | if (ap->executing == 0) { | |||
223 | LIST_REMOVE(ap, next)do { if ((ap)->next.le_next != ((void*)0)) (ap)->next.le_next ->next.le_prev = (ap)->next.le_prev; *(ap)->next.le_prev = (ap)->next.le_next; } while ( 0); | |||
224 | free(ap); | |||
225 | count++; | |||
226 | ap = ap_prev; | |||
227 | } else if (pthread_equal(ap->executing_id, pthread_self()) == 0) | |||
228 | executing++; | |||
229 | else | |||
230 | err = EINPROGRESS115; | |||
231 | } | |||
232 | ap_prev = ap; | |||
233 | } | |||
234 | rte_spinlock_unlock(&alarm_list_lk); | |||
235 | } while (executing != 0); | |||
236 | ||||
237 | if (count == 0 && err == 0) | |||
238 | rte_errno(per_lcore__rte_errno) = ENOENT2; | |||
239 | else if (err) | |||
240 | rte_errno(per_lcore__rte_errno) = err; | |||
241 | ||||
242 | return count; | |||
243 | } |