Changeset da1bafb in mainline for kernel/generic/src/time
- Timestamp:
- 2010-05-24T18:57:31Z (15 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 0095368
- Parents:
- 666f492
- Location:
- kernel/generic/src/time
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/time/clock.c
r666f492 rda1bafb 33 33 /** 34 34 * @file 35 * @brief 35 * @brief High-level clock interrupt handler. 36 36 * 37 37 * This file contains the clock() function which is the source 38 38 * of preemption. It is also responsible for executing expired 39 39 * timeouts. 40 */ 41 40 * 41 */ 42 42 43 #include <time/clock.h> 43 44 #include <time/timeout.h> … … 63 64 static parea_t clock_parea; 64 65 65 /* Variable holding fragment of second, so that we would update 66 * seconds correctly 66 /** Fragment of second 67 * 68 * For updating seconds correctly. 69 * 67 70 */ 68 71 static unative_t secfrag = 0; … … 73 76 * information about realtime data. We allocate 1 page with these 74 77 * data and update it periodically. 78 * 75 79 */ 76 80 void clock_counter_init(void) 77 81 { 78 void *faddr; 79 80 faddr = frame_alloc(ONE_FRAME, FRAME_ATOMIC); 82 void *faddr = frame_alloc(ONE_FRAME, FRAME_ATOMIC); 81 83 if (!faddr) 82 84 panic("Cannot allocate page for clock."); … … 87 89 uptime->seconds2 = 0; 88 90 uptime->useconds = 0; 89 91 90 92 clock_parea.pbase = (uintptr_t) faddr; 91 93 clock_parea.frames = 1; 92 94 ddi_parea_register(&clock_parea); 93 95 94 96 /* 95 97 * Prepare information for the userspace so that it can successfully 96 98 * physmem_map() the clock_parea. 99 * 97 100 */ 98 101 sysinfo_set_item_val("clock.cacheable", NULL, (unative_t) true); … … 100 103 } 101 104 102 103 105 /** Update public counters 104 106 * 105 107 * Update it only on first processor 106 * TODO: Do we really need so many write barriers? 108 * TODO: Do we really need so many write barriers? 109 * 107 110 */ 108 111 static void clock_update_counters(void) … … 131 134 void clock(void) 132 135 { 133 link_t *l;134 timeout_t *h;135 timeout_handler_t f;136 void *arg;137 136 size_t missed_clock_ticks = CPU->missed_clock_ticks; 138 unsigned int i; 139 137 140 138 /* Account lost ticks to CPU usage */ 141 if (CPU->idle) {139 if (CPU->idle) 142 140 CPU->idle_ticks += missed_clock_ticks + 1; 143 } else {141 else 144 142 CPU->busy_ticks += missed_clock_ticks + 1; 145 }143 146 144 CPU->idle = false; 147 145 148 146 /* 149 147 * To avoid lock ordering problems, 150 148 * run all expired timeouts as you visit them. 149 * 151 150 */ 151 size_t i; 152 152 for (i = 0; i <= missed_clock_ticks; i++) { 153 153 clock_update_counters(); 154 spinlock_lock(&CPU->timeoutlock); 155 while ((l = CPU->timeout_active_head.next) != &CPU->timeout_active_head) { 156 h = list_get_instance(l, timeout_t, link); 157 spinlock_lock(&h->lock); 158 if (h->ticks-- != 0) { 159 spinlock_unlock(&h->lock); 154 irq_spinlock_lock(&CPU->timeoutlock, false); 155 156 link_t *cur; 157 while ((cur = CPU->timeout_active_head.next) != &CPU->timeout_active_head) { 158 timeout_t *timeout = list_get_instance(cur, timeout_t, link); 159 160 irq_spinlock_lock(&timeout->lock, false); 161 if (timeout->ticks-- != 0) { 162 irq_spinlock_unlock(&timeout->lock, false); 160 163 break; 161 164 } 162 list_remove(l); 163 f = h->handler; 164 arg = h->arg; 165 timeout_reinitialize(h); 166 spinlock_unlock(&h->lock); 167 spinlock_unlock(&CPU->timeoutlock); 168 169 f(arg); 170 171 spinlock_lock(&CPU->timeoutlock); 165 166 list_remove(cur); 167 timeout_handler_t handler = timeout->handler; 168 void *arg = timeout->arg; 169 timeout_reinitialize(timeout); 170 171 irq_spinlock_unlock(&timeout->lock, false); 172 irq_spinlock_unlock(&CPU->timeoutlock, false); 173 174 handler(arg); 175 176 irq_spinlock_lock(&CPU->timeoutlock, false); 172 177 } 173 spinlock_unlock(&CPU->timeoutlock); 178 179 irq_spinlock_unlock(&CPU->timeoutlock, false); 174 180 } 175 181 CPU->missed_clock_ticks = 0; 176 182 177 183 /* 178 184 * Do CPU usage accounting and find out whether to preempt THREAD. 185 * 179 186 */ 180 187 181 188 if (THREAD) { 182 189 uint64_t ticks; 183 190 184 spinlock_lock(&CPU->lock);191 irq_spinlock_lock(&CPU->lock, false); 185 192 CPU->needs_relink += 1 + missed_clock_ticks; 186 spinlock_unlock(&CPU->lock);187 188 spinlock_lock(&THREAD->lock);193 irq_spinlock_unlock(&CPU->lock, false); 194 195 irq_spinlock_lock(&THREAD->lock, false); 189 196 if ((ticks = THREAD->ticks)) { 190 197 if (ticks >= 1 + missed_clock_ticks) … … 193 200 THREAD->ticks = 0; 194 201 } 195 spinlock_unlock(&THREAD->lock);202 irq_spinlock_unlock(&THREAD->lock, false); 196 203 197 204 if ((!ticks) && (!PREEMPTION_DISABLED)) { 198 #ifdef CONFIG_UDEBUG199 istate_t *istate;200 #endif201 205 scheduler(); 202 206 #ifdef CONFIG_UDEBUG … … 205 209 * before it begins executing userspace code. 206 210 */ 207 istate = THREAD->udebug.uspace_state;208 if ( istate && istate_from_uspace(istate))211 istate_t *istate = THREAD->udebug.uspace_state; 212 if ((istate) && (istate_from_uspace(istate))) 209 213 udebug_before_thread_runs(); 210 214 #endif 211 215 } 212 216 } 213 214 217 } 215 218 -
kernel/generic/src/time/timeout.c
r666f492 rda1bafb 33 33 /** 34 34 * @file 35 * @brief 35 * @brief Timeout management functions. 36 36 */ 37 37 … … 53 53 void timeout_init(void) 54 54 { 55 spinlock_initialize(&CPU->timeoutlock, "timeout_lock");55 irq_spinlock_initialize(&CPU->timeoutlock, "cpu.timeoutlock"); 56 56 list_initialize(&CPU->timeout_active_head); 57 57 } 58 58 59 60 /** Reinitialize timeout 59 /** Reinitialize timeout 61 60 * 62 61 * Initialize all members except the lock. 63 62 * 64 * @param t Timeout to be initialized. 65 * 66 */ 67 void timeout_reinitialize(timeout_t *t) 68 { 69 t->cpu = NULL; 70 t->ticks = 0; 71 t->handler = NULL; 72 t->arg = NULL; 73 link_initialize(&t->link); 74 } 75 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 } 76 74 77 75 /** Initialize timeout … … 79 77 * Initialize all members including the lock. 80 78 * 81 * @param t Timeout to be initialized. 82 * 83 */ 84 void timeout_initialize(timeout_t *t) 85 { 86 spinlock_initialize(&t->lock, "timeout_t_lock"); 87 timeout_reinitialize(t); 88 } 89 79 * @param timeout Timeout to be initialized. 80 * 81 */ 82 void timeout_initialize(timeout_t *timeout) 83 { 84 irq_spinlock_initialize(&timeout->lock, "timeout_t_lock"); 85 timeout_reinitialize(timeout); 86 } 90 87 91 88 /** Register timeout … … 95 92 * time microseconds (or slightly more). 96 93 * 97 * @param t Timeout structure. 98 * @param time Number of usec in the future to execute the handler. 99 * @param f Timeout handler function. 100 * @param arg Timeout handler argument. 101 * 102 */ 103 void 104 timeout_register(timeout_t *t, uint64_t time, timeout_handler_t f, void *arg) 105 { 106 timeout_t *hlp = NULL; 107 link_t *l, *m; 108 ipl_t ipl; 109 uint64_t sum; 110 111 ipl = interrupts_disable(); 112 spinlock_lock(&CPU->timeoutlock); 113 spinlock_lock(&t->lock); 114 115 if (t->cpu) 116 panic("Unexpected: t->cpu != 0."); 117 118 t->cpu = CPU; 119 t->ticks = us2ticks(time); 120 121 t->handler = f; 122 t->arg = arg; 123 124 /* 125 * Insert t into the active timeouts list according to t->ticks. 126 */ 127 sum = 0; 128 l = CPU->timeout_active_head.next; 129 while (l != &CPU->timeout_active_head) { 130 hlp = list_get_instance(l, timeout_t, link); 131 spinlock_lock(&hlp->lock); 132 if (t->ticks < sum + hlp->ticks) { 133 spinlock_unlock(&hlp->lock); 94 * @param timeout Timeout structure. 95 * @param time Number of usec in the future to execute the handler. 96 * @param handler Timeout handler function. 97 * @param arg Timeout handler argument. 98 * 99 */ 100 void timeout_register(timeout_t *timeout, uint64_t time, 101 timeout_handler_t handler, void *arg) 102 { 103 irq_spinlock_lock(&CPU->timeoutlock, true); 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; 121 for (cur = CPU->timeout_active_head.next; 122 cur != &CPU->timeout_active_head; cur = cur->next) { 123 target = list_get_instance(cur, timeout_t, link); 124 irq_spinlock_lock(&target->lock, false); 125 126 if (timeout->ticks < sum + target->ticks) { 127 irq_spinlock_unlock(&target->lock, false); 134 128 break; 135 129 } 136 sum += hlp->ticks;137 s pinlock_unlock(&hlp->lock);138 l = l->next;139 } 140 141 m = l->prev;142 li st_prepend(&t->link, m); /* avoid using l->prev */143 144 /*145 * Adjust t->ticks according to ticks accumulated in h's predecessors.146 * /147 t->ticks -= sum;148 149 /*150 * Decrease ticks of t's immediate succesor by t->ticks.151 */152 if (l != &CPU->timeout_active_head) {153 spinlock_lock(&hlp->lock);154 hlp->ticks -= t->ticks;155 spinlock_unlock(&hlp->lock);156 }157 158 spinlock_unlock(&t->lock);159 spinlock_unlock(&CPU->timeoutlock);160 i nterrupts_restore(ipl);161 } 162 130 131 sum += target->ticks; 132 irq_spinlock_unlock(&target->lock, false); 133 } 134 135 /* Avoid using cur->prev directly */ 136 link_t *prev = cur->prev; 137 list_prepend(&timeout->link, prev); 138 139 /* 140 * Adjust timeout->ticks according to ticks 141 * accumulated in target's predecessors. 142 */ 143 timeout->ticks -= sum; 144 145 /* 146 * Decrease ticks of timeout's immediate succesor by timeout->ticks. 147 */ 148 if (cur != &CPU->timeout_active_head) { 149 irq_spinlock_lock(&target->lock, false); 150 target->ticks -= timeout->ticks; 151 irq_spinlock_unlock(&target->lock, false); 152 } 153 154 irq_spinlock_unlock(&timeout->lock, false); 155 irq_spinlock_unlock(&CPU->timeoutlock, true); 156 } 163 157 164 158 /** Unregister timeout … … 166 160 * Remove timeout from timeout list. 167 161 * 168 * @param t Timeout to unregister. 169 * 170 * @return True on success, false on failure. 171 */ 172 bool timeout_unregister(timeout_t *t) 173 { 174 timeout_t *hlp; 175 link_t *l; 176 ipl_t ipl; 162 * @param timeout Timeout to unregister. 163 * 164 * @return True on success, false on failure. 165 * 166 */ 167 bool timeout_unregister(timeout_t *timeout) 168 { 177 169 DEADLOCK_PROBE_INIT(p_tolock); 178 170 179 171 grab_locks: 180 ipl = interrupts_disable(); 181 spinlock_lock(&t->lock); 182 if (!t->cpu) { 183 spinlock_unlock(&t->lock); 184 interrupts_restore(ipl); 172 irq_spinlock_lock(&timeout->lock, true); 173 if (!timeout->cpu) { 174 irq_spinlock_unlock(&timeout->lock, true); 185 175 return false; 186 176 } 187 if (!spinlock_trylock(&t->cpu->timeoutlock)) {188 spinlock_unlock(&t->lock);189 i nterrupts_restore(ipl);177 178 if (!irq_spinlock_trylock(&timeout->cpu->timeoutlock)) { 179 irq_spinlock_unlock(&timeout->lock, true); 190 180 DEADLOCK_PROBE(p_tolock, DEADLOCK_THRESHOLD); 191 181 goto grab_locks; … … 193 183 194 184 /* 195 * Now we know for sure that t hasn't been activated yet 196 * and is lurking in t->cpu->timeout_active_head queue. 197 */ 198 199 l = t->link.next; 200 if (l != &t->cpu->timeout_active_head) { 201 hlp = list_get_instance(l, timeout_t, link); 202 spinlock_lock(&hlp->lock); 203 hlp->ticks += t->ticks; 204 spinlock_unlock(&hlp->lock); 205 } 206 207 list_remove(&t->link); 208 spinlock_unlock(&t->cpu->timeoutlock); 209 210 timeout_reinitialize(t); 211 spinlock_unlock(&t->lock); 212 213 interrupts_restore(ipl); 185 * Now we know for sure that timeout hasn't been activated yet 186 * and is lurking in timeout->cpu->timeout_active_head queue. 187 */ 188 189 link_t *cur = timeout->link.next; 190 if (cur != &timeout->cpu->timeout_active_head) { 191 timeout_t *tmp = list_get_instance(cur, timeout_t, link); 192 irq_spinlock_lock(&tmp->lock, false); 193 tmp->ticks += timeout->ticks; 194 irq_spinlock_unlock(&tmp->lock, false); 195 } 196 197 list_remove(&timeout->link); 198 irq_spinlock_unlock(&timeout->cpu->timeoutlock, false); 199 200 timeout_reinitialize(timeout); 201 irq_spinlock_unlock(&timeout->lock, true); 202 214 203 return true; 215 204 }
Note:
See TracChangeset
for help on using the changeset viewer.