aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/litmus/litmus.h1
-rw-r--r--include/litmus/rt_param.h3
-rw-r--r--kernel/sched.c2
-rw-r--r--litmus/litmus.c15
-rw-r--r--litmus/litmus_sem.c90
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
203void 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}
3692EXPORT_SYMBOL(schedule); 3694EXPORT_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
318DEFINE_PER_CPU(struct srp, srp); 318DEFINE_PER_CPU(struct srp, srp);
319 319
320
321/* Initialize SRP semaphores at boot time. */
322static 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}
335module_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. */
419static 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
435void do_srp_down(struct srp_semaphore* sem) 439void 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
443void do_srp_up(struct srp_semaphore* sem) 448void 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. 532static void do_ceiling_block(struct task_struct *tsk)
527 */
528void 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 */
552void 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();