Rev 2050 | Rev 2071 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 2050 | Rev 2067 | ||
|---|---|---|---|
| Line 78... | Line 78... | ||
| 78 | "Entering", |
78 | "Entering", |
| 79 | "Exiting", |
79 | "Exiting", |
| 80 | "Undead" |
80 | "Undead" |
| 81 | }; |
81 | }; |
| 82 | 82 | ||
| - | 83 | /** Lock protecting the threads_btree B+tree. |
|
| - | 84 | * |
|
| 83 | /** Lock protecting the threads_btree B+tree. For locking rules, see declaration thereof. */ |
85 | * For locking rules, see declaration thereof. |
| - | 86 | */ |
|
| 84 | SPINLOCK_INITIALIZE(threads_lock); |
87 | SPINLOCK_INITIALIZE(threads_lock); |
| 85 | 88 | ||
| 86 | /** B+tree of all threads. |
89 | /** B+tree of all threads. |
| 87 | * |
90 | * |
| 88 | * When a thread is found in the threads_btree B+tree, it is guaranteed to exist as long |
91 | * When a thread is found in the threads_btree B+tree, it is guaranteed to |
| 89 | * as the threads_lock is held. |
92 | * exist as long as the threads_lock is held. |
| 90 | */ |
93 | */ |
| 91 | btree_t threads_btree; |
94 | btree_t threads_btree; |
| 92 | 95 | ||
| 93 | SPINLOCK_INITIALIZE(tidlock); |
96 | SPINLOCK_INITIALIZE(tidlock); |
| 94 | uint32_t last_tid = 0; |
97 | uint32_t last_tid = 0; |
| Line 96... | Line 99... | ||
| 96 | static slab_cache_t *thread_slab; |
99 | static slab_cache_t *thread_slab; |
| 97 | #ifdef ARCH_HAS_FPU |
100 | #ifdef ARCH_HAS_FPU |
| 98 | slab_cache_t *fpu_context_slab; |
101 | slab_cache_t *fpu_context_slab; |
| 99 | #endif |
102 | #endif |
| 100 | 103 | ||
| 101 | /** Thread wrapper |
104 | /** Thread wrapper. |
| 102 | * |
105 | * |
| 103 | * This wrapper is provided to ensure that every thread |
106 | * This wrapper is provided to ensure that every thread makes a call to |
| 104 | * makes a call to thread_exit() when its implementing |
107 | * thread_exit() when its implementing function returns. |
| 105 | * function returns. |
- | |
| 106 | * |
108 | * |
| 107 | * interrupts_disable() is assumed. |
109 | * interrupts_disable() is assumed. |
| 108 | * |
110 | * |
| 109 | */ |
111 | */ |
| 110 | static void cushion(void) |
112 | static void cushion(void) |
| Line 199... | Line 201... | ||
| 199 | */ |
201 | */ |
| 200 | void thread_init(void) |
202 | void thread_init(void) |
| 201 | { |
203 | { |
| 202 | THREAD = NULL; |
204 | THREAD = NULL; |
| 203 | atomic_set(&nrdy,0); |
205 | atomic_set(&nrdy,0); |
| 204 | thread_slab = slab_cache_create("thread_slab", |
206 | thread_slab = slab_cache_create("thread_slab", sizeof(thread_t), 0, |
| 205 | sizeof(thread_t),0, |
- | |
| 206 | thr_constructor, thr_destructor, 0); |
207 | thr_constructor, thr_destructor, 0); |
| - | 208 | ||
| 207 | #ifdef ARCH_HAS_FPU |
209 | #ifdef ARCH_HAS_FPU |
| 208 | fpu_context_slab = slab_cache_create("fpu_slab", |
210 | fpu_context_slab = slab_cache_create("fpu_slab", sizeof(fpu_context_t), |
| 209 | sizeof(fpu_context_t), |
- | |
| 210 | FPU_CONTEXT_ALIGN, |
- | |
| 211 | NULL, NULL, 0); |
211 | FPU_CONTEXT_ALIGN, NULL, NULL, 0); |
| 212 | #endif |
212 | #endif |
| 213 | 213 | ||
| 214 | btree_create(&threads_btree); |
214 | btree_create(&threads_btree); |
| 215 | } |
215 | } |
| 216 | 216 | ||
| Line 232... | Line 232... | ||
| 232 | 232 | ||
| 233 | spinlock_lock(&t->lock); |
233 | spinlock_lock(&t->lock); |
| 234 | 234 | ||
| 235 | ASSERT(! (t->state == Ready)); |
235 | ASSERT(! (t->state == Ready)); |
| 236 | 236 | ||
| 237 | i = (t->priority < RQ_COUNT -1) ? ++t->priority : t->priority; |
237 | i = (t->priority < RQ_COUNT - 1) ? ++t->priority : t->priority; |
| 238 | 238 | ||
| 239 | cpu = CPU; |
239 | cpu = CPU; |
| 240 | if (t->flags & THREAD_FLAG_WIRED) { |
240 | if (t->flags & THREAD_FLAG_WIRED) { |
| 241 | cpu = t->cpu; |
241 | cpu = t->cpu; |
| 242 | } |
242 | } |
| Line 265... | Line 265... | ||
| 265 | * |
265 | * |
| 266 | * Assume thread->lock is held!! |
266 | * Assume thread->lock is held!! |
| 267 | */ |
267 | */ |
| 268 | void thread_destroy(thread_t *t) |
268 | void thread_destroy(thread_t *t) |
| 269 | { |
269 | { |
| 270 | bool destroy_task = false; |
270 | bool destroy_task = false; |
| 271 | 271 | ||
| 272 | ASSERT(t->state == Exiting || t->state == Undead); |
272 | ASSERT(t->state == Exiting || t->state == Undead); |
| 273 | ASSERT(t->task); |
273 | ASSERT(t->task); |
| 274 | ASSERT(t->cpu); |
274 | ASSERT(t->cpu); |
| 275 | 275 | ||
| 276 | spinlock_lock(&t->cpu->lock); |
276 | spinlock_lock(&t->cpu->lock); |
| 277 | if(t->cpu->fpu_owner==t) |
277 | if(t->cpu->fpu_owner == t) |
| 278 | t->cpu->fpu_owner=NULL; |
278 | t->cpu->fpu_owner = NULL; |
| 279 | spinlock_unlock(&t->cpu->lock); |
279 | spinlock_unlock(&t->cpu->lock); |
| 280 | 280 | ||
| 281 | spinlock_unlock(&t->lock); |
281 | spinlock_unlock(&t->lock); |
| 282 | 282 | ||
| 283 | spinlock_lock(&threads_lock); |
283 | spinlock_lock(&threads_lock); |
| Line 308... | Line 308... | ||
| 308 | * @param func Thread's implementing function. |
308 | * @param func Thread's implementing function. |
| 309 | * @param arg Thread's implementing function argument. |
309 | * @param arg Thread's implementing function argument. |
| 310 | * @param task Task to which the thread belongs. |
310 | * @param task Task to which the thread belongs. |
| 311 | * @param flags Thread flags. |
311 | * @param flags Thread flags. |
| 312 | * @param name Symbolic name. |
312 | * @param name Symbolic name. |
| 313 | * @param uncounted Thread's accounting doesn't affect accumulated task accounting. |
313 | * @param uncounted Thread's accounting doesn't affect accumulated task |
| - | 314 | * accounting. |
|
| 314 | * |
315 | * |
| 315 | * @return New thread's structure on success, NULL on failure. |
316 | * @return New thread's structure on success, NULL on failure. |
| 316 | * |
317 | * |
| 317 | */ |
318 | */ |
| 318 | thread_t *thread_create(void (* func)(void *), void *arg, task_t *task, int flags, char *name, bool uncounted) |
319 | thread_t *thread_create(void (* func)(void *), void *arg, task_t *task, |
| - | 320 | int flags, char *name, bool uncounted) |
|
| 319 | { |
321 | { |
| 320 | thread_t *t; |
322 | thread_t *t; |
| 321 | ipl_t ipl; |
323 | ipl_t ipl; |
| 322 | 324 | ||
| 323 | t = (thread_t *) slab_alloc(thread_slab, 0); |
325 | t = (thread_t *) slab_alloc(thread_slab, 0); |
| 324 | if (!t) |
326 | if (!t) |
| 325 | return NULL; |
327 | return NULL; |
| 326 | 328 | ||
| 327 | /* Not needed, but good for debugging */ |
329 | /* Not needed, but good for debugging */ |
| 328 | memsetb((uintptr_t) t->kstack, THREAD_STACK_SIZE * 1 << STACK_FRAMES, 0); |
330 | memsetb((uintptr_t) t->kstack, THREAD_STACK_SIZE * 1 << STACK_FRAMES, |
| - | 331 | 0); |
|
| 329 | 332 | ||
| 330 | ipl = interrupts_disable(); |
333 | ipl = interrupts_disable(); |
| 331 | spinlock_lock(&tidlock); |
334 | spinlock_lock(&tidlock); |
| 332 | t->tid = ++last_tid; |
335 | t->tid = ++last_tid; |
| 333 | spinlock_unlock(&tidlock); |
336 | spinlock_unlock(&tidlock); |
| 334 | interrupts_restore(ipl); |
337 | interrupts_restore(ipl); |
| 335 | 338 | ||
| 336 | context_save(&t->saved_context); |
339 | context_save(&t->saved_context); |
| 337 | context_set(&t->saved_context, FADDR(cushion), (uintptr_t) t->kstack, THREAD_STACK_SIZE); |
340 | context_set(&t->saved_context, FADDR(cushion), (uintptr_t) t->kstack, |
| - | 341 | THREAD_STACK_SIZE); |
|
| 338 | 342 | ||
| 339 | the_initialize((the_t *) t->kstack); |
343 | the_initialize((the_t *) t->kstack); |
| 340 | 344 | ||
| 341 | ipl = interrupts_disable(); |
345 | ipl = interrupts_disable(); |
| 342 | t->saved_context.ipl = interrupts_read(); |
346 | t->saved_context.ipl = interrupts_read(); |
| Line 374... | Line 378... | ||
| 374 | t->task = task; |
378 | t->task = task; |
| 375 | 379 | ||
| 376 | t->fpu_context_exists = 0; |
380 | t->fpu_context_exists = 0; |
| 377 | t->fpu_context_engaged = 0; |
381 | t->fpu_context_engaged = 0; |
| 378 | 382 | ||
| 379 | thread_create_arch(t); /* might depend on previous initialization */ |
383 | /* might depend on previous initialization */ |
| - | 384 | thread_create_arch(t); |
|
| 380 | 385 | ||
| 381 | /* |
386 | /* |
| 382 | * Attach to the containing task. |
387 | * Attach to the containing task. |
| 383 | */ |
388 | */ |
| 384 | ipl = interrupts_disable(); |
389 | ipl = interrupts_disable(); |
| Line 396... | Line 401... | ||
| 396 | 401 | ||
| 397 | /* |
402 | /* |
| 398 | * Register this thread in the system-wide list. |
403 | * Register this thread in the system-wide list. |
| 399 | */ |
404 | */ |
| 400 | spinlock_lock(&threads_lock); |
405 | spinlock_lock(&threads_lock); |
| 401 | btree_insert(&threads_btree, (btree_key_t) ((uintptr_t) t), (void *) t, NULL); |
406 | btree_insert(&threads_btree, (btree_key_t) ((uintptr_t) t), (void *) t, |
| - | 407 | NULL); |
|
| 402 | spinlock_unlock(&threads_lock); |
408 | spinlock_unlock(&threads_lock); |
| 403 | 409 | ||
| 404 | interrupts_restore(ipl); |
410 | interrupts_restore(ipl); |
| 405 | 411 | ||
| 406 | return t; |
412 | return t; |
| 407 | } |
413 | } |
| 408 | 414 | ||
| 409 | /** Terminate thread. |
415 | /** Terminate thread. |
| 410 | * |
416 | * |
| 411 | * End current thread execution and switch it to the exiting |
417 | * End current thread execution and switch it to the exiting state. All pending |
| 412 | * state. All pending timeouts are executed. |
418 | * timeouts are executed. |
| 413 | * |
- | |
| 414 | */ |
419 | */ |
| 415 | void thread_exit(void) |
420 | void thread_exit(void) |
| 416 | { |
421 | { |
| 417 | ipl_t ipl; |
422 | ipl_t ipl; |
| 418 | 423 | ||
| 419 | restart: |
424 | restart: |
| 420 | ipl = interrupts_disable(); |
425 | ipl = interrupts_disable(); |
| 421 | spinlock_lock(&THREAD->lock); |
426 | spinlock_lock(&THREAD->lock); |
| - | 427 | if (THREAD->timeout_pending) { |
|
| 422 | if (THREAD->timeout_pending) { /* busy waiting for timeouts in progress */ |
428 | /* busy waiting for timeouts in progress */ |
| 423 | spinlock_unlock(&THREAD->lock); |
429 | spinlock_unlock(&THREAD->lock); |
| 424 | interrupts_restore(ipl); |
430 | interrupts_restore(ipl); |
| 425 | goto restart; |
431 | goto restart; |
| 426 | } |
432 | } |
| 427 | THREAD->state = Exiting; |
433 | THREAD->state = Exiting; |
| Line 441... | Line 447... | ||
| 441 | * @param sec Number of seconds to sleep. |
447 | * @param sec Number of seconds to sleep. |
| 442 | * |
448 | * |
| 443 | */ |
449 | */ |
| 444 | void thread_sleep(uint32_t sec) |
450 | void thread_sleep(uint32_t sec) |
| 445 | { |
451 | { |
| 446 | thread_usleep(sec*1000000); |
452 | thread_usleep(sec * 1000000); |
| 447 | } |
453 | } |
| 448 | 454 | ||
| 449 | /** Wait for another thread to exit. |
455 | /** Wait for another thread to exit. |
| 450 | * |
456 | * |
| 451 | * @param t Thread to join on exit. |
457 | * @param t Thread to join on exit. |