diff options
-rw-r--r-- | include/litmus/litmus.h | 1 | ||||
-rw-r--r-- | include/litmus/rt_param.h | 3 | ||||
-rw-r--r-- | kernel/sched.c | 2 | ||||
-rw-r--r-- | litmus/litmus.c | 15 | ||||
-rw-r--r-- | litmus/litmus_sem.c | 90 |
5 files changed, 65 insertions, 46 deletions
diff --git a/include/litmus/litmus.h b/include/litmus/litmus.h index 512efef341..8fc9f630c8 100644 --- a/include/litmus/litmus.h +++ b/include/litmus/litmus.h | |||
@@ -200,5 +200,6 @@ static inline lt_t litmus_clock(void) | |||
200 | #define make_np(t) do {t->rt_param.kernel_np++;} while(0); | 200 | #define make_np(t) do {t->rt_param.kernel_np++;} while(0); |
201 | #define take_np(t) do {t->rt_param.kernel_np--;} while(0); | 201 | #define take_np(t) do {t->rt_param.kernel_np--;} while(0); |
202 | 202 | ||
203 | void srp_ceiling_block(void); | ||
203 | 204 | ||
204 | #endif | 205 | #endif |
diff --git a/include/litmus/rt_param.h b/include/litmus/rt_param.h index 118e8590fd..933c1961cb 100644 --- a/include/litmus/rt_param.h +++ b/include/litmus/rt_param.h | |||
@@ -73,6 +73,9 @@ struct rt_param { | |||
73 | /* is the task sleeping? */ | 73 | /* is the task sleeping? */ |
74 | unsigned int flags:8; | 74 | unsigned int flags:8; |
75 | 75 | ||
76 | /* do we need to check for srp blocking? */ | ||
77 | unsigned int srp_non_recurse:1; | ||
78 | |||
76 | /* user controlled parameters */ | 79 | /* user controlled parameters */ |
77 | struct rt_task task_params; | 80 | struct rt_task task_params; |
78 | 81 | ||
diff --git a/kernel/sched.c b/kernel/sched.c index 5d31bc9d56..00097dea89 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -3688,6 +3688,8 @@ need_resched_nonpreemptible: | |||
3688 | preempt_enable_no_resched(); | 3688 | preempt_enable_no_resched(); |
3689 | if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) | 3689 | if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) |
3690 | goto need_resched; | 3690 | goto need_resched; |
3691 | if (srp_active()) | ||
3692 | srp_ceiling_block(); | ||
3691 | } | 3693 | } |
3692 | EXPORT_SYMBOL(schedule); | 3694 | EXPORT_SYMBOL(schedule); |
3693 | 3695 | ||
diff --git a/litmus/litmus.c b/litmus/litmus.c index 2909d5c04e..60aed9dd30 100644 --- a/litmus/litmus.c +++ b/litmus/litmus.c | |||
@@ -153,8 +153,6 @@ asmlinkage long sys_complete_job(void) | |||
153 | * appropriate queue and call schedule | 153 | * appropriate queue and call schedule |
154 | */ | 154 | */ |
155 | retval = litmus->complete_job(); | 155 | retval = litmus->complete_job(); |
156 | if (!retval) | ||
157 | srp_ceiling_block(); | ||
158 | out: | 156 | out: |
159 | return retval; | 157 | return retval; |
160 | } | 158 | } |
@@ -200,15 +198,10 @@ asmlinkage long sys_wait_for_job_release(unsigned int job) | |||
200 | * FIXME: At least problem 2 should be taken care of eventually. | 198 | * FIXME: At least problem 2 should be taken care of eventually. |
201 | */ | 199 | */ |
202 | while (!retval && job > current->rt_param.job_params.job_no) | 200 | while (!retval && job > current->rt_param.job_params.job_no) |
203 | /* If the last job overran then job <= job_no and we | 201 | /* If the last job overran then job <= job_no and we |
204 | * don't send the task to sleep. | 202 | * don't send the task to sleep. |
205 | */ | 203 | */ |
206 | retval = litmus->complete_job(); | 204 | retval = litmus->complete_job(); |
207 | |||
208 | /* We still have to honor the SRP after the actual release. | ||
209 | */ | ||
210 | if (!retval) | ||
211 | srp_ceiling_block(); | ||
212 | out: | 205 | out: |
213 | return retval; | 206 | return retval; |
214 | } | 207 | } |
diff --git a/litmus/litmus_sem.c b/litmus/litmus_sem.c index 60e82a2494..5d51d337d9 100644 --- a/litmus/litmus_sem.c +++ b/litmus/litmus_sem.c | |||
@@ -317,6 +317,24 @@ atomic_t srp_objects_in_use = ATOMIC_INIT(0); | |||
317 | 317 | ||
318 | DEFINE_PER_CPU(struct srp, srp); | 318 | DEFINE_PER_CPU(struct srp, srp); |
319 | 319 | ||
320 | |||
321 | /* Initialize SRP semaphores at boot time. */ | ||
322 | static int __init srp_init(void) | ||
323 | { | ||
324 | int i; | ||
325 | |||
326 | printk("Initializing SRP per-CPU ceilings..."); | ||
327 | for (i = 0; i < NR_CPUS; i++) { | ||
328 | init_waitqueue_head(&per_cpu(srp, i).ceiling_blocked); | ||
329 | INIT_LIST_HEAD(&per_cpu(srp, i).ceiling); | ||
330 | } | ||
331 | printk(" done!\n"); | ||
332 | |||
333 | return 0; | ||
334 | } | ||
335 | module_init(srp_init); | ||
336 | |||
337 | |||
320 | #define system_ceiling(srp) list2prio(srp->ceiling.next) | 338 | #define system_ceiling(srp) list2prio(srp->ceiling.next) |
321 | 339 | ||
322 | 340 | ||
@@ -347,7 +365,7 @@ static void srp_add_prio(struct srp* srp, struct srp_priority* prio) | |||
347 | struct list_head *pos; | 365 | struct list_head *pos; |
348 | if (in_list(&prio->list)) { | 366 | if (in_list(&prio->list)) { |
349 | printk(KERN_CRIT "WARNING: SRP violation detected, prio is already in " | 367 | printk(KERN_CRIT "WARNING: SRP violation detected, prio is already in " |
350 | "ceiling list!\n"); | 368 | "ceiling list! cpu=%d, srp=%p\n", smp_processor_id(), ceiling2sem(prio)); |
351 | return; | 369 | return; |
352 | } | 370 | } |
353 | list_for_each(pos, &srp->ceiling) | 371 | list_for_each(pos, &srp->ceiling) |
@@ -384,6 +402,8 @@ static noinline int open_srp_semaphore(struct od_table_entry* entry, void* __use | |||
384 | struct srp_priority t_prio; | 402 | struct srp_priority t_prio; |
385 | 403 | ||
386 | TRACE("opening SRP semaphore %p, cpu=%d\n", sem, sem->cpu); | 404 | TRACE("opening SRP semaphore %p, cpu=%d\n", sem, sem->cpu); |
405 | if (!srp_active()) | ||
406 | return -EBUSY; | ||
387 | 407 | ||
388 | if (sem->cpu == UNDEF_SEM) | 408 | if (sem->cpu == UNDEF_SEM) |
389 | sem->cpu = get_partition(t); | 409 | sem->cpu = get_partition(t); |
@@ -415,22 +435,6 @@ struct fdso_ops srp_sem_ops = { | |||
415 | .destroy = destroy_srp_semaphore | 435 | .destroy = destroy_srp_semaphore |
416 | }; | 436 | }; |
417 | 437 | ||
418 | /* Initialize SRP semaphores at boot time. */ | ||
419 | static int __init srp_sema_boot_init(void) | ||
420 | { | ||
421 | int i; | ||
422 | |||
423 | printk("Initializing SRP per-CPU ceilings..."); | ||
424 | for (i = 0; i < NR_CPUS; i++) { | ||
425 | init_waitqueue_head(&per_cpu(srp, i).ceiling_blocked); | ||
426 | INIT_LIST_HEAD(&per_cpu(srp, i).ceiling); | ||
427 | } | ||
428 | printk(" done!\n"); | ||
429 | |||
430 | return 0; | ||
431 | } | ||
432 | __initcall(srp_sema_boot_init); | ||
433 | |||
434 | 438 | ||
435 | void do_srp_down(struct srp_semaphore* sem) | 439 | void do_srp_down(struct srp_semaphore* sem) |
436 | { | 440 | { |
@@ -438,18 +442,20 @@ void do_srp_down(struct srp_semaphore* sem) | |||
438 | srp_add_prio(&__get_cpu_var(srp), &sem->ceiling); | 442 | srp_add_prio(&__get_cpu_var(srp), &sem->ceiling); |
439 | WARN_ON(sem->owner != NULL); | 443 | WARN_ON(sem->owner != NULL); |
440 | sem->owner = current; | 444 | sem->owner = current; |
445 | TRACE_CUR("acquired srp 0x%p\n", sem); | ||
441 | } | 446 | } |
442 | 447 | ||
443 | void do_srp_up(struct srp_semaphore* sem) | 448 | void do_srp_up(struct srp_semaphore* sem) |
444 | { | 449 | { |
445 | /* Determine new system priority ceiling for this CPU. */ | 450 | /* Determine new system priority ceiling for this CPU. */ |
446 | WARN_ON(!in_list(&sem->ceiling.list)); | 451 | WARN_ON(!in_list(&sem->ceiling.list)); |
447 | if (!in_list(&sem->ceiling.list)) | 452 | if (in_list(&sem->ceiling.list)) |
448 | list_del(&sem->ceiling.list); | 453 | list_del(&sem->ceiling.list); |
449 | 454 | ||
450 | sem->owner = NULL; | 455 | sem->owner = NULL; |
451 | 456 | ||
452 | /* Wake tasks on this CPU, if they exceed current ceiling. */ | 457 | /* Wake tasks on this CPU, if they exceed current ceiling. */ |
458 | TRACE_CUR("released srp 0x%p\n", sem); | ||
453 | wake_up_all(&__get_cpu_var(srp).ceiling_blocked); | 459 | wake_up_all(&__get_cpu_var(srp).ceiling_blocked); |
454 | } | 460 | } |
455 | 461 | ||
@@ -522,36 +528,50 @@ static int srp_wake_up(wait_queue_t *wait, unsigned mode, int sync, | |||
522 | } | 528 | } |
523 | 529 | ||
524 | 530 | ||
525 | /* Wait for current task priority to exceed system-wide priority ceiling. | 531 | |
526 | * Can be used to determine when it is safe to run a job after its release. | 532 | static void do_ceiling_block(struct task_struct *tsk) |
527 | */ | ||
528 | void srp_ceiling_block(void) | ||
529 | { | 533 | { |
530 | struct task_struct *tsk = current; | ||
531 | wait_queue_t wait = { | 534 | wait_queue_t wait = { |
532 | .private = tsk, | 535 | .private = tsk, |
533 | .func = srp_wake_up, | 536 | .func = srp_wake_up, |
534 | .task_list = {NULL, NULL} | 537 | .task_list = {NULL, NULL} |
535 | }; | 538 | }; |
536 | 539 | ||
537 | /* bail out early if there aren't any SRP resources around */ | 540 | tsk->state = TASK_UNINTERRUPTIBLE; |
538 | if (!atomic_read(&srp_objects_in_use)) | 541 | add_wait_queue(&__get_cpu_var(srp).ceiling_blocked, &wait); |
542 | tsk->rt_param.srp_non_recurse = 1; | ||
543 | preempt_enable_no_resched(); | ||
544 | schedule(); | ||
545 | preempt_disable(); | ||
546 | tsk->rt_param.srp_non_recurse = 0; | ||
547 | remove_wait_queue(&__get_cpu_var(srp).ceiling_blocked, &wait); | ||
548 | } | ||
549 | |||
550 | /* Wait for current task priority to exceed system-wide priority ceiling. | ||
551 | */ | ||
552 | void srp_ceiling_block(void) | ||
553 | { | ||
554 | struct task_struct *tsk = current; | ||
555 | |||
556 | /* Only applies to real-time tasks, but optimize for RT tasks. */ | ||
557 | if (unlikely(!is_realtime(tsk))) | ||
558 | return; | ||
559 | |||
560 | /* Avoid recursive ceiling blocking. */ | ||
561 | if (unlikely(tsk->rt_param.srp_non_recurse)) | ||
562 | return; | ||
563 | |||
564 | /* Bail out early if there aren't any SRP resources around. */ | ||
565 | if (likely(!atomic_read(&srp_objects_in_use))) | ||
539 | return; | 566 | return; |
540 | 567 | ||
541 | preempt_disable(); | 568 | preempt_disable(); |
569 | tsk->rt_param.srp_block = 0; | ||
542 | if (!srp_exceeds_ceiling(tsk, &__get_cpu_var(srp))) { | 570 | if (!srp_exceeds_ceiling(tsk, &__get_cpu_var(srp))) { |
543 | tsk->state = TASK_UNINTERRUPTIBLE; | ||
544 | add_wait_queue(&__get_cpu_var(srp).ceiling_blocked, &wait); | ||
545 | TRACE_CUR("is priority ceiling blocked.\n"); | 571 | TRACE_CUR("is priority ceiling blocked.\n"); |
546 | preempt_enable_no_resched(); | 572 | while (!srp_exceeds_ceiling(tsk, &__get_cpu_var(srp))) |
547 | schedule(); | 573 | do_ceiling_block(tsk); |
548 | /* Access to CPU var must occur with preemptions disabled, | ||
549 | * otherwise Linux debug code complains loudly, even if it is | ||
550 | * ok here. | ||
551 | */ | ||
552 | preempt_disable(); | ||
553 | TRACE_CUR("finally exceeds system ceiling.\n"); | 574 | TRACE_CUR("finally exceeds system ceiling.\n"); |
554 | remove_wait_queue(&__get_cpu_var(srp).ceiling_blocked, &wait); | ||
555 | } else | 575 | } else |
556 | TRACE_CUR("is not priority ceiling blocked\n"); | 576 | TRACE_CUR("is not priority ceiling blocked\n"); |
557 | preempt_enable(); | 577 | preempt_enable(); |