Rev 2330 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 2330 | Rev 2430 | ||
---|---|---|---|
Line 28... | Line 28... | ||
28 | */ |
28 | */ |
29 | 29 | ||
30 | /** @addtogroup genericddi |
30 | /** @addtogroup genericddi |
31 | * @{ |
31 | * @{ |
32 | */ |
32 | */ |
33 | /** @file |
33 | /** @file tasklet.c |
- | 34 | * @brief Tasklet implementation |
|
34 | */ |
35 | */ |
35 | 36 | ||
36 | #include <arch.h> |
37 | #include <arch.h> |
37 | #include <config.h> |
38 | #include <config.h> |
38 | #include <arch/types.h> |
39 | #include <arch/types.h> |
Line 89... | Line 90... | ||
89 | void tasklet_run_tasklet_thread(task_t * kernel_task) |
90 | void tasklet_run_tasklet_thread(task_t * kernel_task) |
90 | { |
91 | { |
91 | //create the tasklet_thread, it's wired to the current cpu, we'll migrate it ourselves |
92 | //create the tasklet_thread, it's wired to the current cpu, we'll migrate it ourselves |
92 | thread_t* t= thread_create(&tasklet_thread, NULL, kernel_task, THREAD_FLAG_WIRED, "tasklet_thread", false); |
93 | thread_t* t= thread_create(&tasklet_thread, NULL, kernel_task, THREAD_FLAG_WIRED, "tasklet_thread", false); |
93 | if (t==NULL) { |
94 | if (t==NULL) { |
94 | //wtf? |
- | |
95 | panic_printf("tasklet thread not created\n"); |
95 | panic_printf("tasklet thread not created\n"); |
96 | } else { |
96 | } else { |
97 | spinlock_lock(&t->lock); |
97 | spinlock_lock(&t->lock); |
- | 98 | //we'll default on the first CPU |
|
98 | t->cpu = &cpus[0]; |
99 | t->cpu = &cpus[0]; |
99 | t->priority = TASKLET_THREAD_PRIORITY; |
100 | t->priority = TASKLET_THREAD_PRIORITY; |
100 | spinlock_unlock(&t->lock); |
101 | spinlock_unlock(&t->lock); |
101 | thread_ready(t); |
102 | thread_ready(t); |
102 | } |
103 | } |
Line 112... | Line 113... | ||
112 | cpu_t *cpu; |
113 | cpu_t *cpu; |
113 | #endif |
114 | #endif |
114 | waitq_t wq; |
115 | waitq_t wq; |
115 | waitq_initialize(&wq); |
116 | waitq_initialize(&wq); |
116 | 117 | ||
- | 118 | //the infinite loop |
|
117 | while (true) { |
119 | while (true) { |
- | 120 | //execute any scheduled tasklets |
|
118 | tasklet_do(); |
121 | tasklet_do(); |
119 | #ifdef CONFIG_SMP |
122 | #ifdef CONFIG_SMP |
- | 123 | //check whether other CPUs have tasklets to execute |
|
120 | if (config.cpu_active>1) { |
124 | if (config.cpu_active>1) { |
121 | current_cpu = CPU->id; |
125 | current_cpu = CPU->id; |
122 | //find the first cpu with nonempty tasklet_list |
126 | //find the first cpu with nonempty tasklet_list |
123 | for (new_cpu = (current_cpu + 1) % config.cpu_active; new_cpu!=current_cpu && tasklet_list[new_cpu]==0 && cpus[new_cpu].active; |
127 | for (new_cpu = (current_cpu + 1) % config.cpu_count; new_cpu!=current_cpu && tasklet_list[new_cpu]==0 ; |
124 | new_cpu=(new_cpu + 1)% config.cpu_active); |
128 | new_cpu=(new_cpu + 1)% config.cpu_count); |
125 | 129 | ||
- | 130 | //if we found a CPU with unsatisfied tasklet schedule to run there. It must be active! |
|
126 | if (new_cpu!=current_cpu) { |
131 | if (new_cpu!=current_cpu && cpus[new_cpu].active) { |
127 | //we need to migrate this thread to CPU with id new_cpu |
132 | //we need to migrate this thread to CPU with id new_cpu |
128 | cpu = &cpus[new_cpu]; |
133 | cpu = &cpus[new_cpu]; |
129 | 134 | ||
130 | spinlock_lock(&THREAD->lock); |
135 | spinlock_lock(&THREAD->lock); |
131 | //put tasklet_thread on the new_cpu |
136 | //move tasklet_thread on the new_cpu |
132 | THREAD->cpu = cpu; |
137 | THREAD->cpu = cpu; |
133 | spinlock_unlock(&THREAD->lock); |
138 | spinlock_unlock(&THREAD->lock); |
134 | } |
139 | } |
135 | } |
140 | } |
136 | #endif |
141 | #endif |
Line 201... | Line 206... | ||
201 | } |
206 | } |
202 | 207 | ||
203 | 208 | ||
204 | 209 | ||
205 | 210 | ||
206 | /** Executes scheduled enabled tasklets on current CPU */ |
211 | /** Executes scheduled enabled tasklets on current CPU |
- | 212 | * this function could be called from other parts of kernel */ |
|
207 | void tasklet_do(void) |
213 | void tasklet_do(void) |
208 | { |
214 | { |
209 | spinlock_lock(&tasklet_lock); |
215 | spinlock_lock(&tasklet_lock); |
210 | tasklet_descriptor_t* t = tasklet_list[CPU->id]; |
216 | tasklet_descriptor_t* t = tasklet_list[CPU->id]; |
211 | //printf("."); |
- | |
212 | if (t) { |
217 | if (t) { |
213 | //empty the tasklet_list |
218 | //empty the tasklet_list |
214 | tasklet_list[CPU->id]=0; |
219 | tasklet_list[CPU->id]=0; |
215 | spinlock_unlock(&tasklet_lock); |
220 | spinlock_unlock(&tasklet_lock); |
216 | do { |
221 | do { |
217 | if (!(t->state & TASKLET_STATE_DISABLED)) { |
222 | if (!(t->state & TASKLET_STATE_DISABLED)) { |
218 | if (t->func) { |
223 | if (t->func) { |
219 | t->state = TASKLET_STATE_RUNNING; |
224 | t->state = TASKLET_STATE_RUNNING; |
220 | t->func(t->data); |
225 | t->func(t->data); |
221 | //clear running flag, set not active - the tasklet can disable itself |
226 | //clear running flag, set not active |
222 | //thats why we don't just set it as not active |
- | |
223 | t->state &= ~TASKLET_STATE_RUNNING; |
227 | t->state &= ~TASKLET_STATE_RUNNING; |
224 | t->state |= TASKLET_STATE_NOTACTIVE; |
228 | t->state |= TASKLET_STATE_NOTACTIVE; |
225 | } else |
229 | } else |
226 | panic_printf("tasklet func NULL\n"); |
230 | panic_printf("tasklet func NULL\n"); |
227 | } else { |
231 | } else { |
Line 238... | Line 242... | ||
238 | else |
242 | else |
239 | spinlock_unlock(&tasklet_lock); |
243 | spinlock_unlock(&tasklet_lock); |
240 | } |
244 | } |
241 | 245 | ||
242 | /** Frees the tasklet structure when no longer needed. The function doesn't provide |
246 | /** Frees the tasklet structure when no longer needed. The function doesn't provide |
243 | * any synchronization, the caller must be sure, the tasklet is not scheduled. |
247 | * any synchronization, the caller must be sure, that the tasklet is not scheduled. |
244 | * |
248 | * |
245 | * @param tasklet to be freed |
249 | * @param tasklet to be freed |
246 | */ |
250 | */ |
247 | void tasklet_free(tasklet_descriptor_t* t) |
251 | void tasklet_free(tasklet_descriptor_t* t) |
248 | { |
252 | { |