| 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 | } |