diff options
| author | Glenn Elliott <gelliott@cs.unc.edu> | 2013-04-04 17:31:30 -0400 |
|---|---|---|
| committer | Glenn Elliott <gelliott@cs.unc.edu> | 2013-04-04 17:37:06 -0400 |
| commit | b379666c96805563ca61ddfbb38f0ec9809edf05 (patch) | |
| tree | 6f0b64b1aa70b76e4db0e6786629b985a61dbefe | |
| parent | 3324865fc5792b9d755d46cafa42c74b5037bba5 (diff) | |
Proper sobliv draining and many bug fixes.wip-2012.3-gpu-sobliv-budget-w-kshark
Proper sobliv draining: Always and only drain budget
from a task if its BASE priority is among the top
m processors in the cluster. This required some
work with timers and tracking of consumed budget
while a task is suspended (since the Linux rq won't
track this for us).
Had to introduce a number of hacks and kludges to
make this work in the required timeframe:
1) C-EDF's ready queue lock becomes recursive (yuck!)
2) Extend bheap with a for_each visitor function.
This is needed to set a timer for each newly released
job.
3) Dual-binary heap structure in C-EDF to divide
jobs into top-m and not-top-m tasks.
4) Restructured the budget plugin API. Unfortunatly,
there is not a lot of overlap between SIMPLE and
SOBLIV draining policies.
| -rw-r--r-- | include/litmus/bheap.h | 11 | ||||
| -rw-r--r-- | include/litmus/budget.h | 4 | ||||
| -rw-r--r-- | litmus/bheap.c | 20 | ||||
| -rw-r--r-- | litmus/fifo_lock.c | 13 | ||||
| -rw-r--r-- | litmus/sched_cedf.c | 187 |
5 files changed, 147 insertions, 88 deletions
diff --git a/include/litmus/bheap.h b/include/litmus/bheap.h index 4fded5724b28..72dec0cc0240 100644 --- a/include/litmus/bheap.h +++ b/include/litmus/bheap.h | |||
| @@ -24,8 +24,6 @@ struct bheap { | |||
| 24 | * This speeds up repeated peek operations. | 24 | * This speeds up repeated peek operations. |
| 25 | */ | 25 | */ |
| 26 | struct bheap_node* min; | 26 | struct bheap_node* min; |
| 27 | |||
| 28 | // unsigned int size; | ||
| 29 | }; | 27 | }; |
| 30 | 28 | ||
| 31 | typedef int (*bheap_prio_t)(struct bheap_node* a, struct bheap_node* b); | 29 | typedef int (*bheap_prio_t)(struct bheap_node* a, struct bheap_node* b); |
| @@ -43,14 +41,9 @@ static inline int bheap_empty(struct bheap* heap) | |||
| 43 | return heap->head == NULL && heap->min == NULL; | 41 | return heap->head == NULL && heap->min == NULL; |
| 44 | } | 42 | } |
| 45 | 43 | ||
| 46 | //static inline unsigned int bheap_size(struct bheap* heap) | 44 | typedef void (*bheap_for_each_t)(struct bheap_node* node, void* args); |
| 47 | //{ | ||
| 48 | // return heap->size; | ||
| 49 | //} | ||
| 50 | |||
| 51 | typedef void (*bheap_for_all_t)(struct bheap_node* node, void* args); | ||
| 52 | 45 | ||
| 53 | void bheap_for_all(struct bheap* heap, bheap_for_all_t fn, void* args); | 46 | void bheap_for_each(struct bheap* heap, bheap_for_each_t fn, void* args); |
| 54 | 47 | ||
| 55 | /* insert (and reinitialize) a node into the heap */ | 48 | /* insert (and reinitialize) a node into the heap */ |
| 56 | void bheap_insert(bheap_prio_t higher_prio, | 49 | void bheap_insert(bheap_prio_t higher_prio, |
diff --git a/include/litmus/budget.h b/include/litmus/budget.h index 08d5e0970d1d..bcdbf3d82f7b 100644 --- a/include/litmus/budget.h +++ b/include/litmus/budget.h | |||
| @@ -80,12 +80,8 @@ void simple_on_exit(struct task_struct* t); | |||
| 80 | * | 80 | * |
| 81 | * Limitation: Quantum budget tracking is unsupported. | 81 | * Limitation: Quantum budget tracking is unsupported. |
| 82 | */ | 82 | */ |
| 83 | //void sobliv_on_scheduled(struct task_struct* t); | ||
| 84 | void sobliv_on_blocked(struct task_struct* t); | 83 | void sobliv_on_blocked(struct task_struct* t); |
| 85 | void sobliv_on_wakeup(struct task_struct* t); | 84 | void sobliv_on_wakeup(struct task_struct* t); |
| 86 | //void sobliv_on_sleep(struct task_struct* t); | ||
| 87 | //void sobliv_on_preempt(struct task_struct* t); | ||
| 88 | /* Use the DRAIN_SIMPLE implementations */ | ||
| 89 | #define sobliv_on_exit simple_on_exit | 85 | #define sobliv_on_exit simple_on_exit |
| 90 | void sobliv_on_inherit(struct task_struct* t, struct task_struct* prio_inh); | 86 | void sobliv_on_inherit(struct task_struct* t, struct task_struct* prio_inh); |
| 91 | void sobliv_on_disinherit(struct task_struct* t, struct task_struct* prio_inh); | 87 | void sobliv_on_disinherit(struct task_struct* t, struct task_struct* prio_inh); |
diff --git a/litmus/bheap.c b/litmus/bheap.c index 403c09cc9e81..c69d75c28aaf 100644 --- a/litmus/bheap.c +++ b/litmus/bheap.c | |||
| @@ -5,8 +5,6 @@ void bheap_init(struct bheap* heap) | |||
| 5 | { | 5 | { |
| 6 | heap->head = NULL; | 6 | heap->head = NULL; |
| 7 | heap->min = NULL; | 7 | heap->min = NULL; |
| 8 | |||
| 9 | // heap->size = 0; | ||
| 10 | } | 8 | } |
| 11 | 9 | ||
| 12 | void bheap_node_init(struct bheap_node** _h, void* value) | 10 | void bheap_node_init(struct bheap_node** _h, void* value) |
| @@ -21,19 +19,19 @@ void bheap_node_init(struct bheap_node** _h, void* value) | |||
| 21 | } | 19 | } |
| 22 | 20 | ||
| 23 | 21 | ||
| 24 | static void __bheap_for_all(struct bheap_node *h, bheap_for_all_t fn, void* args) | 22 | static void __bheap_for_each(struct bheap_node *h, bheap_for_each_t fn, void* args) |
| 25 | { | 23 | { |
| 26 | /* pre-order */ | 24 | /* pre-order */ |
| 27 | fn(h, args); | 25 | fn(h, args); |
| 28 | 26 | ||
| 29 | /* depth-first */ | 27 | /* depth-first */ |
| 30 | if (h->child) | 28 | if (h->child) |
| 31 | __bheap_for_all(h->child, fn, args); | 29 | __bheap_for_each(h->child, fn, args); |
| 32 | if (h->next) | 30 | if (h->next) |
| 33 | __bheap_for_all(h->next, fn, args); | 31 | __bheap_for_each(h->next, fn, args); |
| 34 | } | 32 | } |
| 35 | 33 | ||
| 36 | void bheap_for_all(struct bheap* heap, bheap_for_all_t fn, void* args) | 34 | void bheap_for_each(struct bheap* heap, bheap_for_each_t fn, void* args) |
| 37 | { | 35 | { |
| 38 | struct bheap_node *head; | 36 | struct bheap_node *head; |
| 39 | 37 | ||
| @@ -41,7 +39,7 @@ void bheap_for_all(struct bheap* heap, bheap_for_all_t fn, void* args) | |||
| 41 | BUG_ON(!fn); | 39 | BUG_ON(!fn); |
| 42 | 40 | ||
| 43 | head = heap->head; | 41 | head = heap->head; |
| 44 | __bheap_for_all(head, fn, args); | 42 | __bheap_for_each(head, fn, args); |
| 45 | } | 43 | } |
| 46 | 44 | ||
| 47 | /* make child a subtree of root */ | 45 | /* make child a subtree of root */ |
| @@ -198,8 +196,6 @@ void bheap_insert(bheap_prio_t higher_prio, struct bheap* heap, | |||
| 198 | heap->min = node; | 196 | heap->min = node; |
| 199 | } else | 197 | } else |
| 200 | __bheap_union(higher_prio, heap, node); | 198 | __bheap_union(higher_prio, heap, node); |
| 201 | |||
| 202 | // ++heap->size; | ||
| 203 | } | 199 | } |
| 204 | 200 | ||
| 205 | void bheap_uncache_min(bheap_prio_t higher_prio, struct bheap* heap) | 201 | void bheap_uncache_min(bheap_prio_t higher_prio, struct bheap* heap) |
| @@ -222,8 +218,6 @@ void bheap_union(bheap_prio_t higher_prio, | |||
| 222 | __bheap_union(higher_prio, target, addition->head); | 218 | __bheap_union(higher_prio, target, addition->head); |
| 223 | /* this is a destructive merge */ | 219 | /* this is a destructive merge */ |
| 224 | addition->head = NULL; | 220 | addition->head = NULL; |
| 225 | |||
| 226 | // target->size += addition->size; | ||
| 227 | } | 221 | } |
| 228 | 222 | ||
| 229 | struct bheap_node* bheap_peek(bheap_prio_t higher_prio, | 223 | struct bheap_node* bheap_peek(bheap_prio_t higher_prio, |
| @@ -245,8 +239,6 @@ struct bheap_node* bheap_take(bheap_prio_t higher_prio, | |||
| 245 | if (node) | 239 | if (node) |
| 246 | node->degree = NOT_IN_HEAP; | 240 | node->degree = NOT_IN_HEAP; |
| 247 | 241 | ||
| 248 | // --heap->size; | ||
| 249 | |||
| 250 | return node; | 242 | return node; |
| 251 | } | 243 | } |
| 252 | 244 | ||
| @@ -320,8 +312,6 @@ void bheap_delete(bheap_prio_t higher_prio, struct bheap* heap, | |||
| 320 | heap->min = NULL; | 312 | heap->min = NULL; |
| 321 | 313 | ||
| 322 | node->degree = NOT_IN_HEAP; | 314 | node->degree = NOT_IN_HEAP; |
| 323 | |||
| 324 | // --heap->size; | ||
| 325 | } | 315 | } |
| 326 | 316 | ||
| 327 | /* allocate a heap node for value and insert into the heap */ | 317 | /* allocate a heap node for value and insert into the heap */ |
diff --git a/litmus/fifo_lock.c b/litmus/fifo_lock.c index ed637044c948..e3a4420851b2 100644 --- a/litmus/fifo_lock.c +++ b/litmus/fifo_lock.c | |||
| @@ -735,20 +735,11 @@ void fifo_mutex_budget_exhausted(struct litmus_lock* l, struct task_struct* t) | |||
| 735 | struct fifo_mutex *mutex = fifo_mutex_from_lock(l); | 735 | struct fifo_mutex *mutex = fifo_mutex_from_lock(l); |
| 736 | unsigned long flags = 0; | 736 | unsigned long flags = 0; |
| 737 | 737 | ||
| 738 | #ifdef CONFIG_LITMUS_DGL_SUPPORT | 738 | /* DGL lock must already be held on this code path */ |
| 739 | unsigned long dglirqflags; | ||
| 740 | raw_spinlock_t *dgl_lock = litmus->get_dgl_spinlock(t); | ||
| 741 | lock_global_irqsave(dgl_lock, dglirqflags); | ||
| 742 | #endif | ||
| 743 | |||
| 744 | lock_fine_irqsave(&mutex->lock, flags); | 739 | lock_fine_irqsave(&mutex->lock, flags); |
| 745 | 740 | ||
| 746 | // unlocks mutex->lock | 741 | /* unlocks mutex->lock */ |
| 747 | __fifo_mutex_propagate_decrease_inheritance(&mutex->litmus_lock, t, flags, 1); | 742 | __fifo_mutex_propagate_decrease_inheritance(&mutex->litmus_lock, t, flags, 1); |
| 748 | |||
| 749 | #ifdef CONFIG_LITMUS_DGL_SUPPORT | ||
| 750 | unlock_global_irqrestore(dgl_lock, dglirqflags); | ||
| 751 | #endif | ||
| 752 | } | 743 | } |
| 753 | 744 | ||
| 754 | 745 | ||
diff --git a/litmus/sched_cedf.c b/litmus/sched_cedf.c index fc174c464a17..f6fa8a339d48 100644 --- a/litmus/sched_cedf.c +++ b/litmus/sched_cedf.c | |||
| @@ -87,6 +87,11 @@ | |||
| 87 | #include <litmus/gpu_affinity.h> | 87 | #include <litmus/gpu_affinity.h> |
| 88 | #endif | 88 | #endif |
| 89 | 89 | ||
| 90 | |||
| 91 | /* TODO: Move this to litmus/Kconfig */ | ||
| 92 | #define RECURSIVE_READY_QUEUE_LOCK | ||
| 93 | |||
| 94 | |||
| 90 | /* Reference configuration variable. Determines which cache level is used to | 95 | /* Reference configuration variable. Determines which cache level is used to |
| 91 | * group CPUs into clusters. GLOBAL_CLUSTER, which is the default, means that | 96 | * group CPUs into clusters. GLOBAL_CLUSTER, which is the default, means that |
| 92 | * all CPUs form a single cluster (just like GSN-EDF). | 97 | * all CPUs form a single cluster (just like GSN-EDF). |
| @@ -133,8 +138,10 @@ typedef struct clusterdomain { | |||
| 133 | cpumask_var_t cpu_map; | 138 | cpumask_var_t cpu_map; |
| 134 | /* the cpus queue themselves according to priority in here */ | 139 | /* the cpus queue themselves according to priority in here */ |
| 135 | struct binheap cpu_heap; | 140 | struct binheap cpu_heap; |
| 136 | /* lock for this cluster */ | 141 | #ifdef RECURSIVE_READY_QUEUE_LOCK |
| 137 | #define cluster_lock domain.ready_lock | 142 | int recursive_depth; |
| 143 | atomic_t owner_cpu; | ||
| 144 | #endif | ||
| 138 | 145 | ||
| 139 | #ifdef CONFIG_LITMUS_PAI_SOFTIRQD | 146 | #ifdef CONFIG_LITMUS_PAI_SOFTIRQD |
| 140 | struct tasklet_head pending_tasklets; | 147 | struct tasklet_head pending_tasklets; |
| @@ -150,6 +157,82 @@ typedef struct clusterdomain { | |||
| 150 | 157 | ||
| 151 | } cedf_domain_t; | 158 | } cedf_domain_t; |
| 152 | 159 | ||
| 160 | |||
| 161 | #ifdef RECURSIVE_READY_QUEUE_LOCK | ||
| 162 | #define lock_readyq_irqsave(cluster, flags) \ | ||
| 163 | do { \ | ||
| 164 | if (unlikely(irqs_disabled() && atomic_read(&cluster->owner_cpu) == smp_processor_id())) { \ | ||
| 165 | local_irq_save(flags); /* useless. makes compiler happy though */ \ | ||
| 166 | ++cluster->recursive_depth; \ | ||
| 167 | } \ | ||
| 168 | else { \ | ||
| 169 | raw_spin_lock_irqsave(&cluster->domain.ready_lock, flags); \ | ||
| 170 | atomic_set(&cluster->owner_cpu, smp_processor_id()); \ | ||
| 171 | BUG_ON(cluster->recursive_depth != 0); \ | ||
| 172 | } \ | ||
| 173 | }while(0) | ||
| 174 | |||
| 175 | #define lock_readyq(cluster) \ | ||
| 176 | do { \ | ||
| 177 | if (unlikely(irqs_disabled() && atomic_read(&cluster->owner_cpu) == smp_processor_id())) \ | ||
| 178 | ++cluster->recursive_depth; \ | ||
| 179 | else { \ | ||
| 180 | raw_spin_lock(&cluster->domain.ready_lock); \ | ||
| 181 | atomic_set(&cluster->owner_cpu, smp_processor_id()); \ | ||
| 182 | BUG_ON(cluster->recursive_depth != 0); \ | ||
| 183 | } \ | ||
| 184 | }while(0) | ||
| 185 | |||
| 186 | #define unlock_readyq_irqrestore(cluster, flags) \ | ||
| 187 | do { \ | ||
| 188 | BUG_ON(!raw_spin_is_locked(&cluster->domain.ready_lock)); \ | ||
| 189 | BUG_ON(atomic_read(&cluster->owner_cpu) != smp_processor_id()); \ | ||
| 190 | if (unlikely(cluster->recursive_depth > 0)) { \ | ||
| 191 | --cluster->recursive_depth; \ | ||
| 192 | local_irq_restore(flags); /* useless. makes compiler happy though */ \ | ||
| 193 | } \ | ||
| 194 | else { \ | ||
| 195 | atomic_set(&cluster->owner_cpu, NO_CPU); \ | ||
| 196 | raw_spin_unlock_irqrestore(&cluster->domain.ready_lock, flags); \ | ||
| 197 | } \ | ||
| 198 | }while(0) | ||
| 199 | |||
| 200 | #define unlock_readyq(cluster) \ | ||
| 201 | do { \ | ||
| 202 | BUG_ON(!raw_spin_is_locked(&cluster->domain.ready_lock)); \ | ||
| 203 | if (unlikely(cluster->recursive_depth > 0)) { \ | ||
| 204 | BUG_ON(atomic_read(&cluster->owner_cpu) != smp_processor_id()); \ | ||
| 205 | --cluster->recursive_depth; \ | ||
| 206 | } \ | ||
| 207 | else { \ | ||
| 208 | atomic_set(&cluster->owner_cpu, NO_CPU); \ | ||
| 209 | raw_spin_unlock(&cluster->domain.ready_lock); \ | ||
| 210 | } \ | ||
| 211 | }while(0) | ||
| 212 | |||
| 213 | #else | ||
| 214 | #define lock_readyq_irqsave(cluster, flags) \ | ||
| 215 | do {\ | ||
| 216 | raw_spin_lock_irqsave(&cluster->domain.ready_lock, flags); \ | ||
| 217 | }while(0) | ||
| 218 | |||
| 219 | #define lock_readyq(cluster) \ | ||
| 220 | do {\ | ||
| 221 | raw_spin_lock(&cluster->domain.ready_lock); \ | ||
| 222 | }while(0) | ||
| 223 | |||
| 224 | #define unlock_readyq_irqrestore(cluster, flags) \ | ||
| 225 | do {\ | ||
| 226 | raw_spin_unlock_irqrestore(&cluster->domain.ready_lock, flags); \ | ||
| 227 | }while(0) | ||
| 228 | |||
| 229 | #define unlock_readyq(cluster) \ | ||
| 230 | do {\ | ||
| 231 | raw_spin_unlock(&cluster->domain.ready_lock); \ | ||
| 232 | }while(0) | ||
| 233 | #endif | ||
| 234 | |||
| 235 | |||
| 153 | /* a cedf_domain per cluster; allocation is done at init/activation time */ | 236 | /* a cedf_domain per cluster; allocation is done at init/activation time */ |
| 154 | cedf_domain_t *cedf; | 237 | cedf_domain_t *cedf; |
| 155 | 238 | ||
| @@ -292,7 +375,7 @@ static void cedf_untrack_in_top_m(struct task_struct *t) | |||
| 292 | &cluster->top_m, | 375 | &cluster->top_m, |
| 293 | struct budget_tracker, top_m_node); | 376 | struct budget_tracker, top_m_node); |
| 294 | bt_flag_set(to_move, BTF_IS_TOP_M); | 377 | bt_flag_set(to_move, BTF_IS_TOP_M); |
| 295 | budget_state_machine(t,on_enter_top_m); | 378 | budget_state_machine(to_move,on_enter_top_m); |
| 296 | } | 379 | } |
| 297 | else { | 380 | else { |
| 298 | --cluster->top_m_size; | 381 | --cluster->top_m_size; |
| @@ -561,14 +644,14 @@ static void cedf_release_jobs(rt_domain_t* rt, struct bheap* tasks) | |||
| 561 | cedf_domain_t* cluster = container_of(rt, cedf_domain_t, domain); | 644 | cedf_domain_t* cluster = container_of(rt, cedf_domain_t, domain); |
| 562 | unsigned long flags; | 645 | unsigned long flags; |
| 563 | 646 | ||
| 564 | raw_spin_lock_irqsave(&cluster->cluster_lock, flags); | 647 | lock_readyq_irqsave(cluster, flags); |
| 565 | 648 | ||
| 566 | bheap_for_all(tasks, cedf_track_on_release, NULL); | 649 | bheap_for_each(tasks, cedf_track_on_release, NULL); |
| 567 | 650 | ||
| 568 | __merge_ready(&cluster->domain, tasks); | 651 | __merge_ready(&cluster->domain, tasks); |
| 569 | check_for_preemptions(cluster); | 652 | check_for_preemptions(cluster); |
| 570 | 653 | ||
| 571 | raw_spin_unlock_irqrestore(&cluster->cluster_lock, flags); | 654 | unlock_readyq_irqrestore(cluster, flags); |
| 572 | } | 655 | } |
| 573 | 656 | ||
| 574 | /* caller holds cluster_lock */ | 657 | /* caller holds cluster_lock */ |
| @@ -755,7 +838,19 @@ static enum hrtimer_restart cedf_sobliv_on_exhausted(struct task_struct *t) | |||
| 755 | /* force job completion */ | 838 | /* force job completion */ |
| 756 | TRACE_TASK(t, "blocked, postponing deadline\n"); | 839 | TRACE_TASK(t, "blocked, postponing deadline\n"); |
| 757 | 840 | ||
| 758 | raw_spin_lock_irqsave(&cluster->cluster_lock, flags); | 841 | /* Outermost lock of the cluster. Recursive lock calls are |
| 842 | * possible on this code path. This should be the _ONLY_ | ||
| 843 | * scenario where recursive calls are made. */ | ||
| 844 | #ifdef CONFIG_LITMUS_DGL_SUPPORT | ||
| 845 | /* Unfortunately, we _might_ need to grab the DGL lock, so we | ||
| 846 | * must grab it every time since it must be take before the | ||
| 847 | * cluster lock. */ | ||
| 848 | raw_spin_lock_irqsave(&cluster->dgl_lock, flags); | ||
| 849 | lock_readyq(cluster); | ||
| 850 | #else | ||
| 851 | lock_readyq_irqsave(cluster, flags); | ||
| 852 | #endif | ||
| 853 | |||
| 759 | job_completion(t, 1); /* refreshes budget and pushes out deadline */ | 854 | job_completion(t, 1); /* refreshes budget and pushes out deadline */ |
| 760 | 855 | ||
| 761 | #ifdef CONFIG_LITMUS_LOCKING | 856 | #ifdef CONFIG_LITMUS_LOCKING |
| @@ -792,7 +887,7 @@ static enum hrtimer_restart cedf_sobliv_on_exhausted(struct task_struct *t) | |||
| 792 | } | 887 | } |
| 793 | } | 888 | } |
| 794 | #endif | 889 | #endif |
| 795 | raw_spin_unlock_irqrestore(&cluster->cluster_lock, flags); | 890 | // unlock_readyq_irqrestore(cluster, flags); |
| 796 | 891 | ||
| 797 | #ifdef CONFIG_LITMUS_LOCKING | 892 | #ifdef CONFIG_LITMUS_LOCKING |
| 798 | /* Check our inheritance and propagate any changes forward. */ | 893 | /* Check our inheritance and propagate any changes forward. */ |
| @@ -810,9 +905,17 @@ static enum hrtimer_restart cedf_sobliv_on_exhausted(struct task_struct *t) | |||
| 810 | 905 | ||
| 811 | #ifdef CONFIG_LITMUS_LOCKING | 906 | #ifdef CONFIG_LITMUS_LOCKING |
| 812 | /* double-check that everything is okay */ | 907 | /* double-check that everything is okay */ |
| 813 | raw_spin_lock_irqsave(&cluster->cluster_lock, flags); | 908 | // lock_readyq_irqsave(cluster, flags); |
| 814 | check_for_preemptions(cluster); | 909 | check_for_preemptions(cluster); |
| 815 | raw_spin_unlock_irqrestore(&cluster->cluster_lock, flags); | 910 | // unlock_readyq_irqrestore(cluster, flags); |
| 911 | #endif | ||
| 912 | |||
| 913 | /* should be the outermost unlock call */ | ||
| 914 | #ifdef CONFIG_LITMUS_DGL_SUPPORT | ||
| 915 | unlock_readyq(cluster); | ||
| 916 | raw_spin_unlock_irqrestore(&cluster->dgl_lock, flags); | ||
| 917 | #else | ||
| 918 | unlock_readyq_irqrestore(cluster, flags); | ||
| 816 | #endif | 919 | #endif |
| 817 | 920 | ||
| 818 | /* we need to set up the budget timer since we're within the callback. */ | 921 | /* we need to set up the budget timer since we're within the callback. */ |
| @@ -890,7 +993,7 @@ static void do_lit_tasklets(cedf_domain_t* cluster, struct task_struct* sched_ta | |||
| 890 | 993 | ||
| 891 | TS_NV_SCHED_BOTISR_START; | 994 | TS_NV_SCHED_BOTISR_START; |
| 892 | 995 | ||
| 893 | raw_spin_lock_irqsave(&cluster->cluster_lock, flags); | 996 | lock_readyq_irqsave(cluster, flags); |
| 894 | 997 | ||
| 895 | if(cluster->pending_tasklets.head != NULL) { | 998 | if(cluster->pending_tasklets.head != NULL) { |
| 896 | // remove tasklet at head. | 999 | // remove tasklet at head. |
| @@ -932,7 +1035,7 @@ static void do_lit_tasklets(cedf_domain_t* cluster, struct task_struct* sched_ta | |||
| 932 | TRACE("%s: Tasklet queue is empty.\n", __FUNCTION__); | 1035 | TRACE("%s: Tasklet queue is empty.\n", __FUNCTION__); |
| 933 | } | 1036 | } |
| 934 | 1037 | ||
| 935 | raw_spin_unlock_irqrestore(&cluster->cluster_lock, flags); | 1038 | unlock_readyq_irqrestore(cluster, flags); |
| 936 | 1039 | ||
| 937 | if(tasklet) { | 1040 | if(tasklet) { |
| 938 | __do_lit_tasklet(tasklet, 0ul); | 1041 | __do_lit_tasklet(tasklet, 0ul); |
| @@ -1040,7 +1143,7 @@ static int cedf_enqueue_pai_tasklet(struct tasklet_struct* tasklet) | |||
| 1040 | 1143 | ||
| 1041 | cluster = task_cpu_cluster(tasklet->owner); | 1144 | cluster = task_cpu_cluster(tasklet->owner); |
| 1042 | 1145 | ||
| 1043 | raw_spin_lock_irqsave(&cluster->cluster_lock, flags); | 1146 | lock_readyq_irqsave(cluster, flags); |
| 1044 | 1147 | ||
| 1045 | thisCPU = smp_processor_id(); | 1148 | thisCPU = smp_processor_id(); |
| 1046 | 1149 | ||
| @@ -1091,7 +1194,7 @@ static int cedf_enqueue_pai_tasklet(struct tasklet_struct* tasklet) | |||
| 1091 | __add_pai_tasklet(tasklet, cluster); | 1194 | __add_pai_tasklet(tasklet, cluster); |
| 1092 | } | 1195 | } |
| 1093 | 1196 | ||
| 1094 | raw_spin_unlock_irqrestore(&cluster->cluster_lock, flags); | 1197 | unlock_readyq_irqrestore(cluster, flags); |
| 1095 | 1198 | ||
| 1096 | 1199 | ||
| 1097 | if (runLocal /*&& runNow */) { // runNow == 1 is implied | 1200 | if (runLocal /*&& runNow */) { // runNow == 1 is implied |
| @@ -1128,14 +1231,14 @@ static void cedf_change_prio_pai_tasklet(struct task_struct *old_prio, | |||
| 1128 | cluster = task_cpu_cluster(probe); | 1231 | cluster = task_cpu_cluster(probe); |
| 1129 | 1232 | ||
| 1130 | if(cluster->pending_tasklets.head != NULL) { | 1233 | if(cluster->pending_tasklets.head != NULL) { |
| 1131 | raw_spin_lock_irqsave(&cluster->cluster_lock, flags); | 1234 | lock_readyq_irqsave(cluster, flags); |
| 1132 | for(step = cluster->pending_tasklets.head; step != NULL; step = step->next) { | 1235 | for(step = cluster->pending_tasklets.head; step != NULL; step = step->next) { |
| 1133 | if(step->owner == old_prio) { | 1236 | if(step->owner == old_prio) { |
| 1134 | TRACE("%s: Found tasklet to change: %d\n", __FUNCTION__, step->owner->pid); | 1237 | TRACE("%s: Found tasklet to change: %d\n", __FUNCTION__, step->owner->pid); |
| 1135 | step->owner = new_prio; | 1238 | step->owner = new_prio; |
| 1136 | } | 1239 | } |
| 1137 | } | 1240 | } |
| 1138 | raw_spin_unlock_irqrestore(&cluster->cluster_lock, flags); | 1241 | unlock_readyq_irqrestore(cluster, flags); |
| 1139 | } | 1242 | } |
| 1140 | } | 1243 | } |
| 1141 | else { | 1244 | else { |
| @@ -1184,7 +1287,7 @@ static struct task_struct* cedf_schedule(struct task_struct * prev) | |||
| 1184 | } | 1287 | } |
| 1185 | #endif | 1288 | #endif |
| 1186 | 1289 | ||
| 1187 | raw_spin_lock(&cluster->cluster_lock); | 1290 | lock_readyq(cluster); |
| 1188 | clear_will_schedule(); | 1291 | clear_will_schedule(); |
| 1189 | 1292 | ||
| 1190 | /* sanity checking */ | 1293 | /* sanity checking */ |
| @@ -1307,27 +1410,8 @@ static struct task_struct* cedf_schedule(struct task_struct * prev) | |||
| 1307 | out_set_state: | 1410 | out_set_state: |
| 1308 | #endif | 1411 | #endif |
| 1309 | 1412 | ||
| 1310 | //#ifdef CONFIG_LITMUS_LOCKING | ||
| 1311 | // /* Update priority inheritance linkbacks. | ||
| 1312 | // * A blocked task may have multiple tasks that inherit from it, but only | ||
| 1313 | // * one of those tasks should be runnable. Provide a link-back between the | ||
| 1314 | // * blocked task and the one that inherits from it. */ | ||
| 1315 | // | ||
| 1316 | // /* TODO: Support klmirqd and aux tasks */ | ||
| 1317 | // /* TODO: MOVE THESE CALLS TO __increase AND __decrease TO CATCH ALL CASES. | ||
| 1318 | // PAY ATTENTION TO RUN-STATE OF INHERITOR & INHERITEE */ | ||
| 1319 | // if (next != prev) { | ||
| 1320 | // if (prev && tsk_rt(prev)->inh_task) { | ||
| 1321 | // clear_inh_task_linkback(prev, tsk_rt(prev)->inh_task); | ||
| 1322 | // } | ||
| 1323 | // if (next && tsk_rt(next)->inh_task) { | ||
| 1324 | // set_inh_task_linkback(next, tsk_rt(next)->inh_task); | ||
| 1325 | // } | ||
| 1326 | // } | ||
| 1327 | //#endif | ||
| 1328 | |||
| 1329 | sched_state_task_picked(); | 1413 | sched_state_task_picked(); |
| 1330 | raw_spin_unlock(&cluster->cluster_lock); | 1414 | unlock_readyq(cluster); |
| 1331 | 1415 | ||
| 1332 | #ifdef WANT_ALL_SCHED_EVENTS | 1416 | #ifdef WANT_ALL_SCHED_EVENTS |
| 1333 | TRACE("cluster_lock released, next=0x%p\n", next); | 1417 | TRACE("cluster_lock released, next=0x%p\n", next); |
| @@ -1368,7 +1452,7 @@ static void cedf_task_new(struct task_struct * t, int on_rq, int running) | |||
| 1368 | /* the cluster doesn't change even if t is running */ | 1452 | /* the cluster doesn't change even if t is running */ |
| 1369 | cluster = task_cpu_cluster(t); | 1453 | cluster = task_cpu_cluster(t); |
| 1370 | 1454 | ||
| 1371 | raw_spin_lock_irqsave(&cluster->cluster_lock, flags); | 1455 | lock_readyq_irqsave(cluster, flags); |
| 1372 | 1456 | ||
| 1373 | /* setup job params */ | 1457 | /* setup job params */ |
| 1374 | release_at(t, litmus_clock()); | 1458 | release_at(t, litmus_clock()); |
| @@ -1400,7 +1484,7 @@ static void cedf_task_new(struct task_struct * t, int on_rq, int running) | |||
| 1400 | cedf_job_arrival(t); | 1484 | cedf_job_arrival(t); |
| 1401 | } | 1485 | } |
| 1402 | 1486 | ||
| 1403 | raw_spin_unlock_irqrestore(&(cluster->cluster_lock), flags); | 1487 | unlock_readyq_irqrestore(cluster, flags); |
| 1404 | } | 1488 | } |
| 1405 | 1489 | ||
| 1406 | static void cedf_task_wake_up(struct task_struct *t) | 1490 | static void cedf_task_wake_up(struct task_struct *t) |
| @@ -1411,7 +1495,7 @@ static void cedf_task_wake_up(struct task_struct *t) | |||
| 1411 | 1495 | ||
| 1412 | cluster = task_cpu_cluster(t); | 1496 | cluster = task_cpu_cluster(t); |
| 1413 | 1497 | ||
| 1414 | raw_spin_lock_irqsave(&cluster->cluster_lock, flags); | 1498 | lock_readyq_irqsave(cluster, flags); |
| 1415 | 1499 | ||
| 1416 | now = litmus_clock(); | 1500 | now = litmus_clock(); |
| 1417 | TRACE_TASK(t, "wake_up at %llu\n", now); | 1501 | TRACE_TASK(t, "wake_up at %llu\n", now); |
| @@ -1443,7 +1527,7 @@ static void cedf_task_wake_up(struct task_struct *t) | |||
| 1443 | budget_state_machine(t,on_wakeup); | 1527 | budget_state_machine(t,on_wakeup); |
| 1444 | cedf_job_arrival(t); | 1528 | cedf_job_arrival(t); |
| 1445 | 1529 | ||
| 1446 | raw_spin_unlock_irqrestore(&cluster->cluster_lock, flags); | 1530 | unlock_readyq_irqrestore(cluster, flags); |
| 1447 | } | 1531 | } |
| 1448 | 1532 | ||
| 1449 | static void cedf_task_block(struct task_struct *t) | 1533 | static void cedf_task_block(struct task_struct *t) |
| @@ -1456,7 +1540,7 @@ static void cedf_task_block(struct task_struct *t) | |||
| 1456 | cluster = task_cpu_cluster(t); | 1540 | cluster = task_cpu_cluster(t); |
| 1457 | 1541 | ||
| 1458 | /* unlink if necessary */ | 1542 | /* unlink if necessary */ |
| 1459 | raw_spin_lock_irqsave(&cluster->cluster_lock, flags); | 1543 | lock_readyq_irqsave(cluster, flags); |
| 1460 | 1544 | ||
| 1461 | unlink(t); | 1545 | unlink(t); |
| 1462 | 1546 | ||
| @@ -1476,7 +1560,7 @@ static void cedf_task_block(struct task_struct *t) | |||
| 1476 | } | 1560 | } |
| 1477 | #endif | 1561 | #endif |
| 1478 | 1562 | ||
| 1479 | raw_spin_unlock_irqrestore(&cluster->cluster_lock, flags); | 1563 | unlock_readyq_irqrestore(cluster, flags); |
| 1480 | 1564 | ||
| 1481 | BUG_ON(!is_realtime(t)); | 1565 | BUG_ON(!is_realtime(t)); |
| 1482 | } | 1566 | } |
| @@ -1492,7 +1576,7 @@ static void cedf_task_exit(struct task_struct * t) | |||
| 1492 | #endif | 1576 | #endif |
| 1493 | 1577 | ||
| 1494 | /* unlink if necessary */ | 1578 | /* unlink if necessary */ |
| 1495 | raw_spin_lock_irqsave(&cluster->cluster_lock, flags); | 1579 | lock_readyq_irqsave(cluster, flags); |
| 1496 | 1580 | ||
| 1497 | if (tsk_rt(t)->inh_task) { | 1581 | if (tsk_rt(t)->inh_task) { |
| 1498 | WARN_ON(1); | 1582 | WARN_ON(1); |
| @@ -1528,7 +1612,7 @@ static void cedf_task_exit(struct task_struct * t) | |||
| 1528 | cpu->scheduled = NULL; | 1612 | cpu->scheduled = NULL; |
| 1529 | tsk_rt(t)->scheduled_on = NO_CPU; | 1613 | tsk_rt(t)->scheduled_on = NO_CPU; |
| 1530 | } | 1614 | } |
| 1531 | raw_spin_unlock_irqrestore(&cluster->cluster_lock, flags); | 1615 | unlock_readyq_irqrestore(cluster, flags); |
| 1532 | 1616 | ||
| 1533 | BUG_ON(!is_realtime(t)); | 1617 | BUG_ON(!is_realtime(t)); |
| 1534 | TRACE_TASK(t, "RIP\n"); | 1618 | TRACE_TASK(t, "RIP\n"); |
| @@ -1792,13 +1876,13 @@ static void increase_priority_inheritance(struct task_struct* t, struct task_str | |||
| 1792 | { | 1876 | { |
| 1793 | cedf_domain_t* cluster = task_cpu_cluster(t); | 1877 | cedf_domain_t* cluster = task_cpu_cluster(t); |
| 1794 | 1878 | ||
| 1795 | raw_spin_lock(&cluster->cluster_lock); | 1879 | lock_readyq(cluster); |
| 1796 | 1880 | ||
| 1797 | TRACE_TASK(t, "to inherit from %s/%d\n", prio_inh->comm, prio_inh->pid); | 1881 | TRACE_TASK(t, "to inherit from %s/%d\n", prio_inh->comm, prio_inh->pid); |
| 1798 | 1882 | ||
| 1799 | __increase_priority_inheritance(t, prio_inh); | 1883 | __increase_priority_inheritance(t, prio_inh); |
| 1800 | 1884 | ||
| 1801 | raw_spin_unlock(&cluster->cluster_lock); | 1885 | unlock_readyq(cluster); |
| 1802 | 1886 | ||
| 1803 | #if defined(CONFIG_LITMUS_PAI_SOFTIRQD) && defined(CONFIG_LITMUS_NVIDIA) | 1887 | #if defined(CONFIG_LITMUS_PAI_SOFTIRQD) && defined(CONFIG_LITMUS_NVIDIA) |
| 1804 | if(tsk_rt(t)->held_gpus) { | 1888 | if(tsk_rt(t)->held_gpus) { |
| @@ -1962,7 +2046,7 @@ static void decrease_priority_inheritance(struct task_struct* t, | |||
| 1962 | { | 2046 | { |
| 1963 | cedf_domain_t* cluster = task_cpu_cluster(t); | 2047 | cedf_domain_t* cluster = task_cpu_cluster(t); |
| 1964 | 2048 | ||
| 1965 | raw_spin_lock(&cluster->cluster_lock); | 2049 | lock_readyq(cluster); |
| 1966 | 2050 | ||
| 1967 | TRACE_TASK(t, "to inherit from %s/%d (decrease)\n", | 2051 | TRACE_TASK(t, "to inherit from %s/%d (decrease)\n", |
| 1968 | (prio_inh) ? prio_inh->comm : "null", | 2052 | (prio_inh) ? prio_inh->comm : "null", |
| @@ -1970,7 +2054,7 @@ static void decrease_priority_inheritance(struct task_struct* t, | |||
| 1970 | 2054 | ||
| 1971 | __decrease_priority_inheritance(t, prio_inh, budget_tiggered); | 2055 | __decrease_priority_inheritance(t, prio_inh, budget_tiggered); |
| 1972 | 2056 | ||
| 1973 | raw_spin_unlock(&cluster->cluster_lock); | 2057 | unlock_readyq(cluster); |
| 1974 | 2058 | ||
| 1975 | #if defined(CONFIG_LITMUS_PAI_SOFTIRQD) && defined(CONFIG_LITMUS_NVIDIA) | 2059 | #if defined(CONFIG_LITMUS_PAI_SOFTIRQD) && defined(CONFIG_LITMUS_NVIDIA) |
| 1976 | if(tsk_rt(t)->held_gpus) { | 2060 | if(tsk_rt(t)->held_gpus) { |
| @@ -2438,6 +2522,11 @@ static long cedf_activate_plugin(void) | |||
| 2438 | raw_spin_lock_init(&cedf[i].dgl_lock); | 2522 | raw_spin_lock_init(&cedf[i].dgl_lock); |
| 2439 | #endif | 2523 | #endif |
| 2440 | 2524 | ||
| 2525 | #ifdef RECURSIVE_READY_QUEUE_LOCK | ||
| 2526 | cedf[i].recursive_depth = 0; | ||
| 2527 | atomic_set(&cedf[i].owner_cpu, NO_CPU); | ||
| 2528 | #endif | ||
| 2529 | |||
| 2441 | cedf[i].top_m_size = 0; | 2530 | cedf[i].top_m_size = 0; |
| 2442 | INIT_BINHEAP_HANDLE(&cedf[i].top_m, cedf_min_heap_base_priority_order); | 2531 | INIT_BINHEAP_HANDLE(&cedf[i].top_m, cedf_min_heap_base_priority_order); |
| 2443 | INIT_BINHEAP_HANDLE(&cedf[i].not_top_m, cedf_max_heap_base_priority_order); | 2532 | INIT_BINHEAP_HANDLE(&cedf[i].not_top_m, cedf_max_heap_base_priority_order); |
