Changes in kernel/generic/src/time/timeout.c [4760793:583c2a3] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/time/timeout.c
r4760793 r583c2a3 1 1 /* 2 2 * Copyright (c) 2001-2004 Jakub Jermar 3 * Copyright (c) 2022 Jiří Zárevúcky4 3 * All rights reserved. 5 4 * … … 58 57 } 59 58 59 /** Reinitialize timeout 60 * 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 60 75 /** Initialize timeout 61 76 * … … 67 82 void timeout_initialize(timeout_t *timeout) 68 83 { 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 } 84 irq_spinlock_initialize(&timeout->lock, "timeout_t_lock"); 85 timeout_reinitialize(timeout); 110 86 } 111 87 … … 126 102 { 127 103 irq_spinlock_lock(&CPU->timeoutlock, true); 128 timeout_register_deadline_locked(timeout, timeout_deadline_in_usec(time), handler, arg); 104 irq_spinlock_lock(&timeout->lock, false); 105 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); 129 158 irq_spinlock_unlock(&CPU->timeoutlock, true); 130 159 } 131 160 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);137 irq_spinlock_unlock(&CPU->timeoutlock, true);138 }139 140 161 /** Unregister timeout 141 162 * … … 149 170 bool timeout_unregister(timeout_t *timeout) 150 171 { 151 if (atomic_load_explicit(&timeout->finished, memory_order_acquire)) 152 /* The timeout fired and finished already, no need to check the list. */ 172 DEADLOCK_PROBE_INIT(p_tolock); 173 174 grab_locks: 175 irq_spinlock_lock(&timeout->lock, true); 176 if (!timeout->cpu) { 177 irq_spinlock_unlock(&timeout->lock, true); 153 178 return false; 154 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); 162 } 163 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(); 170 } 171 172 return success; 179 } 180 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; 185 } 186 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; 173 208 } 174 209
Note:
See TracChangeset
for help on using the changeset viewer.