Changes in kernel/generic/src/time/timeout.c [583c2a3:4760793] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/time/timeout.c
r583c2a3 r4760793 1 1 /* 2 2 * Copyright (c) 2001-2004 Jakub Jermar 3 * Copyright (c) 2022 Jiří Zárevúcky 3 4 * All rights reserved. 4 5 * … … 57 58 } 58 59 59 /** Reinitialize timeout60 *61 * Initialize all members except the lock.62 *63 * @param timeout Timeout to be initialized.64 *65 */66 void timeout_reinitialize(timeout_t *timeout)67 {68 timeout->cpu = NULL;69 timeout->ticks = 0;70 timeout->handler = NULL;71 timeout->arg = NULL;72 link_initialize(&timeout->link);73 }74 75 60 /** Initialize timeout 76 61 * … … 82 67 void timeout_initialize(timeout_t *timeout) 83 68 { 84 irq_spinlock_initialize(&timeout->lock, "timeout_t_lock"); 85 timeout_reinitialize(timeout); 69 link_initialize(&timeout->link); 70 timeout->cpu = NULL; 71 } 72 73 /* Only call when interrupts are disabled. */ 74 deadline_t timeout_deadline_in_usec(uint32_t usec) 75 { 76 if (usec == 0) 77 return 0; 78 79 return CPU_LOCAL->current_clock_tick + us2ticks(usec); 80 } 81 82 static void timeout_register_deadline_locked(timeout_t *timeout, deadline_t deadline, 83 timeout_handler_t handler, void *arg) 84 { 85 assert(!link_in_use(&timeout->link)); 86 87 *timeout = (timeout_t) { 88 .cpu = CPU, 89 .deadline = deadline, 90 .handler = handler, 91 .arg = arg, 92 .finished = ATOMIC_VAR_INIT(false), 93 }; 94 95 /* Insert timeout into the active timeouts list according to timeout->deadline. */ 96 97 link_t *last = list_last(&CPU->timeout_active_list); 98 if (last == NULL || timeout->deadline >= list_get_instance(last, timeout_t, link)->deadline) { 99 list_append(&timeout->link, &CPU->timeout_active_list); 100 } else { 101 for (link_t *cur = list_first(&CPU->timeout_active_list); cur != NULL; 102 cur = list_next(cur, &CPU->timeout_active_list)) { 103 104 if (timeout->deadline < list_get_instance(cur, timeout_t, link)->deadline) { 105 list_insert_before(&timeout->link, cur); 106 break; 107 } 108 } 109 } 86 110 } 87 111 … … 102 126 { 103 127 irq_spinlock_lock(&CPU->timeoutlock, true); 104 irq_spinlock_lock(&timeout->lock, false); 128 timeout_register_deadline_locked(timeout, timeout_deadline_in_usec(time), handler, arg); 129 irq_spinlock_unlock(&CPU->timeoutlock, true); 130 } 105 131 106 if (timeout->cpu) 107 panic("Unexpected: timeout->cpu != 0."); 108 109 timeout->cpu = CPU; 110 timeout->ticks = us2ticks(time); 111 112 timeout->handler = handler; 113 timeout->arg = arg; 114 115 /* 116 * Insert timeout into the active timeouts list according to timeout->ticks. 117 */ 118 uint64_t sum = 0; 119 timeout_t *target = NULL; 120 link_t *cur, *prev; 121 prev = NULL; 122 for (cur = list_first(&CPU->timeout_active_list); 123 cur != NULL; cur = list_next(cur, &CPU->timeout_active_list)) { 124 target = list_get_instance(cur, timeout_t, link); 125 irq_spinlock_lock(&target->lock, false); 126 127 if (timeout->ticks < sum + target->ticks) { 128 irq_spinlock_unlock(&target->lock, false); 129 break; 130 } 131 132 sum += target->ticks; 133 irq_spinlock_unlock(&target->lock, false); 134 prev = cur; 135 } 136 137 if (prev == NULL) 138 list_prepend(&timeout->link, &CPU->timeout_active_list); 139 else 140 list_insert_after(&timeout->link, prev); 141 142 /* 143 * Adjust timeout->ticks according to ticks 144 * accumulated in target's predecessors. 145 */ 146 timeout->ticks -= sum; 147 148 /* 149 * Decrease ticks of timeout's immediate succesor by timeout->ticks. 150 */ 151 if (cur != NULL) { 152 irq_spinlock_lock(&target->lock, false); 153 target->ticks -= timeout->ticks; 154 irq_spinlock_unlock(&target->lock, false); 155 } 156 157 irq_spinlock_unlock(&timeout->lock, false); 132 void timeout_register_deadline(timeout_t *timeout, deadline_t deadline, 133 timeout_handler_t handler, void *arg) 134 { 135 irq_spinlock_lock(&CPU->timeoutlock, true); 136 timeout_register_deadline_locked(timeout, deadline, handler, arg); 158 137 irq_spinlock_unlock(&CPU->timeoutlock, true); 159 138 } … … 170 149 bool timeout_unregister(timeout_t *timeout) 171 150 { 172 DEADLOCK_PROBE_INIT(p_tolock); 151 if (atomic_load_explicit(&timeout->finished, memory_order_acquire)) 152 /* The timeout fired and finished already, no need to check the list. */ 153 return false; 173 154 174 grab_locks: 175 irq_spinlock_lock(&timeout->lock, true); 176 if (!timeout->cpu) { 177 irq_spinlock_unlock(&timeout->lock, true); 178 return false; 155 assert(timeout->cpu); 156 157 irq_spinlock_lock(&timeout->cpu->timeoutlock, true); 158 159 bool success = link_in_use(&timeout->link); 160 if (success) { 161 list_remove(&timeout->link); 179 162 } 180 163 181 if (!irq_spinlock_trylock(&timeout->cpu->timeoutlock)) { 182 irq_spinlock_unlock(&timeout->lock, true); 183 DEADLOCK_PROBE(p_tolock, DEADLOCK_THRESHOLD); 184 goto grab_locks; 164 irq_spinlock_unlock(&timeout->cpu->timeoutlock, true); 165 166 if (!success) { 167 /* Timeout was fired, we need to wait for the callback to finish. */ 168 while (!atomic_load_explicit(&timeout->finished, memory_order_acquire)) 169 cpu_spin_hint(); 185 170 } 186 171 187 /* 188 * Now we know for sure that timeout hasn't been activated yet 189 * and is lurking in timeout->cpu->timeout_active_list. 190 */ 191 192 link_t *cur = list_next(&timeout->link, 193 &timeout->cpu->timeout_active_list); 194 if (cur != NULL) { 195 timeout_t *tmp = list_get_instance(cur, timeout_t, link); 196 irq_spinlock_lock(&tmp->lock, false); 197 tmp->ticks += timeout->ticks; 198 irq_spinlock_unlock(&tmp->lock, false); 199 } 200 201 list_remove(&timeout->link); 202 irq_spinlock_unlock(&timeout->cpu->timeoutlock, false); 203 204 timeout_reinitialize(timeout); 205 irq_spinlock_unlock(&timeout->lock, true); 206 207 return true; 172 return success; 208 173 } 209 174
Note:
See TracChangeset
for help on using the changeset viewer.