Rev 2446 | Rev 2632 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 2446 | Rev 2504 | ||
---|---|---|---|
Line 44... | Line 44... | ||
44 | #include <atomic.h> |
44 | #include <atomic.h> |
45 | #include <synch/spinlock.h> |
45 | #include <synch/spinlock.h> |
46 | #include <synch/waitq.h> |
46 | #include <synch/waitq.h> |
47 | #include <arch.h> |
47 | #include <arch.h> |
48 | #include <panic.h> |
48 | #include <panic.h> |
- | 49 | #include <adt/avl.h> |
|
49 | #include <adt/btree.h> |
50 | #include <adt/btree.h> |
50 | #include <adt/list.h> |
51 | #include <adt/list.h> |
51 | #include <ipc/ipc.h> |
52 | #include <ipc/ipc.h> |
52 | #include <security/cap.h> |
53 | #include <security/cap.h> |
53 | #include <memstr.h> |
54 | #include <memstr.h> |
Line 59... | Line 60... | ||
59 | 60 | ||
60 | #ifndef LOADED_PROG_STACK_PAGES_NO |
61 | #ifndef LOADED_PROG_STACK_PAGES_NO |
61 | #define LOADED_PROG_STACK_PAGES_NO 1 |
62 | #define LOADED_PROG_STACK_PAGES_NO 1 |
62 | #endif |
63 | #endif |
63 | 64 | ||
64 | /** Spinlock protecting the tasks_btree B+tree. */ |
65 | /** Spinlock protecting the tasks_tree AVL tree. */ |
65 | SPINLOCK_INITIALIZE(tasks_lock); |
66 | SPINLOCK_INITIALIZE(tasks_lock); |
66 | 67 | ||
67 | /** B+tree of active tasks. |
68 | /** AVL tree of active tasks. |
68 | * |
69 | * |
69 | * The task is guaranteed to exist after it was found in the tasks_btree as |
70 | * The task is guaranteed to exist after it was found in the tasks_tree as |
70 | * long as: |
71 | * long as: |
71 | * @li the tasks_lock is held, |
72 | * @li the tasks_lock is held, |
72 | * @li the task's lock is held when task's lock is acquired before releasing |
73 | * @li the task's lock is held when task's lock is acquired before releasing |
73 | * tasks_lock or |
74 | * tasks_lock or |
74 | * @li the task's refcount is greater than 0 |
75 | * @li the task's refcount is greater than 0 |
75 | * |
76 | * |
76 | */ |
77 | */ |
77 | btree_t tasks_btree; |
78 | avltree_t tasks_tree; |
78 | 79 | ||
79 | static task_id_t task_counter = 0; |
80 | static task_id_t task_counter = 0; |
80 | 81 | ||
81 | /** Initialize tasks |
82 | /** Initialize tasks |
82 | * |
83 | * |
Line 84... | Line 85... | ||
84 | * |
85 | * |
85 | */ |
86 | */ |
86 | void task_init(void) |
87 | void task_init(void) |
87 | { |
88 | { |
88 | TASK = NULL; |
89 | TASK = NULL; |
89 | btree_create(&tasks_btree); |
90 | avltree_create(&tasks_tree); |
- | 91 | } |
|
- | 92 | ||
- | 93 | /* |
|
- | 94 | * The idea behind this walker is to remember a single task different from TASK. |
|
- | 95 | */ |
|
- | 96 | static bool task_done_walker(avltree_node_t *node, void *arg) |
|
- | 97 | { |
|
- | 98 | task_t *t = avltree_get_instance(node, task_t, tasks_tree_node); |
|
- | 99 | task_t **tp = (task_t **) arg; |
|
- | 100 | ||
- | 101 | if (t != TASK) { |
|
- | 102 | *tp = t; |
|
- | 103 | return false; /* stop walking */ |
|
- | 104 | } |
|
- | 105 | ||
- | 106 | return true; /* continue the walk */ |
|
90 | } |
107 | } |
91 | 108 | ||
92 | /** Kill all tasks except the current task. |
109 | /** Kill all tasks except the current task. |
93 | * |
110 | * |
94 | */ |
111 | */ |
Line 100... | Line 117... | ||
100 | /* Messing with task structures, avoid deadlock */ |
117 | /* Messing with task structures, avoid deadlock */ |
101 | ipl_t ipl = interrupts_disable(); |
118 | ipl_t ipl = interrupts_disable(); |
102 | spinlock_lock(&tasks_lock); |
119 | spinlock_lock(&tasks_lock); |
103 | 120 | ||
104 | t = NULL; |
121 | t = NULL; |
105 | link_t *cur; |
- | |
106 | for (cur = tasks_btree.leaf_head.next; |
122 | avltree_walk(&tasks_tree, task_done_walker, &t); |
107 | cur != &tasks_btree.leaf_head; cur = cur->next) { |
- | |
108 | btree_node_t *node; |
- | |
109 | - | ||
110 | node = list_get_instance(cur, btree_node_t, leaf_link); |
- | |
111 | - | ||
112 | unsigned int i; |
- | |
113 | for (i = 0; i < node->keys; i++) { |
- | |
114 | if ((task_t *) node->value[i] != TASK) { |
- | |
115 | t = (task_t *) node->value[i]; |
- | |
116 | break; |
- | |
117 | } |
- | |
118 | } |
- | |
119 | } |
- | |
120 | 123 | ||
121 | if (t != NULL) { |
124 | if (t != NULL) { |
122 | task_id_t id = t->taskid; |
125 | task_id_t id = t->taskid; |
123 | 126 | ||
124 | spinlock_unlock(&tasks_lock); |
127 | spinlock_unlock(&tasks_lock); |
Line 185... | Line 188... | ||
185 | */ |
188 | */ |
186 | atomic_inc(&as->refcount); |
189 | atomic_inc(&as->refcount); |
187 | 190 | ||
188 | spinlock_lock(&tasks_lock); |
191 | spinlock_lock(&tasks_lock); |
189 | ta->taskid = ++task_counter; |
192 | ta->taskid = ++task_counter; |
- | 193 | avltree_node_initialize(&ta->tasks_tree_node); |
|
- | 194 | ta->tasks_tree_node.key = ta->taskid; |
|
190 | btree_insert(&tasks_btree, (btree_key_t) ta->taskid, (void *) ta, NULL); |
195 | avltree_insert(&tasks_tree, &ta->tasks_tree_node); |
191 | spinlock_unlock(&tasks_lock); |
196 | spinlock_unlock(&tasks_lock); |
192 | interrupts_restore(ipl); |
197 | interrupts_restore(ipl); |
193 | 198 | ||
194 | return ta; |
199 | return ta; |
195 | } |
200 | } |
Line 202... | Line 207... | ||
202 | { |
207 | { |
203 | /* |
208 | /* |
204 | * Remove the task from the task B+tree. |
209 | * Remove the task from the task B+tree. |
205 | */ |
210 | */ |
206 | spinlock_lock(&tasks_lock); |
211 | spinlock_lock(&tasks_lock); |
207 | btree_remove(&tasks_btree, t->taskid, NULL); |
212 | avltree_delete(&tasks_tree, &t->tasks_tree_node); |
208 | spinlock_unlock(&tasks_lock); |
213 | spinlock_unlock(&tasks_lock); |
209 | 214 | ||
210 | /* |
215 | /* |
211 | * Perform architecture specific task destruction. |
216 | * Perform architecture specific task destruction. |
212 | */ |
217 | */ |
Line 308... | Line 313... | ||
308 | * |
313 | * |
309 | * @return Task structure address or NULL if there is no such task ID. |
314 | * @return Task structure address or NULL if there is no such task ID. |
310 | */ |
315 | */ |
311 | task_t *task_find_by_id(task_id_t id) |
316 | task_t *task_find_by_id(task_id_t id) |
312 | { |
317 | { |
313 | btree_node_t *leaf; |
318 | avltree_node_t *node; |
314 | 319 | ||
315 | return (task_t *) btree_search(&tasks_btree, (btree_key_t) id, &leaf); |
320 | node = avltree_search(&tasks_tree, (avltree_key_t) id); |
- | 321 | ||
- | 322 | if (node) |
|
- | 323 | return avltree_get_instance(node, task_t, tasks_tree_node); |
|
- | 324 | return NULL; |
|
316 | } |
325 | } |
317 | 326 | ||
318 | /** Get accounting data of given task. |
327 | /** Get accounting data of given task. |
319 | * |
328 | * |
320 | * Note that task lock of 't' must be already held and |
329 | * Note that task lock of 't' must be already held and |
Line 398... | Line 407... | ||
398 | interrupts_restore(ipl); |
407 | interrupts_restore(ipl); |
399 | 408 | ||
400 | return 0; |
409 | return 0; |
401 | } |
410 | } |
402 | 411 | ||
- | 412 | static bool task_print_walker(avltree_node_t *node, void *arg) |
|
- | 413 | { |
|
- | 414 | task_t *t = avltree_get_instance(node, task_t, tasks_tree_node); |
|
- | 415 | int j; |
|
- | 416 | ||
- | 417 | spinlock_lock(&t->lock); |
|
- | 418 | ||
- | 419 | uint64_t cycles; |
|
- | 420 | char suffix; |
|
- | 421 | order(task_get_accounting(t), &cycles, &suffix); |
|
- | 422 | ||
- | 423 | printf("%-6llu %-10s %-3ld %#10zx %#10zx %9llu%c %7zd %6zd", |
|
- | 424 | t->taskid, t->name, t->context, t, t->as, cycles, suffix, |
|
- | 425 | t->refcount, atomic_get(&t->active_calls)); |
|
- | 426 | for (j = 0; j < IPC_MAX_PHONES; j++) { |
|
- | 427 | if (t->phones[j].callee) |
|
- | 428 | printf(" %zd:%#zx", j, t->phones[j].callee); |
|
- | 429 | } |
|
- | 430 | printf("\n"); |
|
- | 431 | ||
- | 432 | spinlock_unlock(&t->lock); |
|
- | 433 | return true; |
|
- | 434 | } |
|
- | 435 | ||
403 | /** Print task list */ |
436 | /** Print task list */ |
404 | void task_print_list(void) |
437 | void task_print_list(void) |
405 | { |
438 | { |
406 | link_t *cur; |
- | |
407 | ipl_t ipl; |
439 | ipl_t ipl; |
408 | 440 | ||
409 | /* Messing with task structures, avoid deadlock */ |
441 | /* Messing with task structures, avoid deadlock */ |
410 | ipl = interrupts_disable(); |
442 | ipl = interrupts_disable(); |
411 | spinlock_lock(&tasks_lock); |
443 | spinlock_lock(&tasks_lock); |
Line 413... | Line 445... | ||
413 | printf("taskid name ctx address as cycles threads " |
445 | printf("taskid name ctx address as cycles threads " |
414 | "calls callee\n"); |
446 | "calls callee\n"); |
415 | printf("------ ---------- --- ---------- ---------- ---------- ------- " |
447 | printf("------ ---------- --- ---------- ---------- ---------- ------- " |
416 | "------ ------>\n"); |
448 | "------ ------>\n"); |
417 | 449 | ||
418 | for (cur = tasks_btree.leaf_head.next; cur != &tasks_btree.leaf_head; |
- | |
419 | cur = cur->next) { |
- | |
420 | btree_node_t *node; |
- | |
421 | unsigned int i; |
- | |
422 | - | ||
423 | node = list_get_instance(cur, btree_node_t, leaf_link); |
- | |
424 | for (i = 0; i < node->keys; i++) { |
- | |
425 | task_t *t; |
- | |
426 | int j; |
- | |
427 | - | ||
428 | t = (task_t *) node->value[i]; |
- | |
429 | - | ||
430 | spinlock_lock(&t->lock); |
- | |
431 | - | ||
432 | uint64_t cycles; |
- | |
433 | char suffix; |
- | |
434 | order(task_get_accounting(t), &cycles, &suffix); |
450 | avltree_walk(&tasks_tree, task_print_walker, NULL); |
435 | - | ||
436 | printf("%-6llu %-10s %-3ld %#10zx %#10zx %9llu%c %7zd " |
- | |
437 | "%6zd", t->taskid, t->name, t->context, t, t->as, |
- | |
438 | cycles, suffix, t->refcount, |
- | |
439 | atomic_get(&t->active_calls)); |
- | |
440 | for (j = 0; j < IPC_MAX_PHONES; j++) { |
- | |
441 | if (t->phones[j].callee) |
- | |
442 | printf(" %zd:%#zx", j, |
- | |
443 | t->phones[j].callee); |
- | |
444 | } |
- | |
445 | printf("\n"); |
- | |
446 | - | ||
447 | spinlock_unlock(&t->lock); |
- | |
448 | } |
- | |
449 | } |
- | |
450 | 451 | ||
451 | spinlock_unlock(&tasks_lock); |
452 | spinlock_unlock(&tasks_lock); |
452 | interrupts_restore(ipl); |
453 | interrupts_restore(ipl); |
453 | } |
454 | } |
454 | 455 |