diff options
author | Bjoern B. Brandenburg <bbb@cs.unc.edu> | 2008-05-02 22:53:02 -0400 |
---|---|---|
committer | Bjoern B. Brandenburg <bbb@cs.unc.edu> | 2008-05-02 22:53:02 -0400 |
commit | ae9203a19764fd434ded1e4b16ce897566aba63c (patch) | |
tree | 66802ec3ecfd985bcee370b33a42a529b6b692fb | |
parent | d8be518053ec5b66250836f6989d1dffca5b021c (diff) |
LITMUS: add framework for carrying out jobs after dropping rq locks
Many things can't be done from within the scheduler.
This framework should make it easer to defer them.
-rw-r--r-- | include/litmus/norqlock.h | 26 | ||||
-rw-r--r-- | kernel/sched.c | 6 | ||||
-rw-r--r-- | litmus/Makefile | 2 | ||||
-rw-r--r-- | litmus/norqlock.c | 56 |
4 files changed, 88 insertions, 2 deletions
diff --git a/include/litmus/norqlock.h b/include/litmus/norqlock.h new file mode 100644 index 0000000000..e4c1d06f51 --- /dev/null +++ b/include/litmus/norqlock.h | |||
@@ -0,0 +1,26 @@ | |||
1 | #ifndef NORQLOCK_H | ||
2 | #define NORQLOCK_H | ||
3 | |||
4 | typedef void (*work_t)(unsigned long arg); | ||
5 | |||
6 | struct no_rqlock_work { | ||
7 | int active; | ||
8 | work_t work; | ||
9 | unsigned long arg; | ||
10 | struct no_rqlock_work* next; | ||
11 | }; | ||
12 | |||
13 | void init_no_rqlock_work(struct no_rqlock_work* w, work_t work, | ||
14 | unsigned long arg); | ||
15 | |||
16 | void __do_without_rqlock(struct no_rqlock_work *work); | ||
17 | |||
18 | static inline void do_without_rqlock(struct no_rqlock_work *work) | ||
19 | { | ||
20 | if (!test_and_set_bit(0, (void*)&work->active)) | ||
21 | __do_without_rqlock(work); | ||
22 | } | ||
23 | |||
24 | void tick_no_rqlock(void); | ||
25 | |||
26 | #endif | ||
diff --git a/kernel/sched.c b/kernel/sched.c index c52f1b3000..441996e08c 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -67,6 +67,8 @@ | |||
67 | #include <asm/tlb.h> | 67 | #include <asm/tlb.h> |
68 | #include <asm/irq_regs.h> | 68 | #include <asm/irq_regs.h> |
69 | 69 | ||
70 | #include <litmus/norqlock.h> | ||
71 | |||
70 | /* | 72 | /* |
71 | * Scheduler clock - returns current time in nanosec units. | 73 | * Scheduler clock - returns current time in nanosec units. |
72 | * This is default implementation. | 74 | * This is default implementation. |
@@ -1654,7 +1656,7 @@ out_running: | |||
1654 | p->state = TASK_RUNNING; | 1656 | p->state = TASK_RUNNING; |
1655 | out: | 1657 | out: |
1656 | task_rq_unlock(rq, &flags); | 1658 | task_rq_unlock(rq, &flags); |
1657 | 1659 | tick_no_rqlock(); | |
1658 | return success; | 1660 | return success; |
1659 | } | 1661 | } |
1660 | 1662 | ||
@@ -3681,6 +3683,8 @@ need_resched_nonpreemptible: | |||
3681 | } else | 3683 | } else |
3682 | spin_unlock_irq(&rq->lock); | 3684 | spin_unlock_irq(&rq->lock); |
3683 | 3685 | ||
3686 | tick_no_rqlock(); | ||
3687 | |||
3684 | if (unlikely(reacquire_kernel_lock(current) < 0)) { | 3688 | if (unlikely(reacquire_kernel_lock(current) < 0)) { |
3685 | cpu = smp_processor_id(); | 3689 | cpu = smp_processor_id(); |
3686 | rq = cpu_rq(cpu); | 3690 | rq = cpu_rq(cpu); |
diff --git a/litmus/Makefile b/litmus/Makefile index ec088a071b..0e3bedd165 100644 --- a/litmus/Makefile +++ b/litmus/Makefile | |||
@@ -6,6 +6,6 @@ obj-y = sched_plugin.o litmus.o sched_trace.o \ | |||
6 | edf_common.o jobs.o\ | 6 | edf_common.o jobs.o\ |
7 | sched_gsn_edf.o sched_psn_edf.o \ | 7 | sched_gsn_edf.o sched_psn_edf.o \ |
8 | rt_domain.o fdso.o sync.o \ | 8 | rt_domain.o fdso.o sync.o \ |
9 | fmlp.o srp.o | 9 | fmlp.o srp.o norqlock.o |
10 | 10 | ||
11 | obj-$(CONFIG_FEATHER_TRACE) += trace.o ft_event.o | 11 | obj-$(CONFIG_FEATHER_TRACE) += trace.o ft_event.o |
diff --git a/litmus/norqlock.c b/litmus/norqlock.c new file mode 100644 index 0000000000..d0cbe1388e --- /dev/null +++ b/litmus/norqlock.c | |||
@@ -0,0 +1,56 @@ | |||
1 | #include <linux/list.h> | ||
2 | #include <linux/bitops.h> | ||
3 | #include <linux/percpu.h> | ||
4 | #include <linux/module.h> | ||
5 | #include <linux/smp.h> | ||
6 | |||
7 | #include <litmus/norqlock.h> | ||
8 | |||
9 | struct worklist { | ||
10 | struct no_rqlock_work* next; | ||
11 | }; | ||
12 | |||
13 | static DEFINE_PER_CPU(struct worklist, norq_worklist) = {NULL}; | ||
14 | |||
15 | void init_no_rqlock_work(struct no_rqlock_work* w, work_t work, | ||
16 | unsigned long arg) | ||
17 | { | ||
18 | w->active = 0; | ||
19 | w->work = work; | ||
20 | w->arg = arg; | ||
21 | w->next = NULL; | ||
22 | } | ||
23 | |||
24 | void __do_without_rqlock(struct no_rqlock_work *work) | ||
25 | { | ||
26 | long flags; | ||
27 | struct worklist* wl; | ||
28 | |||
29 | local_irq_save(flags); | ||
30 | wl = &__get_cpu_var(norq_worklist); | ||
31 | work->next = wl->next; | ||
32 | wl->next = work; | ||
33 | local_irq_restore(flags); | ||
34 | } | ||
35 | |||
36 | void tick_no_rqlock(void) | ||
37 | { | ||
38 | long flags; | ||
39 | struct no_rqlock_work *todo, *next; | ||
40 | |||
41 | local_irq_save(flags); | ||
42 | |||
43 | next = __get_cpu_var(norq_worklist).next; | ||
44 | __get_cpu_var(norq_worklist).next = NULL; | ||
45 | |||
46 | while (next) { | ||
47 | todo = next; | ||
48 | next = next->next; | ||
49 | todo->next = NULL; | ||
50 | mb(); | ||
51 | todo->active = 0; | ||
52 | todo->work(todo->arg); | ||
53 | } | ||
54 | |||
55 | local_irq_restore(flags); | ||
56 | } | ||