diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2012-05-03 16:50:32 -0400 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2012-05-03 17:17:52 -0400 |
commit | bb35f3fc684667598d7ae39fd2d49a16f77beb39 (patch) | |
tree | 6a70f13510e36e2771652bb3fc6d60321bf1daf6 | |
parent | e0e02579c34b9920781b3ce3fc9d6d7bcafb4d5b (diff) |
Added color schedule
-rw-r--r-- | include/litmus/budget.h | 20 | ||||
-rw-r--r-- | include/litmus/color.h | 9 | ||||
-rw-r--r-- | include/litmus/dgl.h | 61 | ||||
-rw-r--r-- | include/litmus/fifo_common.h | 25 | ||||
-rw-r--r-- | include/litmus/litmus.h | 19 | ||||
-rw-r--r-- | include/litmus/locking.h | 1 | ||||
-rw-r--r-- | include/litmus/rt_domain.h | 2 | ||||
-rw-r--r-- | include/litmus/rt_param.h | 14 | ||||
-rw-r--r-- | include/litmus/rt_server.h | 39 | ||||
-rw-r--r-- | include/litmus/sched_plugin.h | 7 | ||||
-rw-r--r-- | include/litmus/sched_trace.h | 175 | ||||
-rw-r--r-- | include/trace/events/litmus.h | 425 | ||||
-rw-r--r-- | include/trace/ftrace.h | 5 | ||||
-rw-r--r-- | kernel/sched.c | 6 | ||||
-rw-r--r-- | litmus/Kconfig | 18 | ||||
-rw-r--r-- | litmus/Makefile | 14 | ||||
-rw-r--r-- | litmus/budget.c | 29 | ||||
-rw-r--r-- | litmus/color_proc.c | 143 | ||||
-rw-r--r-- | litmus/dgl.c | 248 | ||||
-rw-r--r-- | litmus/fifo_common.c | 58 | ||||
-rw-r--r-- | litmus/ftdev.c | 2 | ||||
-rw-r--r-- | litmus/locking.c | 8 | ||||
-rw-r--r-- | litmus/rt_server.c | 34 | ||||
-rw-r--r-- | litmus/sched_color.c | 811 | ||||
-rw-r--r-- | litmus/sched_litmus.c | 4 | ||||
-rw-r--r-- | litmus/sched_plugin.c | 6 | ||||
-rw-r--r-- | litmus/sync.c | 3 |
27 files changed, 2127 insertions, 59 deletions
diff --git a/include/litmus/budget.h b/include/litmus/budget.h index 732530e63491..6ef0e44effb1 100644 --- a/include/litmus/budget.h +++ b/include/litmus/budget.h | |||
@@ -1,8 +1,24 @@ | |||
1 | #ifndef _LITMUS_BUDGET_H_ | 1 | #ifndef _LITMUS_BUDGET_H_ |
2 | #define _LITMUS_BUDGET_H_ | 2 | #define _LITMUS_BUDGET_H_ |
3 | 3 | ||
4 | /* Update the per-processor enforcement timer (arm/reproram/cancel) for | 4 | struct enforcement_timer { |
5 | * the next task. */ | 5 | struct hrtimer timer; |
6 | int armed; | ||
7 | }; | ||
8 | |||
9 | /** | ||
10 | * update_enforcement_timer() - Update per-processor enforcement timer for | ||
11 | * the next scheduled task. | ||
12 | * | ||
13 | * If @t is not NULL and has a precisely enforced budget, the timer will be | ||
14 | * armed to trigger a reschedule when the budget is exhausted. Otherwise, | ||
15 | * the timer will be cancelled. | ||
16 | */ | ||
6 | void update_enforcement_timer(struct task_struct* t); | 17 | void update_enforcement_timer(struct task_struct* t); |
7 | 18 | ||
19 | void init_enforcement_timer(struct enforcement_timer *et); | ||
20 | |||
21 | void arm_enforcement_timer(struct enforcement_timer* et, struct task_struct* t); | ||
22 | |||
23 | void cancel_enforcement_timer(struct enforcement_timer* et); | ||
8 | #endif | 24 | #endif |
diff --git a/include/litmus/color.h b/include/litmus/color.h index 998af33cd3ea..250f08a6e1f3 100644 --- a/include/litmus/color.h +++ b/include/litmus/color.h | |||
@@ -1,6 +1,11 @@ | |||
1 | #ifndef LITMUS_COLOR_H | 1 | #ifndef LITMUS_COLOR_H |
2 | #define LITMUS_COLOR_H | 2 | #define LITMUS_COLOR_H |
3 | 3 | ||
4 | #define NUM_COLORS 64 | ||
5 | #define NUM_WAYS 12 | ||
6 | |||
7 | #ifdef __KERNEL__ | ||
8 | |||
4 | #define ONE_COLOR_LEN 11 | 9 | #define ONE_COLOR_LEN 11 |
5 | #define ONE_COLOR_FMT "%4lu: %4d\n" | 10 | #define ONE_COLOR_FMT "%4lu: %4d\n" |
6 | 11 | ||
@@ -16,6 +21,8 @@ void add_page_to_color_list(struct page*); | |||
16 | void add_page_to_alloced_list(struct page*, struct vm_area_struct*); | 21 | void add_page_to_alloced_list(struct page*, struct vm_area_struct*); |
17 | void reclaim_pages(struct vm_area_struct*); | 22 | void reclaim_pages(struct vm_area_struct*); |
18 | 23 | ||
24 | int color_server_params(int cpu, unsigned long *wcet, unsigned long *period); | ||
25 | |||
19 | int color_add_pages_handler(struct ctl_table *, int, void __user *, | 26 | int color_add_pages_handler(struct ctl_table *, int, void __user *, |
20 | size_t *, loff_t *); | 27 | size_t *, loff_t *); |
21 | int color_nr_pages_handler(struct ctl_table *, int, void __user *, | 28 | int color_nr_pages_handler(struct ctl_table *, int, void __user *, |
@@ -38,3 +45,5 @@ int color_reclaim_pages_handler(struct ctl_table *, int, void __user *, | |||
38 | #endif | 45 | #endif |
39 | 46 | ||
40 | #endif | 47 | #endif |
48 | |||
49 | #endif | ||
diff --git a/include/litmus/dgl.h b/include/litmus/dgl.h new file mode 100644 index 000000000000..2bf61d4a7547 --- /dev/null +++ b/include/litmus/dgl.h | |||
@@ -0,0 +1,61 @@ | |||
1 | #ifndef __DGL_H_ | ||
2 | #define __DGL_H_ | ||
3 | |||
4 | #include <litmus/color.h> | ||
5 | #include <linux/list.h> | ||
6 | |||
7 | #define WP(num, word) (num / word + (num % word != 0)) | ||
8 | |||
9 | #define NUM_REPLICAS NUM_WAYS | ||
10 | #define NUM_RESOURCES NUM_COLORS | ||
11 | #define MASK_SIZE (sizeof(unsigned long) * 8) | ||
12 | #define MASK_WORDS WP(NUM_RESOURCES, MASK_SIZE) | ||
13 | |||
14 | /* | ||
15 | * A request for @replica amount of a single resource. | ||
16 | */ | ||
17 | struct dgl_req { | ||
18 | unsigned short replicas; | ||
19 | struct list_head list; | ||
20 | }; | ||
21 | |||
22 | /* | ||
23 | * Simultaneous @requests for multiple resources. | ||
24 | */ | ||
25 | struct dgl_group_req { | ||
26 | int cpu; | ||
27 | unsigned long requested[MASK_WORDS]; | ||
28 | unsigned long waiting[MASK_WORDS]; | ||
29 | struct dgl_req requests[NUM_RESOURCES]; | ||
30 | unsigned long long ts; | ||
31 | }; | ||
32 | |||
33 | /* | ||
34 | * A single resource. | ||
35 | */ | ||
36 | struct dgl_resource { | ||
37 | unsigned int free_replicas; | ||
38 | struct list_head waiting; | ||
39 | }; | ||
40 | |||
41 | /* | ||
42 | * A group of resources. | ||
43 | */ | ||
44 | struct dgl { | ||
45 | struct dgl_resource resources[NUM_RESOURCES]; | ||
46 | struct dgl_group_req* acquired[NR_CPUS]; | ||
47 | |||
48 | char requests; | ||
49 | char running; | ||
50 | unsigned long long ts; | ||
51 | }; | ||
52 | |||
53 | void dgl_init(struct dgl *dgl); | ||
54 | void dgl_group_req_init(struct dgl_group_req *greq); | ||
55 | |||
56 | void set_req(struct dgl_group_req *greq, int resource, int replicas); | ||
57 | |||
58 | void add_group_req(struct dgl *dgl, struct dgl_group_req *greq, int cpu); | ||
59 | void remove_group_req(struct dgl *dgl, struct dgl_group_req *greq); | ||
60 | |||
61 | #endif | ||
diff --git a/include/litmus/fifo_common.h b/include/litmus/fifo_common.h new file mode 100644 index 000000000000..4756f77bd511 --- /dev/null +++ b/include/litmus/fifo_common.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * EDF common data structures and utility functions shared by all EDF | ||
3 | * based scheduler plugins | ||
4 | */ | ||
5 | |||
6 | /* CLEANUP: Add comments and make it less messy. | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #ifndef __FIFO_COMMON_H__ | ||
11 | #define __FIFO_COMMON_H__ | ||
12 | |||
13 | #include <litmus/rt_domain.h> | ||
14 | |||
15 | void fifo_domain_init(rt_domain_t* rt, check_resched_needed_t resched, | ||
16 | release_jobs_t release); | ||
17 | |||
18 | int fifo_higher_prio(struct task_struct* first, | ||
19 | struct task_struct* second); | ||
20 | |||
21 | int fifo_ready_order(struct bheap_node* a, struct bheap_node* b); | ||
22 | |||
23 | int fifo_preemption_needed(rt_domain_t* rt, struct task_struct *t); | ||
24 | |||
25 | #endif | ||
diff --git a/include/litmus/litmus.h b/include/litmus/litmus.h index 0b071fd359f9..f0ddb89e68dd 100644 --- a/include/litmus/litmus.h +++ b/include/litmus/litmus.h | |||
@@ -44,6 +44,8 @@ void litmus_exit_task(struct task_struct *tsk); | |||
44 | 44 | ||
45 | #define tsk_rt(t) (&(t)->rt_param) | 45 | #define tsk_rt(t) (&(t)->rt_param) |
46 | 46 | ||
47 | #define get_server_job(t) (tsk_rt(t)->job_params.fake_job_no) | ||
48 | |||
47 | /* Realtime utility macros */ | 49 | /* Realtime utility macros */ |
48 | #define get_rt_flags(t) (tsk_rt(t)->flags) | 50 | #define get_rt_flags(t) (tsk_rt(t)->flags) |
49 | #define set_rt_flags(t,f) (tsk_rt(t)->flags=(f)) | 51 | #define set_rt_flags(t,f) (tsk_rt(t)->flags=(f)) |
@@ -51,10 +53,13 @@ void litmus_exit_task(struct task_struct *tsk); | |||
51 | #define get_exec_time(t) (tsk_rt(t)->job_params.exec_time) | 53 | #define get_exec_time(t) (tsk_rt(t)->job_params.exec_time) |
52 | #define get_rt_period(t) (tsk_rt(t)->task_params.period) | 54 | #define get_rt_period(t) (tsk_rt(t)->task_params.period) |
53 | #define get_rt_phase(t) (tsk_rt(t)->task_params.phase) | 55 | #define get_rt_phase(t) (tsk_rt(t)->task_params.phase) |
56 | #define get_rt_job(t) (tsk_rt(t)->job_params.job_no) | ||
54 | #define get_partition(t) (tsk_rt(t)->task_params.cpu) | 57 | #define get_partition(t) (tsk_rt(t)->task_params.cpu) |
55 | #define get_deadline(t) (tsk_rt(t)->job_params.deadline) | 58 | #define get_deadline(t) (tsk_rt(t)->job_params.deadline) |
56 | #define get_release(t) (tsk_rt(t)->job_params.release) | 59 | #define get_release(t) (tsk_rt(t)->job_params.release) |
57 | #define get_class(t) (tsk_rt(t)->task_params.cls) | 60 | #define get_class(t) (tsk_rt(t)->task_params.cls) |
61 | #define is_server(t) (tsk_rt(t)->is_server) | ||
62 | #define get_task_server(task) (tsk_rt(task)->server) | ||
58 | 63 | ||
59 | #define is_priority_boosted(t) (tsk_rt(t)->priority_boosted) | 64 | #define is_priority_boosted(t) (tsk_rt(t)->priority_boosted) |
60 | #define get_boost_start(t) (tsk_rt(t)->boost_start_time) | 65 | #define get_boost_start(t) (tsk_rt(t)->boost_start_time) |
@@ -128,6 +133,16 @@ void srp_ceiling_block(void); | |||
128 | 133 | ||
129 | #define bheap2task(hn) ((struct task_struct*) hn->value) | 134 | #define bheap2task(hn) ((struct task_struct*) hn->value) |
130 | 135 | ||
136 | static inline struct control_page* get_control_page(struct task_struct *t) | ||
137 | { | ||
138 | return tsk_rt(t)->ctrl_page; | ||
139 | } | ||
140 | |||
141 | static inline int has_control_page(struct task_struct* t) | ||
142 | { | ||
143 | return tsk_rt(t)->ctrl_page != NULL; | ||
144 | } | ||
145 | |||
131 | #ifdef CONFIG_NP_SECTION | 146 | #ifdef CONFIG_NP_SECTION |
132 | 147 | ||
133 | static inline int is_kernel_np(struct task_struct *t) | 148 | static inline int is_kernel_np(struct task_struct *t) |
@@ -230,10 +245,6 @@ static inline int is_np(struct task_struct *t) | |||
230 | int kernel, user; | 245 | int kernel, user; |
231 | kernel = is_kernel_np(t); | 246 | kernel = is_kernel_np(t); |
232 | user = is_user_np(t); | 247 | user = is_user_np(t); |
233 | if (kernel || user) | ||
234 | TRACE_TASK(t, " is non-preemptive: kernel=%d user=%d\n", | ||
235 | |||
236 | kernel, user); | ||
237 | return kernel || user; | 248 | return kernel || user; |
238 | #else | 249 | #else |
239 | return unlikely(is_kernel_np(t) || is_user_np(t)); | 250 | return unlikely(is_kernel_np(t) || is_user_np(t)); |
diff --git a/include/litmus/locking.h b/include/litmus/locking.h index 4d7b870cb443..41991d5af01b 100644 --- a/include/litmus/locking.h +++ b/include/litmus/locking.h | |||
@@ -9,6 +9,7 @@ struct litmus_lock_ops; | |||
9 | struct litmus_lock { | 9 | struct litmus_lock { |
10 | struct litmus_lock_ops *ops; | 10 | struct litmus_lock_ops *ops; |
11 | int type; | 11 | int type; |
12 | int id; | ||
12 | }; | 13 | }; |
13 | 14 | ||
14 | struct litmus_lock_ops { | 15 | struct litmus_lock_ops { |
diff --git a/include/litmus/rt_domain.h b/include/litmus/rt_domain.h index ac249292e866..b243f998fef7 100644 --- a/include/litmus/rt_domain.h +++ b/include/litmus/rt_domain.h | |||
@@ -82,6 +82,8 @@ void __add_ready(rt_domain_t* rt, struct task_struct *new); | |||
82 | void __merge_ready(rt_domain_t* rt, struct bheap *tasks); | 82 | void __merge_ready(rt_domain_t* rt, struct bheap *tasks); |
83 | void __add_release(rt_domain_t* rt, struct task_struct *task); | 83 | void __add_release(rt_domain_t* rt, struct task_struct *task); |
84 | 84 | ||
85 | struct release_heap* release_heap_alloc(int gfp_flags); | ||
86 | |||
85 | static inline struct task_struct* __take_ready(rt_domain_t* rt) | 87 | static inline struct task_struct* __take_ready(rt_domain_t* rt) |
86 | { | 88 | { |
87 | struct bheap_node* hn = bheap_take(rt->order, &rt->ready_queue); | 89 | struct bheap_node* hn = bheap_take(rt->order, &rt->ready_queue); |
diff --git a/include/litmus/rt_param.h b/include/litmus/rt_param.h index ed9b7d20a763..2991fff58bc6 100644 --- a/include/litmus/rt_param.h +++ b/include/litmus/rt_param.h | |||
@@ -5,6 +5,8 @@ | |||
5 | #ifndef _LINUX_RT_PARAM_H_ | 5 | #ifndef _LINUX_RT_PARAM_H_ |
6 | #define _LINUX_RT_PARAM_H_ | 6 | #define _LINUX_RT_PARAM_H_ |
7 | 7 | ||
8 | #include <litmus/color.h> | ||
9 | |||
8 | /* Litmus time type. */ | 10 | /* Litmus time type. */ |
9 | typedef unsigned long long lt_t; | 11 | typedef unsigned long long lt_t; |
10 | 12 | ||
@@ -69,7 +71,10 @@ union np_flag { | |||
69 | struct control_page { | 71 | struct control_page { |
70 | volatile union np_flag sched; | 72 | volatile union np_flag sched; |
71 | 73 | ||
72 | /* to be extended */ | 74 | /* locking overhead tracing: time stamp prior to system call */ |
75 | uint64_t ts_syscall_start; /* Feather-Trace cycles */ | ||
76 | |||
77 | int requests[NUM_COLORS]; | ||
73 | }; | 78 | }; |
74 | 79 | ||
75 | #ifndef __KERNEL__ | 80 | #ifndef __KERNEL__ |
@@ -92,6 +97,8 @@ struct color_ctrl_page { | |||
92 | struct _rt_domain; | 97 | struct _rt_domain; |
93 | struct bheap_node; | 98 | struct bheap_node; |
94 | struct release_heap; | 99 | struct release_heap; |
100 | struct rt_server; | ||
101 | struct dgl_group_req; | ||
95 | 102 | ||
96 | struct rt_job { | 103 | struct rt_job { |
97 | /* Time instant the the job was or will be released. */ | 104 | /* Time instant the the job was or will be released. */ |
@@ -128,6 +135,8 @@ struct rt_param { | |||
128 | /* is the task present? (true if it can be scheduled) */ | 135 | /* is the task present? (true if it can be scheduled) */ |
129 | unsigned int present:1; | 136 | unsigned int present:1; |
130 | 137 | ||
138 | unsigned int is_server:1; | ||
139 | |||
131 | #ifdef CONFIG_LITMUS_LOCKING | 140 | #ifdef CONFIG_LITMUS_LOCKING |
132 | /* Is the task being priority-boosted by a locking protocol? */ | 141 | /* Is the task being priority-boosted by a locking protocol? */ |
133 | unsigned int priority_boosted:1; | 142 | unsigned int priority_boosted:1; |
@@ -135,6 +144,8 @@ struct rt_param { | |||
135 | lt_t boost_start_time; | 144 | lt_t boost_start_time; |
136 | #endif | 145 | #endif |
137 | 146 | ||
147 | struct rt_server *server; | ||
148 | |||
138 | /* user controlled parameters */ | 149 | /* user controlled parameters */ |
139 | struct rt_task task_params; | 150 | struct rt_task task_params; |
140 | 151 | ||
@@ -213,6 +224,7 @@ struct rt_param { | |||
213 | struct control_page * ctrl_page; | 224 | struct control_page * ctrl_page; |
214 | 225 | ||
215 | struct color_ctrl_page *color_ctrl_page; | 226 | struct color_ctrl_page *color_ctrl_page; |
227 | struct dgl_group_req *req; | ||
216 | }; | 228 | }; |
217 | 229 | ||
218 | /* Possible RT flags */ | 230 | /* Possible RT flags */ |
diff --git a/include/litmus/rt_server.h b/include/litmus/rt_server.h new file mode 100644 index 000000000000..0f3147707a3b --- /dev/null +++ b/include/litmus/rt_server.h | |||
@@ -0,0 +1,39 @@ | |||
1 | #ifndef __RT_SERVER_H | ||
2 | #define __RT_SERVER_H | ||
3 | |||
4 | #include <linux/sched.h> | ||
5 | #include <litmus/litmus.h> | ||
6 | #include <litmus/rt_domain.h> | ||
7 | |||
8 | struct rt_server; | ||
9 | |||
10 | typedef int (*need_preempt_t)(rt_domain_t *rt, struct task_struct *t); | ||
11 | typedef void (*server_update_t)(struct rt_server *srv); | ||
12 | typedef void (*server_requeue_t)(struct rt_server *srv, struct task_struct *t); | ||
13 | typedef struct task_struct* (*server_take_t)(struct rt_server *srv); | ||
14 | |||
15 | struct rt_server { | ||
16 | int sid; | ||
17 | int cpu; | ||
18 | struct task_struct* linked; | ||
19 | rt_domain_t* domain; | ||
20 | int running; | ||
21 | |||
22 | /* Does this server have a higher-priority task? */ | ||
23 | need_preempt_t need_preempt; | ||
24 | /* System state has changed, so should server */ | ||
25 | server_update_t update; | ||
26 | /* Requeue task in domain */ | ||
27 | server_requeue_t requeue; | ||
28 | /* Take next task from domain */ | ||
29 | server_take_t take; | ||
30 | }; | ||
31 | |||
32 | void init_rt_server(struct rt_server *server, | ||
33 | int sid, int cpu, rt_domain_t *domain, | ||
34 | need_preempt_t need_preempt, | ||
35 | server_requeue_t requeue, | ||
36 | server_update_t update, | ||
37 | server_take_t take); | ||
38 | |||
39 | #endif | ||
diff --git a/include/litmus/sched_plugin.h b/include/litmus/sched_plugin.h index 6e7cabdddae8..0f529fa78b4d 100644 --- a/include/litmus/sched_plugin.h +++ b/include/litmus/sched_plugin.h | |||
@@ -11,6 +11,8 @@ | |||
11 | #include <litmus/locking.h> | 11 | #include <litmus/locking.h> |
12 | #endif | 12 | #endif |
13 | 13 | ||
14 | struct litmus_lock; | ||
15 | |||
14 | /************************ setup/tear down ********************/ | 16 | /************************ setup/tear down ********************/ |
15 | 17 | ||
16 | typedef long (*activate_plugin_t) (void); | 18 | typedef long (*activate_plugin_t) (void); |
@@ -67,6 +69,9 @@ typedef long (*admit_task_t)(struct task_struct* tsk); | |||
67 | 69 | ||
68 | typedef void (*release_at_t)(struct task_struct *t, lt_t start); | 70 | typedef void (*release_at_t)(struct task_struct *t, lt_t start); |
69 | 71 | ||
72 | /* TODO remove me */ | ||
73 | typedef void (*release_ts_t)(lt_t time); | ||
74 | |||
70 | struct sched_plugin { | 75 | struct sched_plugin { |
71 | struct list_head list; | 76 | struct list_head list; |
72 | /* basic info */ | 77 | /* basic info */ |
@@ -93,6 +98,8 @@ struct sched_plugin { | |||
93 | task_block_t task_block; | 98 | task_block_t task_block; |
94 | task_exit_t task_exit; | 99 | task_exit_t task_exit; |
95 | 100 | ||
101 | release_ts_t release_ts; | ||
102 | |||
96 | #ifdef CONFIG_LITMUS_LOCKING | 103 | #ifdef CONFIG_LITMUS_LOCKING |
97 | /* locking protocols */ | 104 | /* locking protocols */ |
98 | allocate_lock_t allocate_lock; | 105 | allocate_lock_t allocate_lock; |
diff --git a/include/litmus/sched_trace.h b/include/litmus/sched_trace.h index 7ca34cb13881..96d7666aa22c 100644 --- a/include/litmus/sched_trace.h +++ b/include/litmus/sched_trace.h | |||
@@ -24,7 +24,8 @@ struct st_param_data { /* regular params */ | |||
24 | u32 phase; | 24 | u32 phase; |
25 | u8 partition; | 25 | u8 partition; |
26 | u8 class; | 26 | u8 class; |
27 | u8 __unused[2]; | 27 | u8 level; |
28 | u8 __unused[1]; | ||
28 | }; | 29 | }; |
29 | 30 | ||
30 | struct st_release_data { /* A job is was/is going to be released. */ | 31 | struct st_release_data { /* A job is was/is going to be released. */ |
@@ -71,8 +72,8 @@ struct st_resume_data { /* A task resumes. */ | |||
71 | 72 | ||
72 | struct st_action_data { | 73 | struct st_action_data { |
73 | u64 when; | 74 | u64 when; |
74 | u8 action; | 75 | u32 action; |
75 | u8 __unused[7]; | 76 | u8 __unused[4]; |
76 | }; | 77 | }; |
77 | 78 | ||
78 | struct st_sys_release_data { | 79 | struct st_sys_release_data { |
@@ -164,34 +165,156 @@ feather_callback void do_sched_trace_sys_release(unsigned long id, | |||
164 | 165 | ||
165 | #endif | 166 | #endif |
166 | 167 | ||
168 | #ifdef CONFIG_SCHED_LITMUS_TRACEPOINT | ||
169 | |||
170 | #include <trace/events/litmus.h> | ||
171 | |||
172 | #else | ||
173 | |||
174 | #warning this is happeing | ||
175 | |||
176 | /* Override trace macros to actually do nothing */ | ||
177 | #define trace_litmus_task_param(t) | ||
178 | #define trace_litmus_task_release(t) | ||
179 | #define trace_litmus_switch_to(t) | ||
180 | #define trace_litmus_switch_away(prev) | ||
181 | #define trace_litmus_task_completion(t, forced) | ||
182 | #define trace_litmus_task_block(t, i) | ||
183 | #define trace_litmus_task_resume(t, i) | ||
184 | #define trace_litmus_sys_release(start) | ||
185 | |||
186 | #define trace_litmus_resource_acquire(t, i); | ||
187 | #define trace_litmus_resource_release(t, i); | ||
188 | #define trace_litmus_priority_donate(t, d, i) | ||
189 | |||
190 | #define trace_litmus_container_param(cid, name) | ||
191 | #define trace_litmus_server_param(sid, cid, wcet, time) | ||
192 | #define trace_litmus_server_switch_to(sid, job, tid, tjob) | ||
193 | #define trace_litmus_server_switch_away(sid, job, tid, tjob) | ||
194 | #define trace_litmus_server_release(sid, job, release, deadline) | ||
195 | #define trace_litmus_server_completion(sid, job) | ||
196 | |||
197 | #endif | ||
198 | |||
167 | 199 | ||
168 | #define SCHED_TRACE_BASE_ID 500 | 200 | #define SCHED_TRACE_BASE_ID 500 |
169 | 201 | ||
170 | 202 | ||
171 | #define sched_trace_task_name(t) \ | 203 | #define sched_trace_task_name(t) \ |
172 | SCHED_TRACE(SCHED_TRACE_BASE_ID + 1, do_sched_trace_task_name, t) | 204 | SCHED_TRACE(SCHED_TRACE_BASE_ID + 1, \ |
173 | #define sched_trace_task_param(t) \ | 205 | do_sched_trace_task_name, t) |
174 | SCHED_TRACE(SCHED_TRACE_BASE_ID + 2, do_sched_trace_task_param, t) | 206 | |
175 | #define sched_trace_task_release(t) \ | 207 | #define sched_trace_task_param(t) \ |
176 | SCHED_TRACE(SCHED_TRACE_BASE_ID + 3, do_sched_trace_task_release, t) | 208 | do { \ |
177 | #define sched_trace_task_switch_to(t) \ | 209 | SCHED_TRACE(SCHED_TRACE_BASE_ID + 2, \ |
178 | SCHED_TRACE(SCHED_TRACE_BASE_ID + 4, do_sched_trace_task_switch_to, t) | 210 | do_sched_trace_task_param, t); \ |
179 | #define sched_trace_task_switch_away(t) \ | 211 | trace_litmus_task_param(t); \ |
180 | SCHED_TRACE(SCHED_TRACE_BASE_ID + 5, do_sched_trace_task_switch_away, t) | 212 | } while (0) |
181 | #define sched_trace_task_completion(t, forced) \ | 213 | |
182 | SCHED_TRACE2(SCHED_TRACE_BASE_ID + 6, do_sched_trace_task_completion, t, \ | 214 | #define sched_trace_task_release(t) \ |
183 | (unsigned long) forced) | 215 | do { \ |
184 | #define sched_trace_task_block(t) \ | 216 | SCHED_TRACE(SCHED_TRACE_BASE_ID + 3, \ |
185 | SCHED_TRACE(SCHED_TRACE_BASE_ID + 7, do_sched_trace_task_block, t) | 217 | do_sched_trace_task_release, t); \ |
186 | #define sched_trace_task_resume(t) \ | 218 | trace_litmus_task_release(t); \ |
187 | SCHED_TRACE(SCHED_TRACE_BASE_ID + 8, do_sched_trace_task_resume, t) | 219 | } while (0) |
188 | #define sched_trace_action(t, action) \ | 220 | |
189 | SCHED_TRACE2(SCHED_TRACE_BASE_ID + 9, do_sched_trace_action, t, \ | 221 | #define sched_trace_task_switch_to(t) \ |
190 | (unsigned long) action); | 222 | do { \ |
191 | /* when is a pointer, it does not need an explicit cast to unsigned long */ | 223 | SCHED_TRACE(SCHED_TRACE_BASE_ID + 4, \ |
192 | #define sched_trace_sys_release(when) \ | 224 | do_sched_trace_task_switch_to, t); \ |
193 | SCHED_TRACE(SCHED_TRACE_BASE_ID + 10, do_sched_trace_sys_release, when) | 225 | trace_litmus_switch_to(t); \ |
226 | } while (0) | ||
227 | |||
228 | #define sched_trace_task_switch_away(t) \ | ||
229 | do { \ | ||
230 | SCHED_TRACE(SCHED_TRACE_BASE_ID + 5, \ | ||
231 | do_sched_trace_task_switch_away, t); \ | ||
232 | trace_litmus_switch_away(t); \ | ||
233 | } while (0) | ||
234 | |||
235 | #define sched_trace_task_completion(t, forced) \ | ||
236 | do { \ | ||
237 | SCHED_TRACE2(SCHED_TRACE_BASE_ID + 6, \ | ||
238 | do_sched_trace_task_completion, t, \ | ||
239 | (unsigned long) forced); \ | ||
240 | trace_litmus_task_completion(t, forced); \ | ||
241 | } while (0) | ||
242 | |||
243 | #define sched_trace_task_block(t, i) \ | ||
244 | do { \ | ||
245 | SCHED_TRACE(SCHED_TRACE_BASE_ID + 7, \ | ||
246 | do_sched_trace_task_block, t); \ | ||
247 | trace_litmus_task_block(t, i); \ | ||
248 | } while (0) | ||
249 | |||
250 | #define sched_trace_task_resume(t, i) \ | ||
251 | do { \ | ||
252 | SCHED_TRACE(SCHED_TRACE_BASE_ID + 8, \ | ||
253 | do_sched_trace_task_resume, t); \ | ||
254 | trace_litmus_task_resume(t, i); \ | ||
255 | } while (0) | ||
256 | |||
257 | #define sched_trace_action(t, action) \ | ||
258 | SCHED_TRACE2(SCHED_TRACE_BASE_ID + 9, \ | ||
259 | do_sched_trace_action, t, (unsigned long) action); | ||
194 | 260 | ||
261 | /* when is a pointer, it does not need an explicit cast to unsigned long */ | ||
262 | #define sched_trace_sys_release(when) \ | ||
263 | do { \ | ||
264 | SCHED_TRACE(SCHED_TRACE_BASE_ID + 10, \ | ||
265 | do_sched_trace_sys_release, when); \ | ||
266 | trace_litmus_sys_release(when); \ | ||
267 | } while (0) | ||
268 | |||
269 | #define QT_START lt_t _qt_start = litmus_clock() | ||
270 | #define QT_END \ | ||
271 | sched_trace_log_message("%d P%d [%s@%s:%d]: Took %llu\n\n", \ | ||
272 | TRACE_ARGS, litmus_clock() - _qt_start) | ||
273 | |||
274 | #define sched_trace_resource_acquire(t, i) \ | ||
275 | do { \ | ||
276 | trace_litmus_resource_acquire(t, i); \ | ||
277 | } while (0) | ||
278 | |||
279 | #define sched_trace_resource_release(t, i) \ | ||
280 | do { \ | ||
281 | trace_litmus_resource_release(t, i); \ | ||
282 | } while (0) | ||
283 | |||
284 | #define sched_trace_priority_donate(t, d, i) \ | ||
285 | do { \ | ||
286 | trace_litmus_priority_donate(t, d, i); \ | ||
287 | } while (0) | ||
288 | |||
289 | #define sched_trace_container_param(cid, name) \ | ||
290 | do { \ | ||
291 | trace_litmus_container_param(cid, name); \ | ||
292 | } while (0) | ||
293 | |||
294 | #define sched_trace_server_param(sid, cid, wcet, period) \ | ||
295 | do { \ | ||
296 | trace_litmus_server_param(sid, cid, wcet, period); \ | ||
297 | } while(0) | ||
298 | |||
299 | #define sched_trace_server_switch_to(sid, job, tid, tjob) \ | ||
300 | do { \ | ||
301 | trace_litmus_server_switch_to(sid, job, tid, tjob); \ | ||
302 | } while(0) | ||
303 | |||
304 | #define sched_trace_server_switch_away(sid, job, tid, tjob) \ | ||
305 | do { \ | ||
306 | trace_litmus_server_switch_away(sid, job, tid, tjob); \ | ||
307 | } while (0) | ||
308 | |||
309 | #define sched_trace_server_release(sid, job, rel, dead) \ | ||
310 | do { \ | ||
311 | trace_litmus_server_release(sid, job, rel, dead); \ | ||
312 | } while (0) | ||
313 | |||
314 | #define sched_trace_server_completion(sid, job) \ | ||
315 | do { \ | ||
316 | trace_litmus_server_completion(sid, job); \ | ||
317 | } while (0) | ||
195 | 318 | ||
196 | #define sched_trace_quantum_boundary() /* NOT IMPLEMENTED */ | 319 | #define sched_trace_quantum_boundary() /* NOT IMPLEMENTED */ |
197 | 320 | ||
diff --git a/include/trace/events/litmus.h b/include/trace/events/litmus.h new file mode 100644 index 000000000000..136a80db54a4 --- /dev/null +++ b/include/trace/events/litmus.h | |||
@@ -0,0 +1,425 @@ | |||
1 | /* | ||
2 | * LITMUS^RT kernel style scheduling tracepoints | ||
3 | */ | ||
4 | #undef TRACE_SYSTEM | ||
5 | #define TRACE_SYSTEM litmus | ||
6 | |||
7 | #if !defined(_SCHED_TASK_TRACEPOINT_H) || defined(TRACE_HEADER_MULTI_READ) | ||
8 | #define _SCHED_TASK_TRACEPOINT_H | ||
9 | |||
10 | #include <linux/tracepoint.h> | ||
11 | |||
12 | #include <litmus/litmus.h> | ||
13 | #include <litmus/rt_param.h> | ||
14 | |||
15 | TRACE_EVENT(litmus_task_param, | ||
16 | |||
17 | TP_PROTO(struct task_struct *t), | ||
18 | |||
19 | TP_ARGS(t), | ||
20 | |||
21 | TP_STRUCT__entry( | ||
22 | __field( pid_t, pid ) | ||
23 | __field( unsigned int, job ) | ||
24 | __field( unsigned long long, wcet ) | ||
25 | __field( unsigned long long, period ) | ||
26 | __field( unsigned long long, phase ) | ||
27 | __field( int, partition ) | ||
28 | ), | ||
29 | |||
30 | TP_fast_assign( | ||
31 | __entry->pid = t ? t->pid : 0; | ||
32 | __entry->job = t ? t->rt_param.job_params.job_no : 0; | ||
33 | __entry->wcet = get_exec_cost(t); | ||
34 | __entry->period = get_rt_period(t); | ||
35 | __entry->phase = get_rt_phase(t); | ||
36 | __entry->partition = get_partition(t); | ||
37 | ), | ||
38 | |||
39 | TP_printk("period(%d, %Lu).\nwcet(%d, %Lu).\n", | ||
40 | __entry->pid, __entry->period, | ||
41 | __entry->pid, __entry->wcet) | ||
42 | ); | ||
43 | |||
44 | /* | ||
45 | * Tracing jobs release | ||
46 | */ | ||
47 | TRACE_EVENT(litmus_task_release, | ||
48 | |||
49 | TP_PROTO(struct task_struct *t), | ||
50 | |||
51 | TP_ARGS(t), | ||
52 | |||
53 | TP_STRUCT__entry( | ||
54 | __field( pid_t, pid ) | ||
55 | __field( unsigned int, job ) | ||
56 | __field( unsigned long long, release ) | ||
57 | __field( unsigned long long, deadline ) | ||
58 | ), | ||
59 | |||
60 | TP_fast_assign( | ||
61 | __entry->pid = t ? t->pid : 0; | ||
62 | __entry->job = t ? t->rt_param.job_params.job_no : 0; | ||
63 | __entry->release = get_release(t); | ||
64 | __entry->deadline = get_deadline(t); | ||
65 | ), | ||
66 | |||
67 | TP_printk("release(job(%u, %u)): %Lu\ndeadline(job(%u, %u)): %Lu\n", | ||
68 | __entry->pid, __entry->job, __entry->release, | ||
69 | __entry->pid, __entry->job, __entry->deadline) | ||
70 | ); | ||
71 | |||
72 | /* | ||
73 | * Tracepoint for switching to new task | ||
74 | */ | ||
75 | TRACE_EVENT(litmus_switch_to, | ||
76 | |||
77 | TP_PROTO(struct task_struct *t), | ||
78 | |||
79 | TP_ARGS(t), | ||
80 | |||
81 | TP_STRUCT__entry( | ||
82 | __field( pid_t, pid ) | ||
83 | __field( unsigned int, job ) | ||
84 | __field( unsigned long long, exec_time ) | ||
85 | ), | ||
86 | |||
87 | TP_fast_assign( | ||
88 | __entry->pid = t->pid;//is_realtime(t) ? t->pid : 0; | ||
89 | __entry->job = t->rt_param.job_params.job_no;//is_realtime(t) ? t->rt_param.job_params.job_no : 0; | ||
90 | __entry->exec_time = get_exec_time(t); | ||
91 | ), | ||
92 | |||
93 | TP_printk("switch_to(job(%u, %u)): (exec: %Lu)\n", | ||
94 | __entry->pid, __entry->job, | ||
95 | __entry->exec_time) | ||
96 | ); | ||
97 | |||
98 | /* | ||
99 | * Tracepoint for switching away previous task | ||
100 | */ | ||
101 | TRACE_EVENT(litmus_switch_away, | ||
102 | |||
103 | TP_PROTO(struct task_struct *t), | ||
104 | |||
105 | TP_ARGS(t), | ||
106 | |||
107 | TP_STRUCT__entry( | ||
108 | __field( pid_t, pid ) | ||
109 | __field( unsigned int, job ) | ||
110 | __field( unsigned long long, exec_time ) | ||
111 | ), | ||
112 | |||
113 | TP_fast_assign( | ||
114 | __entry->pid = t->pid;//is_realtime(t) ? t->pid : 0; | ||
115 | __entry->job = t->rt_param.job_params.job_no;//is_realtime(t) ? t->rt_param.job_params.job_no : 0; | ||
116 | __entry->exec_time = get_exec_time(t); | ||
117 | ), | ||
118 | |||
119 | TP_printk("switch_away(job(%u, %u)): (exec: %Lu)\n", | ||
120 | __entry->pid, __entry->job, | ||
121 | __entry->exec_time) | ||
122 | ); | ||
123 | |||
124 | /* | ||
125 | * Tracing jobs completion | ||
126 | */ | ||
127 | TRACE_EVENT(litmus_task_completion, | ||
128 | |||
129 | TP_PROTO(struct task_struct *t, unsigned long forced), | ||
130 | |||
131 | TP_ARGS(t, forced), | ||
132 | |||
133 | TP_STRUCT__entry( | ||
134 | __field( pid_t, pid ) | ||
135 | __field( unsigned int, job ) | ||
136 | __field( unsigned long, forced ) | ||
137 | ), | ||
138 | |||
139 | TP_fast_assign( | ||
140 | __entry->pid = t ? t->pid : 0; | ||
141 | __entry->job = t ? t->rt_param.job_params.job_no : 0; | ||
142 | __entry->forced = forced; | ||
143 | ), | ||
144 | |||
145 | TP_printk("completed(job(%u, %u)): (forced: %lu)\n", | ||
146 | __entry->pid, __entry->job, | ||
147 | __entry->forced) | ||
148 | ); | ||
149 | |||
150 | /* | ||
151 | * Trace blocking tasks. | ||
152 | */ | ||
153 | TRACE_EVENT(litmus_task_block, | ||
154 | |||
155 | TP_PROTO(struct task_struct *t, int lid), | ||
156 | |||
157 | TP_ARGS(t, lid), | ||
158 | |||
159 | TP_STRUCT__entry( | ||
160 | __field( pid_t, pid ) | ||
161 | __field( int, lid ) | ||
162 | ), | ||
163 | |||
164 | TP_fast_assign( | ||
165 | __entry->pid = t ? t->pid : 0; | ||
166 | __entry->lid = lid; | ||
167 | ), | ||
168 | |||
169 | TP_printk("(%u) blocks on %d\n", __entry->pid, | ||
170 | __entry->lid) | ||
171 | ); | ||
172 | |||
173 | /* | ||
174 | * Lock events | ||
175 | */ | ||
176 | TRACE_EVENT(litmus_resource_acquire, | ||
177 | |||
178 | TP_PROTO(struct task_struct *t, int lid), | ||
179 | |||
180 | TP_ARGS(t, lid), | ||
181 | |||
182 | TP_STRUCT__entry( | ||
183 | __field( pid_t, pid ) | ||
184 | __field( int, lid ) | ||
185 | ), | ||
186 | |||
187 | TP_fast_assign( | ||
188 | __entry->pid = t ? t->pid : 0; | ||
189 | __entry->lid = lid; | ||
190 | ), | ||
191 | |||
192 | TP_printk("(%u) acquires %d\n", __entry->pid, | ||
193 | __entry->lid) | ||
194 | ); | ||
195 | |||
196 | TRACE_EVENT(litmus_resource_release, | ||
197 | |||
198 | TP_PROTO(struct task_struct *t, int lid), | ||
199 | |||
200 | TP_ARGS(t, lid), | ||
201 | |||
202 | TP_STRUCT__entry( | ||
203 | __field( pid_t, pid ) | ||
204 | __field( int, lid ) | ||
205 | ), | ||
206 | |||
207 | TP_fast_assign( | ||
208 | __entry->pid = t ? t->pid : 0; | ||
209 | __entry->lid = lid; | ||
210 | ), | ||
211 | |||
212 | TP_printk("(%u) releases %d\n", __entry->pid, | ||
213 | __entry->lid) | ||
214 | ); | ||
215 | |||
216 | TRACE_EVENT(litmus_priority_donate, | ||
217 | |||
218 | TP_PROTO(struct task_struct *t, struct task_struct *donor, int lid), | ||
219 | |||
220 | TP_ARGS(t, donor, lid), | ||
221 | |||
222 | TP_STRUCT__entry( | ||
223 | __field( pid_t, t_pid ) | ||
224 | __field( pid_t, d_pid ) | ||
225 | __field( unsigned long long, prio) | ||
226 | __field( int, lid ) | ||
227 | ), | ||
228 | |||
229 | TP_fast_assign( | ||
230 | __entry->t_pid = t ? t->pid : 0; | ||
231 | __entry->d_pid = donor ? donor->pid : 0; | ||
232 | __entry->prio = get_deadline(donor); | ||
233 | __entry->lid = lid; | ||
234 | ), | ||
235 | |||
236 | TP_printk("(%u) inherits %llu from (%u) on %d\n", __entry->t_pid, | ||
237 | __entry->d_pid, __entry->prio, __entry->lid) | ||
238 | ); | ||
239 | |||
240 | /* | ||
241 | * Tracing jobs resume | ||
242 | */ | ||
243 | TRACE_EVENT(litmus_task_resume, | ||
244 | |||
245 | TP_PROTO(struct task_struct *t, int lid), | ||
246 | |||
247 | TP_ARGS(t, lid), | ||
248 | |||
249 | TP_STRUCT__entry( | ||
250 | __field( pid_t, pid ) | ||
251 | __field( int, lid ) | ||
252 | __field( unsigned int, job ) | ||
253 | ), | ||
254 | |||
255 | TP_fast_assign( | ||
256 | __entry->pid = t ? t->pid : 0; | ||
257 | __entry->job = t ? t->rt_param.job_params.job_no : 0; | ||
258 | __entry->lid = lid; | ||
259 | ), | ||
260 | |||
261 | TP_printk("resume(job(%u, %u)) on %d\n", | ||
262 | __entry->pid, __entry->job, | ||
263 | __entry->lid) | ||
264 | ); | ||
265 | |||
266 | /* | ||
267 | * Trace synchronous release | ||
268 | */ | ||
269 | TRACE_EVENT(litmus_sys_release, | ||
270 | |||
271 | TP_PROTO(unsigned long long *start), | ||
272 | |||
273 | TP_ARGS(start), | ||
274 | |||
275 | TP_STRUCT__entry( | ||
276 | __field( unsigned long long, rel ) | ||
277 | ), | ||
278 | |||
279 | TP_fast_assign( | ||
280 | __entry->rel = *start; | ||
281 | ), | ||
282 | |||
283 | TP_printk("SynRelease(%Lu)\n", __entry->rel) | ||
284 | ); | ||
285 | |||
286 | /* | ||
287 | * Containers | ||
288 | */ | ||
289 | TRACE_EVENT(litmus_container_param, | ||
290 | |||
291 | TP_PROTO(int cid, const char *name), | ||
292 | |||
293 | TP_ARGS(cid, name), | ||
294 | |||
295 | TP_STRUCT__entry( | ||
296 | __field( int, cid ) | ||
297 | __array( char, name, TASK_COMM_LEN ) | ||
298 | ), | ||
299 | |||
300 | TP_fast_assign( | ||
301 | memcpy(__entry->name, name, TASK_COMM_LEN); | ||
302 | __entry->cid = cid; | ||
303 | ), | ||
304 | |||
305 | TP_printk("container, name: %s, id: %d\n", __entry->name, __entry->cid) | ||
306 | ); | ||
307 | |||
308 | TRACE_EVENT(litmus_server_param, | ||
309 | |||
310 | TP_PROTO(int sid, int cid, unsigned long long wcet, unsigned long long period), | ||
311 | |||
312 | TP_ARGS(sid, cid, wcet, period), | ||
313 | |||
314 | TP_STRUCT__entry( | ||
315 | __field( int, sid ) | ||
316 | __field( int, cid ) | ||
317 | __field( unsigned long long, wcet ) | ||
318 | __field( unsigned long long, period ) | ||
319 | ), | ||
320 | |||
321 | TP_fast_assign( | ||
322 | __entry->cid = cid; | ||
323 | __entry->sid = sid; | ||
324 | __entry->wcet = wcet; | ||
325 | __entry->period = period; | ||
326 | ), | ||
327 | |||
328 | TP_printk("server(%llu, %llu), sid: %llu, cont: %llu\n", | ||
329 | __entry->wcet, __entry->period, __entry->sid, __entry->cid) | ||
330 | ); | ||
331 | |||
332 | TRACE_EVENT(litmus_server_switch_to, | ||
333 | |||
334 | TP_PROTO(int sid, unsigned int job, int tid, unsigned int tjob), | ||
335 | |||
336 | TP_ARGS(sid, job, tid, tjob), | ||
337 | |||
338 | TP_STRUCT__entry( | ||
339 | __field( int, sid) | ||
340 | __field( unsigned int, job) | ||
341 | __field( int, tid) | ||
342 | __field( unsigned int, tjob) | ||
343 | ), | ||
344 | |||
345 | TP_fast_assign( | ||
346 | __entry->sid = sid; | ||
347 | __entry->tid = tid; | ||
348 | __entry->job = job; | ||
349 | __entry->tjob = tjob; | ||
350 | ), | ||
351 | |||
352 | TP_printk("switch_to(server(%d, %u)): (%d, %d)\n", __entry->sid, __entry->job, __entry->tid, __entry->tjob) | ||
353 | ); | ||
354 | |||
355 | TRACE_EVENT(litmus_server_switch_away, | ||
356 | |||
357 | TP_PROTO(int sid, unsigned int job, int tid, unsigned int tjob), | ||
358 | |||
359 | TP_ARGS(sid, job, tid, tjob), | ||
360 | |||
361 | TP_STRUCT__entry( | ||
362 | __field( int, sid) | ||
363 | __field( unsigned int, job) | ||
364 | __field( int, tid) | ||
365 | __field( unsigned int, tjob) | ||
366 | ), | ||
367 | |||
368 | TP_fast_assign( | ||
369 | __entry->sid = sid; | ||
370 | __entry->tid = tid; | ||
371 | __entry->job = job; | ||
372 | __entry->tjob = tjob; | ||
373 | ), | ||
374 | |||
375 | TP_printk("switch_away(server(%d, %u)): (%d, %d)\n", __entry->sid, __entry->job, __entry->tid, __entry->tjob) | ||
376 | ); | ||
377 | |||
378 | TRACE_EVENT(litmus_server_release, | ||
379 | |||
380 | TP_PROTO(int sid, unsigned int job, | ||
381 | unsigned long long release, | ||
382 | unsigned long long deadline), | ||
383 | |||
384 | TP_ARGS(sid, job, release, deadline), | ||
385 | |||
386 | TP_STRUCT__entry( | ||
387 | __field( int, sid) | ||
388 | __field( unsigned int, job) | ||
389 | __field( unsigned long long, release) | ||
390 | __field( unsigned long long, deadline) | ||
391 | ), | ||
392 | |||
393 | TP_fast_assign( | ||
394 | __entry->sid = sid; | ||
395 | __entry->job = job; | ||
396 | __entry->release = release; | ||
397 | __entry->deadline = deadline; | ||
398 | ), | ||
399 | |||
400 | TP_printk("release(server(%d, %u)), release: %llu, deadline: %llu\n", __entry->sid, __entry->job, __entry->release, __entry->deadline) | ||
401 | ); | ||
402 | |||
403 | TRACE_EVENT(litmus_server_completion, | ||
404 | |||
405 | TP_PROTO(int sid, int job), | ||
406 | |||
407 | TP_ARGS(sid, job), | ||
408 | |||
409 | TP_STRUCT__entry( | ||
410 | __field( int, sid) | ||
411 | __field( unsigned int, job) | ||
412 | ), | ||
413 | |||
414 | TP_fast_assign( | ||
415 | __entry->sid = sid; | ||
416 | __entry->job = job; | ||
417 | ), | ||
418 | |||
419 | TP_printk("completion(server(%d, %d))\n", __entry->sid, __entry->job) | ||
420 | ); | ||
421 | |||
422 | #endif /* _SCHED_TASK_TRACEPOINT_H */ | ||
423 | |||
424 | /* Must stay outside the protection */ | ||
425 | #include <trace/define_trace.h> | ||
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 533c49f48047..4d6f3474e8fa 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h | |||
@@ -17,6 +17,7 @@ | |||
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/ftrace_event.h> | 19 | #include <linux/ftrace_event.h> |
20 | #include <litmus/litmus.h> | ||
20 | 21 | ||
21 | /* | 22 | /* |
22 | * DECLARE_EVENT_CLASS can be used to add a generic function | 23 | * DECLARE_EVENT_CLASS can be used to add a generic function |
@@ -54,7 +55,7 @@ | |||
54 | #define __string(item, src) __dynamic_array(char, item, -1) | 55 | #define __string(item, src) __dynamic_array(char, item, -1) |
55 | 56 | ||
56 | #undef TP_STRUCT__entry | 57 | #undef TP_STRUCT__entry |
57 | #define TP_STRUCT__entry(args...) args | 58 | #define TP_STRUCT__entry(args...) args __field( unsigned long long, __rt_ts ) |
58 | 59 | ||
59 | #undef DECLARE_EVENT_CLASS | 60 | #undef DECLARE_EVENT_CLASS |
60 | #define DECLARE_EVENT_CLASS(name, proto, args, tstruct, assign, print) \ | 61 | #define DECLARE_EVENT_CLASS(name, proto, args, tstruct, assign, print) \ |
@@ -507,7 +508,7 @@ static inline notrace int ftrace_get_offsets_##call( \ | |||
507 | strcpy(__get_str(dst), src); | 508 | strcpy(__get_str(dst), src); |
508 | 509 | ||
509 | #undef TP_fast_assign | 510 | #undef TP_fast_assign |
510 | #define TP_fast_assign(args...) args | 511 | #define TP_fast_assign(args...) args; __entry->__rt_ts = litmus_clock(); |
511 | 512 | ||
512 | #undef TP_perf_assign | 513 | #undef TP_perf_assign |
513 | #define TP_perf_assign(args...) | 514 | #define TP_perf_assign(args...) |
diff --git a/kernel/sched.c b/kernel/sched.c index baaca61bc3a3..2229d0deec4b 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -80,14 +80,14 @@ | |||
80 | #include "workqueue_sched.h" | 80 | #include "workqueue_sched.h" |
81 | #include "sched_autogroup.h" | 81 | #include "sched_autogroup.h" |
82 | 82 | ||
83 | #define CREATE_TRACE_POINTS | ||
84 | #include <trace/events/sched.h> | ||
85 | |||
83 | #include <litmus/sched_trace.h> | 86 | #include <litmus/sched_trace.h> |
84 | #include <litmus/trace.h> | 87 | #include <litmus/trace.h> |
85 | 88 | ||
86 | static void litmus_tick(struct rq*, struct task_struct*); | 89 | static void litmus_tick(struct rq*, struct task_struct*); |
87 | 90 | ||
88 | #define CREATE_TRACE_POINTS | ||
89 | #include <trace/events/sched.h> | ||
90 | |||
91 | /* | 91 | /* |
92 | * Convert user-nice values [ -20 ... 0 ... 19 ] | 92 | * Convert user-nice values [ -20 ... 0 ... 19 ] |
93 | * to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ], | 93 | * to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ], |
diff --git a/litmus/Kconfig b/litmus/Kconfig index 94b48e199577..68459d4dca41 100644 --- a/litmus/Kconfig +++ b/litmus/Kconfig | |||
@@ -138,6 +138,24 @@ config SCHED_TASK_TRACE_SHIFT | |||
138 | 10 => 1k events | 138 | 10 => 1k events |
139 | 8 => 512 events | 139 | 8 => 512 events |
140 | 140 | ||
141 | config SCHED_LITMUS_TRACEPOINT | ||
142 | bool "Enable Event/Tracepoint Tracing for real-time task tracing" | ||
143 | depends on TRACEPOINTS | ||
144 | default n | ||
145 | help | ||
146 | Enable kernel-style events (tracepoint) for Litmus. Litmus events | ||
147 | trace the same functions as the above sched_trace_XXX(), but can | ||
148 | be enabled independently. | ||
149 | Litmus tracepoints can be recorded and analyzed together (single | ||
150 | time reference) with all other kernel tracing events (e.g., | ||
151 | sched:sched_switch, etc.). | ||
152 | |||
153 | This also enables a quick way to visualize schedule traces using | ||
154 | trace-cmd utility and kernelshark visualizer. | ||
155 | |||
156 | Say Yes for debugging and visualization purposes. | ||
157 | Say No for overhead tracing. | ||
158 | |||
141 | config SCHED_OVERHEAD_TRACE | 159 | config SCHED_OVERHEAD_TRACE |
142 | bool "Record timestamps for overhead measurements" | 160 | bool "Record timestamps for overhead measurements" |
143 | depends on FEATHER_TRACE | 161 | depends on FEATHER_TRACE |
diff --git a/litmus/Makefile b/litmus/Makefile index 2d77d11e905e..d24e9855a7f9 100644 --- a/litmus/Makefile +++ b/litmus/Makefile | |||
@@ -16,16 +16,22 @@ obj-y = sched_plugin.o litmus.o \ | |||
16 | srp.o \ | 16 | srp.o \ |
17 | bheap.o \ | 17 | bheap.o \ |
18 | ctrldev.o \ | 18 | ctrldev.o \ |
19 | sched_gsn_edf.o \ | ||
20 | sched_psn_edf.o \ | ||
21 | color.o \ | 19 | color.o \ |
22 | color_proc.o \ | 20 | color_proc.o \ |
23 | color_dev.o | 21 | color_dev.o \ |
22 | rt_server.o \ | ||
23 | dgl.o \ | ||
24 | fifo_common.o \ | ||
25 | sched_color.o | ||
26 | |||
27 | # sched_psn_edf.o \ | ||
28 | # sched_gsn_edf.o \ | ||
29 | |||
30 | |||
24 | 31 | ||
25 | obj-$(CONFIG_PLUGIN_CEDF) += sched_cedf.o | 32 | obj-$(CONFIG_PLUGIN_CEDF) += sched_cedf.o |
26 | obj-$(CONFIG_PLUGIN_PFAIR) += sched_pfair.o | 33 | obj-$(CONFIG_PLUGIN_PFAIR) += sched_pfair.o |
27 | obj-$(CONFIG_SCHED_CPU_AFFINITY) += affinity.o | 34 | obj-$(CONFIG_SCHED_CPU_AFFINITY) += affinity.o |
28 | |||
29 | obj-$(CONFIG_FEATHER_TRACE) += ft_event.o ftdev.o | 35 | obj-$(CONFIG_FEATHER_TRACE) += ft_event.o ftdev.o |
30 | obj-$(CONFIG_SCHED_TASK_TRACE) += sched_task_trace.o | 36 | obj-$(CONFIG_SCHED_TASK_TRACE) += sched_task_trace.o |
31 | obj-$(CONFIG_SCHED_DEBUG_TRACE) += sched_trace.o | 37 | obj-$(CONFIG_SCHED_DEBUG_TRACE) += sched_trace.o |
diff --git a/litmus/budget.c b/litmus/budget.c index 310e9a3d4172..84f3f22770b1 100644 --- a/litmus/budget.c +++ b/litmus/budget.c | |||
@@ -4,13 +4,8 @@ | |||
4 | 4 | ||
5 | #include <litmus/litmus.h> | 5 | #include <litmus/litmus.h> |
6 | #include <litmus/preempt.h> | 6 | #include <litmus/preempt.h> |
7 | 7 | #include <litmus/budget.h> | |
8 | struct enforcement_timer { | 8 | #include <litmus/sched_trace.h> |
9 | /* The enforcement timer is used to accurately police | ||
10 | * slice budgets. */ | ||
11 | struct hrtimer timer; | ||
12 | int armed; | ||
13 | }; | ||
14 | 9 | ||
15 | DEFINE_PER_CPU(struct enforcement_timer, budget_timer); | 10 | DEFINE_PER_CPU(struct enforcement_timer, budget_timer); |
16 | 11 | ||
@@ -32,7 +27,7 @@ static enum hrtimer_restart on_enforcement_timeout(struct hrtimer *timer) | |||
32 | } | 27 | } |
33 | 28 | ||
34 | /* assumes called with IRQs off */ | 29 | /* assumes called with IRQs off */ |
35 | static void cancel_enforcement_timer(struct enforcement_timer* et) | 30 | void cancel_enforcement_timer(struct enforcement_timer* et) |
36 | { | 31 | { |
37 | int ret; | 32 | int ret; |
38 | 33 | ||
@@ -54,11 +49,10 @@ static void cancel_enforcement_timer(struct enforcement_timer* et) | |||
54 | } | 49 | } |
55 | 50 | ||
56 | /* assumes called with IRQs off */ | 51 | /* assumes called with IRQs off */ |
57 | static void arm_enforcement_timer(struct enforcement_timer* et, | 52 | void arm_enforcement_timer(struct enforcement_timer* et, |
58 | struct task_struct* t) | 53 | struct task_struct* t) |
59 | { | 54 | { |
60 | lt_t when_to_fire; | 55 | lt_t when_to_fire; |
61 | TRACE_TASK(t, "arming enforcement timer.\n"); | ||
62 | 56 | ||
63 | /* Calling this when there is no budget left for the task | 57 | /* Calling this when there is no budget left for the task |
64 | * makes no sense, unless the task is non-preemptive. */ | 58 | * makes no sense, unless the task is non-preemptive. */ |
@@ -67,8 +61,11 @@ static void arm_enforcement_timer(struct enforcement_timer* et, | |||
67 | /* __hrtimer_start_range_ns() cancels the timer | 61 | /* __hrtimer_start_range_ns() cancels the timer |
68 | * anyway, so we don't have to check whether it is still armed */ | 62 | * anyway, so we don't have to check whether it is still armed */ |
69 | 63 | ||
70 | if (likely(!is_np(t))) { | 64 | if (likely(!is_user_np(t))) { |
71 | when_to_fire = litmus_clock() + budget_remaining(t); | 65 | when_to_fire = litmus_clock() + budget_remaining(t); |
66 | TRACE_TASK(t, "arming enforcement timer for %llu.\n", | ||
67 | when_to_fire); | ||
68 | |||
72 | __hrtimer_start_range_ns(&et->timer, | 69 | __hrtimer_start_range_ns(&et->timer, |
73 | ns_to_ktime(when_to_fire), | 70 | ns_to_ktime(when_to_fire), |
74 | 0 /* delta */, | 71 | 0 /* delta */, |
@@ -94,6 +91,11 @@ void update_enforcement_timer(struct task_struct* t) | |||
94 | } | 91 | } |
95 | } | 92 | } |
96 | 93 | ||
94 | void init_enforcement_timer(struct enforcement_timer *et) | ||
95 | { | ||
96 | hrtimer_init(&et->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); | ||
97 | et->timer.function = on_enforcement_timeout; | ||
98 | } | ||
97 | 99 | ||
98 | static int __init init_budget_enforcement(void) | 100 | static int __init init_budget_enforcement(void) |
99 | { | 101 | { |
@@ -102,8 +104,7 @@ static int __init init_budget_enforcement(void) | |||
102 | 104 | ||
103 | for (cpu = 0; cpu < NR_CPUS; cpu++) { | 105 | for (cpu = 0; cpu < NR_CPUS; cpu++) { |
104 | et = &per_cpu(budget_timer, cpu); | 106 | et = &per_cpu(budget_timer, cpu); |
105 | hrtimer_init(&et->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); | 107 | init_enforcement_timer(et); |
106 | et->timer.function = on_enforcement_timeout; | ||
107 | } | 108 | } |
108 | return 0; | 109 | return 0; |
109 | } | 110 | } |
diff --git a/litmus/color_proc.c b/litmus/color_proc.c index 4cb6c9ac89bb..0ac533f96d3e 100644 --- a/litmus/color_proc.c +++ b/litmus/color_proc.c | |||
@@ -2,17 +2,30 @@ | |||
2 | #include <linux/sysctl.h> | 2 | #include <linux/sysctl.h> |
3 | #include <linux/slab.h> | 3 | #include <linux/slab.h> |
4 | 4 | ||
5 | #include <litmus/sched_trace.h> | ||
5 | #include <litmus/color.h> | 6 | #include <litmus/color.h> |
6 | 7 | ||
8 | #define SPERIOD_LEN 7 | ||
9 | #define SPERIOD_FILE "period" | ||
10 | #define SWCET_LEN 5 | ||
11 | #define SWCET_FILE "wcet" | ||
12 | |||
7 | extern int color_sysctl_add_pages_data; /* litmus/color.c */ | 13 | extern int color_sysctl_add_pages_data; /* litmus/color.c */ |
8 | 14 | ||
9 | static int zero = 0; | 15 | static int zero = 0; |
10 | static int one = 1; | 16 | static int one = 1; |
11 | 17 | ||
18 | static unsigned long *server_wcet; | ||
19 | static unsigned long *server_period; | ||
20 | |||
12 | #define NR_PAGES_INDEX 0 /* location of nr_pages in the table below */ | 21 | #define NR_PAGES_INDEX 0 /* location of nr_pages in the table below */ |
13 | static struct ctl_table color_table[] = | 22 | static struct ctl_table color_table[] = |
14 | { | 23 | { |
15 | { | 24 | { |
25 | .procname = "servers", | ||
26 | .mode = 0555, | ||
27 | }, | ||
28 | { | ||
16 | /* you MUST update NR_PAGES_INDEX if you move this entry */ | 29 | /* you MUST update NR_PAGES_INDEX if you move this entry */ |
17 | .procname = "nr_pages", | 30 | .procname = "nr_pages", |
18 | .mode = 0444, | 31 | .mode = 0444, |
@@ -41,6 +54,7 @@ static struct ctl_table litmus_table[] = | |||
41 | }, | 54 | }, |
42 | { } | 55 | { } |
43 | }; | 56 | }; |
57 | |||
44 | static struct ctl_table litmus_dir_table[] = { | 58 | static struct ctl_table litmus_dir_table[] = { |
45 | { | 59 | { |
46 | .procname = "litmus", | 60 | .procname = "litmus", |
@@ -50,6 +64,26 @@ static struct ctl_table litmus_dir_table[] = { | |||
50 | { } | 64 | { } |
51 | }; | 65 | }; |
52 | 66 | ||
67 | int color_server_params(int cpu, unsigned long *wcet, unsigned long *period) | ||
68 | { | ||
69 | if (cpu >= num_online_cpus()) { | ||
70 | printk(KERN_WARNING "Cannot access illegal CPU: %d\n", cpu); | ||
71 | return -EFAULT; | ||
72 | } | ||
73 | |||
74 | if (server_wcet[cpu] == 0 || server_period[cpu] == 0) { | ||
75 | printk(KERN_WARNING "Server %d is uninitialized!\n", cpu); | ||
76 | return -EPERM; | ||
77 | } | ||
78 | |||
79 | *wcet = server_wcet[cpu]; | ||
80 | *period = server_period[cpu]; | ||
81 | |||
82 | TRACE("For %d: %lu, %lu\n", cpu, server_wcet[cpu], server_period[cpu]); | ||
83 | |||
84 | return 0; | ||
85 | } | ||
86 | |||
53 | extern unsigned long nr_colors; /* litmus/color.c */ | 87 | extern unsigned long nr_colors; /* litmus/color.c */ |
54 | 88 | ||
55 | /* must be called AFTER nr_colors is set */ | 89 | /* must be called AFTER nr_colors is set */ |
@@ -67,11 +101,101 @@ out: | |||
67 | return ret; | 101 | return ret; |
68 | } | 102 | } |
69 | 103 | ||
104 | static void __init init_server_entry(struct ctl_table *entry, | ||
105 | unsigned long *parameter, | ||
106 | char *name) | ||
107 | { | ||
108 | entry->procname = name; | ||
109 | entry->mode = 0666; | ||
110 | entry->proc_handler = proc_doulongvec_minmax; | ||
111 | entry->data = parameter; | ||
112 | entry->maxlen = sizeof(unsigned long); | ||
113 | } | ||
114 | |||
115 | static int __init init_cpu_entry(struct ctl_table *cpu_table, int cpu) | ||
116 | { | ||
117 | char *name; | ||
118 | size_t size; | ||
119 | struct ctl_table *server_table, *entry; | ||
120 | |||
121 | server_wcet[cpu] = 0; | ||
122 | server_period[cpu] = 0; | ||
123 | |||
124 | printk(KERN_INFO "Creating cpu %d\n", cpu); | ||
125 | |||
126 | size = sizeof(ctl_table) * 3; | ||
127 | server_table = kmalloc(size, GFP_ATOMIC); | ||
128 | if (!server_table) { | ||
129 | printk(KERN_WARNING "Could not allocate " | ||
130 | "color server proc for CPU %d.\n", cpu); | ||
131 | return -ENOMEM; | ||
132 | } | ||
133 | memset(server_table, 0, size); | ||
134 | |||
135 | /* Server WCET */ | ||
136 | name = kmalloc(SWCET_LEN, GFP_ATOMIC); | ||
137 | if (!name) { | ||
138 | return -ENOMEM; | ||
139 | } | ||
140 | strcpy(name, SWCET_FILE); | ||
141 | entry = &server_table[0]; | ||
142 | init_server_entry(entry, &server_wcet[cpu], name); | ||
143 | |||
144 | |||
145 | /* Server period */ | ||
146 | name = kmalloc(SPERIOD_LEN, GFP_ATOMIC); | ||
147 | if (!name) { | ||
148 | return -ENOMEM; | ||
149 | } | ||
150 | strcpy(name, SPERIOD_FILE); | ||
151 | entry = &server_table[1]; | ||
152 | init_server_entry(entry, &server_period[cpu], name); | ||
153 | |||
154 | name = kmalloc(3, GFP_ATOMIC); | ||
155 | if (!name) { | ||
156 | return -ENOMEM; | ||
157 | } | ||
158 | snprintf(name, 2, "%d", cpu); | ||
159 | cpu_table->procname = name; | ||
160 | cpu_table->mode = 0555; | ||
161 | cpu_table->child = server_table; | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | static int __init init_server_entries(struct ctl_table *cpu_tables) | ||
167 | { | ||
168 | size_t size; | ||
169 | int ret, cpu; | ||
170 | struct ctl_table *cpu_table; | ||
171 | |||
172 | size = sizeof(unsigned long) * num_online_cpus(); | ||
173 | server_wcet = kmalloc(size, GFP_ATOMIC); | ||
174 | server_period = kmalloc(size, GFP_ATOMIC); | ||
175 | if (!server_wcet || !server_period) { | ||
176 | printk(KERN_WARNING "Could not allocate server parameters.\n"); | ||
177 | return -ENOMEM; | ||
178 | } | ||
179 | |||
180 | for_each_online_cpu(cpu) { | ||
181 | cpu_table = &cpu_tables[cpu]; | ||
182 | ret = init_cpu_entry(cpu_table, cpu); | ||
183 | if (ret) { | ||
184 | return ret; | ||
185 | } | ||
186 | } | ||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | |||
70 | static struct ctl_table_header *litmus_sysctls; | 191 | static struct ctl_table_header *litmus_sysctls; |
71 | 192 | ||
72 | static int __init litmus_sysctl_init(void) | 193 | static int __init litmus_sysctl_init(void) |
73 | { | 194 | { |
74 | int ret = 0; | 195 | int ret = 0; |
196 | size_t size; | ||
197 | struct ctl_table *cpu_tables; | ||
198 | |||
75 | printk(KERN_INFO "Registering LITMUS^RT proc sysctl.\n"); | 199 | printk(KERN_INFO "Registering LITMUS^RT proc sysctl.\n"); |
76 | litmus_sysctls = register_sysctl_table(litmus_dir_table); | 200 | litmus_sysctls = register_sysctl_table(litmus_dir_table); |
77 | if (!litmus_sysctls) { | 201 | if (!litmus_sysctls) { |
@@ -80,6 +204,25 @@ static int __init litmus_sysctl_init(void) | |||
80 | goto out; | 204 | goto out; |
81 | } | 205 | } |
82 | ret = init_sysctl_nr_colors(); | 206 | ret = init_sysctl_nr_colors(); |
207 | if (ret) | ||
208 | goto out; | ||
209 | |||
210 | |||
211 | size = sizeof(ctl_table) * (num_online_cpus() + 2); | ||
212 | cpu_tables = kmalloc(size, GFP_ATOMIC); | ||
213 | if (!cpu_tables) { | ||
214 | printk(KERN_WARNING "Could not allocate color CPU proc.\n"); | ||
215 | ret = -ENOMEM; | ||
216 | goto out; | ||
217 | } | ||
218 | memset(cpu_tables, 0, size); | ||
219 | |||
220 | ret = init_server_entries(cpu_tables); | ||
221 | if (ret) | ||
222 | goto out; | ||
223 | |||
224 | color_table[0].child = cpu_tables; | ||
225 | |||
83 | out: | 226 | out: |
84 | return ret; | 227 | return ret; |
85 | } | 228 | } |
diff --git a/litmus/dgl.c b/litmus/dgl.c new file mode 100644 index 000000000000..e09d57cc2672 --- /dev/null +++ b/litmus/dgl.c | |||
@@ -0,0 +1,248 @@ | |||
1 | #include <linux/sched.h> | ||
2 | #include <litmus/litmus.h> | ||
3 | #include <litmus/dgl.h> | ||
4 | #include <litmus/sched_trace.h> | ||
5 | |||
6 | /* Word, bit -> resource id */ | ||
7 | #define ri(w, b) (w * MASK_SIZE + b) | ||
8 | |||
9 | /* For loop, where @i iterates over each set bit in @bit_arr */ | ||
10 | #define for_each_resource(bit_arr, w, b, i) \ | ||
11 | for(w = 0; w < MASK_WORDS; ++w) \ | ||
12 | for(b = find_first_bit(&bit_arr[w],MASK_SIZE), i = ri(w, b); \ | ||
13 | b < MASK_SIZE; \ | ||
14 | b = find_next_bit(&bit_arr[w],MASK_SIZE,b+1), i = ri(w, b)) | ||
15 | |||
16 | /* Return resource id in dgl @d for resource @r */ | ||
17 | #define resource_id(d, r) ((((void*)r) - (void*)(&(d)->resources))/ sizeof(*r)) | ||
18 | |||
19 | /* Return request group of req @r for resource @i */ | ||
20 | #define req_group(r, i) (container_of(((void*)r) - sizeof(*r)*(i), \ | ||
21 | struct dgl_group_req, requests)) | ||
22 | |||
23 | /* Resource id -> word, bit */ | ||
24 | static inline void mask_idx(int resource, int *word, int *bit) | ||
25 | { | ||
26 | *word = resource / MASK_SIZE; | ||
27 | *bit = resource % MASK_SIZE; | ||
28 | } | ||
29 | |||
30 | |||
31 | static void print_waiting(struct dgl *dgl, struct dgl_resource *resource) | ||
32 | { | ||
33 | struct dgl_req *pos; | ||
34 | struct dgl_group_req *greq; | ||
35 | int rid = resource_id(dgl, resource); | ||
36 | unsigned long long last = 0; | ||
37 | |||
38 | TRACE("List for rid %d\n", resource_id(dgl, resource)); | ||
39 | list_for_each_entry(pos, &resource->waiting, list) { | ||
40 | greq = req_group(pos, rid); | ||
41 | TRACE(" 0x%p with timestamp %llu\n", greq, greq->ts); | ||
42 | BUG_ON(greq->ts < last); | ||
43 | last = greq->ts; | ||
44 | } | ||
45 | } | ||
46 | |||
47 | void dgl_init(struct dgl *dgl) | ||
48 | { | ||
49 | int i; | ||
50 | struct dgl_resource *resource; | ||
51 | |||
52 | for (i = 0; i < NR_CPUS; ++i) | ||
53 | dgl->acquired[i] = NULL; | ||
54 | |||
55 | for (i = 0; i < NUM_RESOURCES; ++i) { | ||
56 | resource = &dgl->resources[i]; | ||
57 | |||
58 | INIT_LIST_HEAD(&resource->waiting); | ||
59 | resource->free_replicas = NUM_REPLICAS; | ||
60 | } | ||
61 | |||
62 | dgl->requests = 0; | ||
63 | dgl->running = 0; | ||
64 | dgl->ts = 0; | ||
65 | } | ||
66 | |||
67 | void dgl_group_req_init(struct dgl_group_req *greq) | ||
68 | { | ||
69 | int i; | ||
70 | greq->cpu = NO_CPU; | ||
71 | for (i = 0; i < MASK_WORDS; ++i) { | ||
72 | greq->requested[i] = 0; | ||
73 | greq->waiting[i] = 0; | ||
74 | } | ||
75 | } | ||
76 | |||
77 | /** | ||
78 | * set_req - create request for @replicas of @resource. | ||
79 | */ | ||
80 | void set_req(struct dgl_group_req *greq, int resource, int replicas) | ||
81 | { | ||
82 | int word, bit; | ||
83 | struct dgl_req *req; | ||
84 | |||
85 | BUG_ON(replicas > NUM_REPLICAS); | ||
86 | |||
87 | mask_idx(resource, &word, &bit); | ||
88 | __set_bit(bit, &greq->requested[word]); | ||
89 | |||
90 | req = &greq->requests[resource]; | ||
91 | INIT_LIST_HEAD(&req->list); | ||
92 | req->replicas = replicas; | ||
93 | } | ||
94 | |||
95 | /* | ||
96 | * Attempt to fulfill request @req for @resource. | ||
97 | * Return 1 if successful. If the matching group request has acquired all of | ||
98 | * its needed resources, this will then set that req as dgl->acquired[cpu]. | ||
99 | */ | ||
100 | static unsigned long try_acquire(struct dgl *dgl, struct dgl_resource *resource, | ||
101 | struct dgl_req *req) | ||
102 | { | ||
103 | int word, bit, rid, head, empty, room; | ||
104 | unsigned long waiting; | ||
105 | struct dgl_group_req *greq; | ||
106 | |||
107 | rid = resource_id(dgl, resource); | ||
108 | greq = req_group(req, rid); | ||
109 | |||
110 | head = resource->waiting.next == &req->list; | ||
111 | empty = list_empty(&resource->waiting); | ||
112 | room = resource->free_replicas >= req->replicas; | ||
113 | |||
114 | if (! (room && (head || empty)) ) { | ||
115 | TRACE("0x%p cannot acquire %d replicas, %d free\n", | ||
116 | greq, req->replicas, resource->free_replicas, | ||
117 | room, head, empty); | ||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | resource->free_replicas -= req->replicas; | ||
122 | BUG_ON(resource->free_replicas > NUM_REPLICAS); | ||
123 | |||
124 | TRACE("0x%p acquired %d replicas of rid %d\n", | ||
125 | greq, req->replicas, rid); | ||
126 | |||
127 | mask_idx(rid, &word, &bit); | ||
128 | clear_bit(bit, &greq->waiting[word]); | ||
129 | |||
130 | waiting = 0; | ||
131 | for (word = 0; word < MASK_WORDS; word++) { | ||
132 | waiting |= greq->waiting[word]; | ||
133 | if (waiting) | ||
134 | break; | ||
135 | } | ||
136 | |||
137 | if (!waiting) { | ||
138 | TRACE("0x%p acquired all resources\n", greq); | ||
139 | BUG_ON(dgl->acquired[greq->cpu]); | ||
140 | dgl->acquired[greq->cpu] = greq; | ||
141 | litmus_reschedule(greq->cpu); | ||
142 | dgl->running++; | ||
143 | } | ||
144 | |||
145 | return 1; | ||
146 | } | ||
147 | |||
148 | /** | ||
149 | * add_group_req - initiate group request. | ||
150 | */ | ||
151 | void add_group_req(struct dgl *dgl, struct dgl_group_req *greq, int cpu) | ||
152 | { | ||
153 | int b, w, i, succ, all_succ = 1; | ||
154 | struct dgl_req *req; | ||
155 | struct dgl_resource *resource; | ||
156 | |||
157 | greq->cpu = cpu; | ||
158 | greq->ts = dgl->ts++; | ||
159 | |||
160 | TRACE("0x%p group request added for CPU %d\n", greq, cpu); | ||
161 | BUG_ON(dgl->acquired[cpu] == greq); | ||
162 | |||
163 | ++dgl->requests; | ||
164 | |||
165 | for_each_resource(greq->requested, w, b, i) { | ||
166 | __set_bit(b, &greq->waiting[w]); | ||
167 | } | ||
168 | |||
169 | for_each_resource(greq->requested, w, b, i) { | ||
170 | req = &greq->requests[i]; | ||
171 | resource = &dgl->resources[i]; | ||
172 | |||
173 | succ = try_acquire(dgl, resource, req); | ||
174 | all_succ &= succ; | ||
175 | |||
176 | if (!succ) { | ||
177 | TRACE("0x%p waiting on rid %d\n", greq, i); | ||
178 | list_add_tail(&req->list, &resource->waiting); | ||
179 | } | ||
180 | } | ||
181 | |||
182 | /* Grant empty requests */ | ||
183 | if (all_succ && !dgl->acquired[cpu]) { | ||
184 | TRACE("0x%p empty group request acquired cpu %d\n", greq, cpu); | ||
185 | dgl->acquired[cpu] = greq; | ||
186 | ++dgl->running; | ||
187 | } | ||
188 | |||
189 | BUG_ON(dgl->requests && !dgl->running); | ||
190 | } | ||
191 | |||
192 | /** | ||
193 | * remove_group_req - abandon group request. | ||
194 | * | ||
195 | * This will also progress the waiting queues of resources acquired by @greq. | ||
196 | */ | ||
197 | void remove_group_req(struct dgl *dgl, struct dgl_group_req *greq) | ||
198 | { | ||
199 | int b, w, i; | ||
200 | struct dgl_req *req, *next; | ||
201 | struct dgl_resource *resource; | ||
202 | |||
203 | TRACE("0x%p removing group request for CPU %d\n", greq, greq->cpu); | ||
204 | |||
205 | --dgl->requests; | ||
206 | |||
207 | if (dgl->acquired[greq->cpu] == greq) { | ||
208 | TRACE("0x%p no longer acquired on CPU %d\n", greq, greq->cpu); | ||
209 | dgl->acquired[greq->cpu] = NULL; | ||
210 | --dgl->running; | ||
211 | } | ||
212 | |||
213 | for_each_resource(greq->requested, w, b, i) { | ||
214 | req = &greq->requests[i]; | ||
215 | resource = &dgl->resources[i]; | ||
216 | |||
217 | if (!list_empty(&req->list)) { | ||
218 | /* Waiting on resource */ | ||
219 | clear_bit(b, &greq->waiting[w]); | ||
220 | list_del_init(&req->list); | ||
221 | TRACE("Quitting 0x%p from rid %d\n", | ||
222 | req, i); | ||
223 | } else { | ||
224 | /* Have resource */ | ||
225 | resource->free_replicas += req->replicas; | ||
226 | BUG_ON(resource->free_replicas > NUM_REPLICAS); | ||
227 | TRACE("0x%p releasing %d of %d replicas, rid %d\n", | ||
228 | greq, req->replicas, resource->free_replicas, i); | ||
229 | |||
230 | if (!list_empty(&resource->waiting)) { | ||
231 | /* Give it to the next guy */ | ||
232 | next = list_first_entry(&resource->waiting, | ||
233 | struct dgl_req, | ||
234 | list); | ||
235 | |||
236 | BUG_ON(req_group(next, i)->ts < greq->ts); | ||
237 | |||
238 | if (try_acquire(dgl, resource, next)) { | ||
239 | list_del_init(&next->list); | ||
240 | print_waiting(dgl, resource); | ||
241 | |||
242 | } | ||
243 | } | ||
244 | } | ||
245 | } | ||
246 | |||
247 | BUG_ON(dgl->requests && !dgl->running); | ||
248 | } | ||
diff --git a/litmus/fifo_common.c b/litmus/fifo_common.c new file mode 100644 index 000000000000..84ae98e42ae4 --- /dev/null +++ b/litmus/fifo_common.c | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | * kernel/edf_common.c | ||
3 | * | ||
4 | * Common functions for EDF based scheduler. | ||
5 | */ | ||
6 | |||
7 | #include <linux/percpu.h> | ||
8 | #include <linux/sched.h> | ||
9 | #include <linux/list.h> | ||
10 | |||
11 | #include <litmus/litmus.h> | ||
12 | #include <litmus/sched_plugin.h> | ||
13 | #include <litmus/sched_trace.h> | ||
14 | |||
15 | #include <litmus/fifo_common.h> | ||
16 | |||
17 | int fifo_higher_prio(struct task_struct* first, | ||
18 | struct task_struct* second) | ||
19 | { | ||
20 | /* There is no point in comparing a task to itself. */ | ||
21 | if (first && first == second) { | ||
22 | TRACE_TASK(first, | ||
23 | "WARNING: pointless fifo priority comparison.\n"); | ||
24 | BUG_ON(1); | ||
25 | return 0; | ||
26 | } | ||
27 | |||
28 | if (!first || !second) | ||
29 | return first && !second; | ||
30 | |||
31 | /* Tiebreak by PID */ | ||
32 | return (get_release(first) == get_release(second) && | ||
33 | first->pid > second->pid) || | ||
34 | (get_release(first) < get_release(second)); | ||
35 | |||
36 | |||
37 | } | ||
38 | |||
39 | int fifo_ready_order(struct bheap_node* a, struct bheap_node* b) | ||
40 | { | ||
41 | return fifo_higher_prio(bheap2task(a), bheap2task(b)); | ||
42 | } | ||
43 | |||
44 | void fifo_domain_init(rt_domain_t* rt, check_resched_needed_t resched, | ||
45 | release_jobs_t release) | ||
46 | { | ||
47 | rt_domain_init(rt, fifo_ready_order, resched, release); | ||
48 | } | ||
49 | |||
50 | int fifo_preemption_needed(rt_domain_t* rt, struct task_struct *t) | ||
51 | { | ||
52 | if (!__jobs_pending(rt)) | ||
53 | return 0; | ||
54 | if (!t) | ||
55 | return 1; | ||
56 | |||
57 | return !is_realtime(t) || fifo_higher_prio(__next_ready(rt), t); | ||
58 | } | ||
diff --git a/litmus/ftdev.c b/litmus/ftdev.c index 06fcf4cf77dc..7ff7f25b56aa 100644 --- a/litmus/ftdev.c +++ b/litmus/ftdev.c | |||
@@ -231,7 +231,9 @@ static ssize_t ftdev_read(struct file *filp, | |||
231 | * lost if the task is interrupted (e.g., killed). | 231 | * lost if the task is interrupted (e.g., killed). |
232 | */ | 232 | */ |
233 | set_current_state(TASK_INTERRUPTIBLE); | 233 | set_current_state(TASK_INTERRUPTIBLE); |
234 | |||
234 | schedule_timeout(50); | 235 | schedule_timeout(50); |
236 | |||
235 | if (signal_pending(current)) { | 237 | if (signal_pending(current)) { |
236 | if (err == 0) | 238 | if (err == 0) |
237 | /* nothing read yet, signal problem */ | 239 | /* nothing read yet, signal problem */ |
diff --git a/litmus/locking.c b/litmus/locking.c index 0c1aa6aa40b7..4881ca119acf 100644 --- a/litmus/locking.c +++ b/litmus/locking.c | |||
@@ -1,3 +1,5 @@ | |||
1 | #include <linux/sched.h> | ||
2 | #include <litmus/litmus.h> | ||
1 | #include <litmus/fdso.h> | 3 | #include <litmus/fdso.h> |
2 | 4 | ||
3 | #ifdef CONFIG_LITMUS_LOCKING | 5 | #ifdef CONFIG_LITMUS_LOCKING |
@@ -28,14 +30,18 @@ static inline struct litmus_lock* get_lock(struct od_table_entry* entry) | |||
28 | return (struct litmus_lock*) entry->obj->obj; | 30 | return (struct litmus_lock*) entry->obj->obj; |
29 | } | 31 | } |
30 | 32 | ||
33 | atomic_t lock_id = ATOMIC_INIT(0); | ||
34 | |||
31 | static int create_generic_lock(void** obj_ref, obj_type_t type, void* __user arg) | 35 | static int create_generic_lock(void** obj_ref, obj_type_t type, void* __user arg) |
32 | { | 36 | { |
33 | struct litmus_lock* lock; | 37 | struct litmus_lock* lock; |
34 | int err; | 38 | int err; |
35 | 39 | ||
36 | err = litmus->allocate_lock(&lock, type, arg); | 40 | err = litmus->allocate_lock(&lock, type, arg); |
37 | if (err == 0) | 41 | if (err == 0) { |
42 | lock->id = atomic_add_return(1, &lock_id); | ||
38 | *obj_ref = lock; | 43 | *obj_ref = lock; |
44 | } | ||
39 | return err; | 45 | return err; |
40 | } | 46 | } |
41 | 47 | ||
diff --git a/litmus/rt_server.c b/litmus/rt_server.c new file mode 100644 index 000000000000..818588a3d317 --- /dev/null +++ b/litmus/rt_server.c | |||
@@ -0,0 +1,34 @@ | |||
1 | #include <litmus/rt_server.h> | ||
2 | |||
3 | |||
4 | static struct task_struct* default_server_take(struct rt_server *srv) | ||
5 | { | ||
6 | return __take_ready(srv->domain); | ||
7 | } | ||
8 | |||
9 | static void default_server_update(struct rt_server *srv) | ||
10 | { | ||
11 | } | ||
12 | |||
13 | void init_rt_server(struct rt_server *server, | ||
14 | int sid, int cpu, rt_domain_t *domain, | ||
15 | need_preempt_t need_preempt, | ||
16 | server_requeue_t requeue, | ||
17 | server_update_t update, | ||
18 | server_take_t take) | ||
19 | { | ||
20 | if (!need_preempt || !requeue) | ||
21 | BUG_ON(1); | ||
22 | |||
23 | server->need_preempt = need_preempt; | ||
24 | server->requeue = requeue; | ||
25 | |||
26 | server->update = (update) ? update : default_server_update; | ||
27 | server->take = (take) ? take : default_server_take; | ||
28 | |||
29 | server->sid = sid; | ||
30 | server->cpu = cpu; | ||
31 | server->linked = NULL; | ||
32 | server->domain = domain; | ||
33 | server->running = 0; | ||
34 | } | ||
diff --git a/litmus/sched_color.c b/litmus/sched_color.c new file mode 100644 index 000000000000..98a46bb1b06f --- /dev/null +++ b/litmus/sched_color.c | |||
@@ -0,0 +1,811 @@ | |||
1 | #include <linux/percpu.h> | ||
2 | #include <linux/sched.h> | ||
3 | #include <linux/list.h> | ||
4 | #include <linux/spinlock.h> | ||
5 | #include <linux/module.h> | ||
6 | #include <linux/slab.h> | ||
7 | |||
8 | #include <litmus/litmus.h> | ||
9 | #include <litmus/jobs.h> | ||
10 | #include <litmus/preempt.h> | ||
11 | #include <litmus/sched_plugin.h> | ||
12 | #include <litmus/edf_common.h> | ||
13 | #include <litmus/sched_trace.h> | ||
14 | #include <litmus/color.h> | ||
15 | #include <litmus/fifo_common.h> | ||
16 | #include <litmus/budget.h> | ||
17 | #include <litmus/rt_server.h> | ||
18 | #include <litmus/dgl.h> | ||
19 | |||
20 | /** | ||
21 | * @rt_server Common server functionality. | ||
22 | * @task Task used to schedule server. | ||
23 | * @timer Budget enforcement for @task | ||
24 | * @start_time If set, time at which server began running. | ||
25 | */ | ||
26 | struct fifo_server { | ||
27 | struct rt_server server; | ||
28 | struct task_struct* task; | ||
29 | struct enforcement_timer timer; | ||
30 | lt_t start_time; | ||
31 | }; | ||
32 | |||
33 | /** | ||
34 | * @server Common server functionality. | ||
35 | * @edf_domain PEDF domain. | ||
36 | * @scheduled Task physically running on CPU. | ||
37 | * @fifo_server Server partitioned to this CPU. | ||
38 | */ | ||
39 | struct cpu_entry { | ||
40 | struct rt_server server; | ||
41 | rt_domain_t edf_domain; | ||
42 | struct task_struct* scheduled; | ||
43 | struct fifo_server fifo_server; | ||
44 | }; | ||
45 | |||
46 | DEFINE_PER_CPU(struct cpu_entry, color_cpus); | ||
47 | |||
48 | static rt_domain_t fifo_domain; | ||
49 | static raw_spinlock_t fifo_lock; | ||
50 | |||
51 | static struct dgl group_lock; | ||
52 | static raw_spinlock_t dgl_lock; | ||
53 | |||
54 | #define local_entry (&__get_cpu_var(color_cpus)) | ||
55 | #define remote_entry(cpu) (&per_cpu(color_cpus, cpu)) | ||
56 | #define task_entry(task) remote_entry(get_partition(task)) | ||
57 | #define task_fserver(task) (&task_entry(task)->fifo_server.server) | ||
58 | #define entry_lock(entry) (&entry->edf_domain.ready_lock) | ||
59 | |||
60 | #define has_resources(t, c) (tsk_rt(t)->req == group_lock.acquired[c]) | ||
61 | #define task_dom(entry, task) (is_be(task) ? &fifo_domain : &entry->edf_domain) | ||
62 | #define task_lock(entry, task) (is_be(task) ? &fifo_lock : entry_lock(entry)) | ||
63 | |||
64 | /* | ||
65 | * Requeue onto domain's release or ready queue based on task state. | ||
66 | */ | ||
67 | static void requeue(rt_domain_t *dom, struct task_struct* t) | ||
68 | { | ||
69 | if (is_server(t) && !tsk_rt(t)->present) | ||
70 | /* Remove stopped server from the system */ | ||
71 | return; | ||
72 | |||
73 | TRACE_TASK(t, "Requeueing\n"); | ||
74 | if (is_queued(t)) { | ||
75 | TRACE_TASK(t, "Already queued!\n"); | ||
76 | return; | ||
77 | } | ||
78 | |||
79 | set_rt_flags(t, RT_F_RUNNING); | ||
80 | if (is_released(t, litmus_clock())) | ||
81 | __add_ready(dom, t); | ||
82 | else | ||
83 | add_release(dom, t); | ||
84 | } | ||
85 | |||
86 | /* | ||
87 | * Relinquish resources held by @t (or its children). | ||
88 | */ | ||
89 | static void release_resources(struct task_struct *t) | ||
90 | { | ||
91 | struct task_struct *sched; | ||
92 | |||
93 | TRACE_TASK(t, "Releasing resources\n"); | ||
94 | |||
95 | if (is_server(t)) { | ||
96 | sched = task_fserver(t)->linked; | ||
97 | if (sched) | ||
98 | release_resources(sched); | ||
99 | } else if (is_kernel_np(t)) | ||
100 | remove_group_req(&group_lock, tsk_rt(t)->req); | ||
101 | tsk_rt(t)->kernel_np = 0; | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * Put in requests for resources needed by @t. If @t is a server, this will | ||
106 | * set @t's np flag to reflect resources held by @t's children. | ||
107 | */ | ||
108 | static void acquire_resources(struct task_struct *t) | ||
109 | { | ||
110 | int cpu; | ||
111 | struct rt_server *server; | ||
112 | struct task_struct *sched; | ||
113 | |||
114 | /* Can't acquire resources if t is not running */ | ||
115 | BUG_ON(!get_task_server(t)); | ||
116 | |||
117 | if (is_kernel_np(t)) { | ||
118 | TRACE_TASK(t, "Already contending for resources\n"); | ||
119 | return; | ||
120 | } | ||
121 | cpu = get_task_server(t)->cpu; | ||
122 | |||
123 | if (is_server(t)) { | ||
124 | server = task_fserver(t); | ||
125 | sched = server->linked; | ||
126 | |||
127 | /* Happens when server is booted off on completion or | ||
128 | * has just completed executing a task. | ||
129 | */ | ||
130 | if (sched && !is_kernel_np(sched)) | ||
131 | acquire_resources(sched); | ||
132 | |||
133 | /* Become np if there is a running task */ | ||
134 | if (sched && has_resources(sched, cpu)) { | ||
135 | TRACE_TASK(t, "Running task with resource\n"); | ||
136 | tsk_rt(t)->kernel_np = 1; | ||
137 | } else { | ||
138 | TRACE_TASK(t, "Running no resources\n"); | ||
139 | tsk_rt(t)->kernel_np = 0; | ||
140 | } | ||
141 | } else { | ||
142 | TRACE_TASK(t, "Acquiring resources\n"); | ||
143 | if (!has_resources(t, cpu)) | ||
144 | add_group_req(&group_lock, tsk_rt(t)->req, cpu); | ||
145 | tsk_rt(t)->kernel_np = 1; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | /* | ||
150 | * Stop logically running the currently linked task. | ||
151 | */ | ||
152 | static void unlink(struct rt_server *server) | ||
153 | { | ||
154 | BUG_ON(!server->linked); | ||
155 | |||
156 | if (is_server(server->linked)) | ||
157 | task_fserver(server->linked)->running = 0; | ||
158 | |||
159 | |||
160 | sched_trace_server_switch_away(server->sid, 0, | ||
161 | server->linked->pid, | ||
162 | get_rt_job(server->linked)); | ||
163 | TRACE_TASK(server->linked, "No longer run by server %d\n", server->sid); | ||
164 | |||
165 | raw_spin_lock(&dgl_lock); | ||
166 | release_resources(server->linked); | ||
167 | raw_spin_unlock(&dgl_lock); | ||
168 | |||
169 | get_task_server(server->linked) = NULL; | ||
170 | server->linked = NULL; | ||
171 | } | ||
172 | |||
173 | static struct task_struct* schedule_server(struct rt_server *server); | ||
174 | |||
175 | /* | ||
176 | * Logically run @task. | ||
177 | */ | ||
178 | static void link(struct rt_server *server, struct task_struct *task) | ||
179 | { | ||
180 | struct rt_server *tserv; | ||
181 | |||
182 | BUG_ON(server->linked); | ||
183 | BUG_ON(!server->running); | ||
184 | BUG_ON(is_kernel_np(task)); | ||
185 | |||
186 | TRACE_TASK(task, "Run by server %d\n", server->sid); | ||
187 | |||
188 | if (is_server(task)) { | ||
189 | tserv = task_fserver(task); | ||
190 | tserv->running = 1; | ||
191 | schedule_server(tserv); | ||
192 | } | ||
193 | |||
194 | server->linked = task; | ||
195 | get_task_server(task) = server; | ||
196 | |||
197 | sched_trace_server_switch_to(server->sid, 0, | ||
198 | task->pid, get_rt_job(task)); | ||
199 | } | ||
200 | |||
201 | /* | ||
202 | * Complete job for task linked to @server. | ||
203 | */ | ||
204 | static void job_completion(struct rt_server *server) | ||
205 | { | ||
206 | struct task_struct *t = server->linked; | ||
207 | |||
208 | TRACE_TASK(t, "Job completed\n"); | ||
209 | if (is_server(t)) | ||
210 | sched_trace_server_completion(t->pid, get_rt_job(t)); | ||
211 | else | ||
212 | sched_trace_task_completion(t, 0); | ||
213 | |||
214 | unlink(server); | ||
215 | set_rt_flags(t, RT_F_SLEEP); | ||
216 | prepare_for_next_period(t); | ||
217 | |||
218 | if (is_server(t)) | ||
219 | sched_trace_server_release(t->pid, get_rt_job(t), | ||
220 | get_release(t), get_deadline(t)); | ||
221 | else | ||
222 | sched_trace_task_release(t); | ||
223 | |||
224 | if (is_running(t)) | ||
225 | server->requeue(server, t); | ||
226 | } | ||
227 | |||
228 | /* | ||
229 | * Update @server state to reflect task's state. | ||
230 | */ | ||
231 | static void update_task(struct rt_server *server) | ||
232 | { | ||
233 | int oot, sleep, block, np; | ||
234 | struct task_struct *t = server->linked; | ||
235 | |||
236 | block = !is_running(t); | ||
237 | oot = budget_enforced(t) && budget_exhausted(t); | ||
238 | np = is_kernel_np(t); | ||
239 | sleep = get_rt_flags(t) == RT_F_SLEEP; | ||
240 | |||
241 | TRACE_TASK(t, "Updating task, block: %d, oot: %d, np: %d, sleep: %d\n", | ||
242 | block, oot, np, sleep); | ||
243 | |||
244 | if (block) | ||
245 | unlink(server); | ||
246 | else if (oot || sleep) | ||
247 | job_completion(server); | ||
248 | } | ||
249 | |||
250 | /* | ||
251 | * Link next task for @server. | ||
252 | */ | ||
253 | static struct task_struct* schedule_server(struct rt_server *server) | ||
254 | { | ||
255 | struct task_struct *next; | ||
256 | struct rt_server *lserver; | ||
257 | |||
258 | TRACE("Scheduling server %d\n", server->sid); | ||
259 | |||
260 | if (server->linked) { | ||
261 | if (is_server(server->linked)) { | ||
262 | lserver = task_fserver(server->linked); | ||
263 | lserver->update(lserver); | ||
264 | } | ||
265 | update_task(server); | ||
266 | } | ||
267 | |||
268 | next = server->linked; | ||
269 | if ((!next || !is_np(next)) && | ||
270 | server->need_preempt(server->domain, next)) { | ||
271 | if (next) { | ||
272 | TRACE_TASK(next, "Preempted\n"); | ||
273 | unlink(server); | ||
274 | server->requeue(server, next); | ||
275 | } | ||
276 | next = __take_ready(server->domain); | ||
277 | link(server, next); | ||
278 | } | ||
279 | |||
280 | return next; | ||
281 | } | ||
282 | |||
283 | /* | ||
284 | * Dumb requeue for PEDF (CPU) servers. | ||
285 | */ | ||
286 | static void edf_requeue(struct rt_server *server, struct task_struct *t) | ||
287 | { | ||
288 | BUG_ON(is_be(t)); | ||
289 | requeue(server->domain, t); | ||
290 | } | ||
291 | |||
292 | /* | ||
293 | * Locking requeue for FIFO servers. | ||
294 | */ | ||
295 | static void fifo_requeue(struct rt_server *server, struct task_struct *t) | ||
296 | { | ||
297 | BUG_ON(!is_be(t)); | ||
298 | raw_spin_lock(&fifo_lock); | ||
299 | requeue(server->domain, t); | ||
300 | raw_spin_unlock(&fifo_lock); | ||
301 | } | ||
302 | |||
303 | |||
304 | /* | ||
305 | * Locking take for FIFO servers. | ||
306 | */ | ||
307 | static struct task_struct* fifo_take(struct rt_server *server) | ||
308 | { | ||
309 | struct task_struct *ret; | ||
310 | |||
311 | raw_spin_lock(&fifo_lock); | ||
312 | ret = __take_ready(server->domain); | ||
313 | raw_spin_unlock(&fifo_lock); | ||
314 | |||
315 | return ret; | ||
316 | } | ||
317 | |||
318 | /* | ||
319 | * Update server state, including picking next running task and incrementing | ||
320 | * server execution time. | ||
321 | */ | ||
322 | static void fifo_update(struct rt_server *server) | ||
323 | { | ||
324 | lt_t delta; | ||
325 | struct fifo_server *fserver; | ||
326 | |||
327 | fserver = container_of(server, struct fifo_server, server); | ||
328 | TRACE_TASK(fserver->task, "Updating FIFO server\n"); | ||
329 | |||
330 | if (!server->linked || has_resources(server->linked, server->cpu)) { | ||
331 | /* Running here means linked to a parent server */ | ||
332 | BUG_ON(!server->running); | ||
333 | |||
334 | /* Stop executing */ | ||
335 | if (fserver->start_time) { | ||
336 | delta = litmus_clock() - fserver->start_time; | ||
337 | tsk_rt(fserver->task)->job_params.exec_time += delta; | ||
338 | fserver->start_time = 0; | ||
339 | cancel_enforcement_timer(&fserver->timer); | ||
340 | } else { | ||
341 | /* Server is linked, but not executing */ | ||
342 | BUG_ON(fserver->timer.armed); | ||
343 | } | ||
344 | |||
345 | /* Calculate next task */ | ||
346 | schedule_server(&fserver->server); | ||
347 | |||
348 | /* Reserve needed resources */ | ||
349 | raw_spin_lock(&dgl_lock); | ||
350 | acquire_resources(fserver->task); | ||
351 | raw_spin_unlock(&dgl_lock); | ||
352 | } | ||
353 | } | ||
354 | |||
355 | /* | ||
356 | * Triggers preemption on edf-scheduled "linked" field only. | ||
357 | */ | ||
358 | static void color_edf_release(rt_domain_t *edf, struct bheap *tasks) | ||
359 | { | ||
360 | unsigned long flags; | ||
361 | struct cpu_entry *entry; | ||
362 | |||
363 | TRACE_TASK(bheap2task(bheap_peek(edf->order, tasks)), | ||
364 | "Released set of EDF tasks\n"); | ||
365 | |||
366 | entry = container_of(edf, struct cpu_entry, edf_domain); | ||
367 | raw_spin_lock_irqsave(entry_lock(entry), flags); | ||
368 | |||
369 | __merge_ready(edf, tasks); | ||
370 | |||
371 | if (edf_preemption_needed(edf, entry->server.linked) && | ||
372 | (!entry->server.linked || !is_kernel_np(entry->server.linked))) { | ||
373 | litmus_reschedule(entry->server.cpu); | ||
374 | } | ||
375 | |||
376 | raw_spin_unlock_irqrestore(entry_lock(entry), flags); | ||
377 | } | ||
378 | |||
379 | /* | ||
380 | * Triggers preemption on first FIFO server which is running NULL. | ||
381 | */ | ||
382 | static void check_for_fifo_preempt(void) | ||
383 | { | ||
384 | int ret = 0, cpu; | ||
385 | struct cpu_entry *entry; | ||
386 | struct rt_server *cpu_server, *fifo_server; | ||
387 | |||
388 | TRACE("Checking for FIFO preempt\n"); | ||
389 | |||
390 | for_each_online_cpu(cpu) { | ||
391 | entry = remote_entry(cpu); | ||
392 | cpu_server = &entry->server; | ||
393 | fifo_server = &entry->fifo_server.server; | ||
394 | |||
395 | raw_spin_lock(entry_lock(entry)); | ||
396 | raw_spin_lock(&fifo_lock); | ||
397 | |||
398 | if (cpu_server->linked && is_server(cpu_server->linked) && | ||
399 | !fifo_server->linked) { | ||
400 | litmus_reschedule(cpu); | ||
401 | ret = 1; | ||
402 | } | ||
403 | |||
404 | raw_spin_unlock(&fifo_lock); | ||
405 | raw_spin_unlock(entry_lock(entry)); | ||
406 | |||
407 | if (ret) | ||
408 | break; | ||
409 | } | ||
410 | } | ||
411 | |||
412 | static void color_fifo_release(rt_domain_t *dom, struct bheap *tasks) | ||
413 | { | ||
414 | unsigned long flags; | ||
415 | |||
416 | TRACE_TASK(bheap2task(bheap_peek(dom->order, tasks)), | ||
417 | "Released set of FIFO tasks\n"); | ||
418 | local_irq_save(flags); | ||
419 | |||
420 | raw_spin_lock(&fifo_lock); | ||
421 | __merge_ready(dom, tasks); | ||
422 | raw_spin_unlock(&fifo_lock); | ||
423 | |||
424 | check_for_fifo_preempt(); | ||
425 | |||
426 | local_irq_restore(flags); | ||
427 | } | ||
428 | |||
429 | #define cpu_empty(entry, run) \ | ||
430 | (!(run) || (is_server(run) && !(entry)->fifo_server.server.linked)) | ||
431 | |||
432 | static struct task_struct* color_schedule(struct task_struct *prev) | ||
433 | { | ||
434 | unsigned long flags; | ||
435 | int server_running; | ||
436 | struct cpu_entry *entry = local_entry; | ||
437 | struct task_struct *next, *plink = entry->server.linked; | ||
438 | |||
439 | TRACE("Reschedule on %d at %llu\n", entry->server.cpu, litmus_clock()); | ||
440 | BUG_ON(entry->scheduled && entry->scheduled != prev); | ||
441 | BUG_ON(entry->scheduled && !is_realtime(prev)); | ||
442 | |||
443 | raw_spin_lock_irqsave(entry_lock(entry), flags); | ||
444 | |||
445 | if (entry->scheduled && cpu_empty(entry, plink) && is_running(prev)) { | ||
446 | TRACE_TASK(prev, "Snuck in on new!\n"); | ||
447 | requeue(task_dom(entry, prev), prev); | ||
448 | } | ||
449 | |||
450 | /* Pick next top-level task */ | ||
451 | next = schedule_server(&entry->server); | ||
452 | /* Schedule hierarchically */ | ||
453 | server_running = next && is_server(next); | ||
454 | if (server_running) | ||
455 | next = task_fserver(next)->linked; | ||
456 | |||
457 | /* Selected tasks must contend for group lock */ | ||
458 | if (next) { | ||
459 | raw_spin_lock(&dgl_lock); | ||
460 | acquire_resources(next); | ||
461 | if (has_resources(next, entry->server.cpu)) { | ||
462 | TRACE_TASK(next, "Has group lock\n"); | ||
463 | sched_trace_task_resume(next, 1); | ||
464 | } else { | ||
465 | TRACE_TASK(next, "Does not have lock, 0x%p does\n", | ||
466 | group_lock.acquired[entry->server.cpu]); | ||
467 | if (next != prev) | ||
468 | sched_trace_task_block(next, 1); | ||
469 | next = NULL; | ||
470 | server_running = 0; | ||
471 | } | ||
472 | raw_spin_unlock(&dgl_lock); | ||
473 | } | ||
474 | |||
475 | /* Server is blocked if its running task is blocked. Note that if the | ||
476 | * server has no running task, the server will now execute NULL. | ||
477 | */ | ||
478 | if (server_running) { | ||
479 | TRACE_TASK(entry->server.linked, "Server running\n"); | ||
480 | arm_enforcement_timer(&entry->fifo_server.timer, | ||
481 | entry->fifo_server.task); | ||
482 | entry->fifo_server.start_time = litmus_clock(); | ||
483 | } | ||
484 | |||
485 | if (prev) | ||
486 | tsk_rt(prev)->scheduled_on = NO_CPU; | ||
487 | if (next) | ||
488 | tsk_rt(next)->scheduled_on = entry->server.cpu; | ||
489 | |||
490 | entry->scheduled = next; | ||
491 | sched_state_task_picked(); | ||
492 | |||
493 | raw_spin_unlock_irqrestore(entry_lock(entry), flags); | ||
494 | |||
495 | return entry->scheduled; | ||
496 | } | ||
497 | |||
498 | static void color_task_new(struct task_struct *t, int on_rq, int running) | ||
499 | { | ||
500 | unsigned long flags; | ||
501 | int i, replicas; | ||
502 | raw_spinlock_t *lock; | ||
503 | struct cpu_entry *entry; | ||
504 | struct dgl_group_req *req; | ||
505 | |||
506 | TRACE_TASK(t, "New colored task\n"); | ||
507 | local_irq_save(flags); | ||
508 | |||
509 | entry = (is_be(t)) ? local_entry : task_entry(t); | ||
510 | lock = task_lock(entry, t); | ||
511 | |||
512 | release_at(t, litmus_clock()); | ||
513 | |||
514 | /* Create request for dynamic group locks */ | ||
515 | req = kmalloc(sizeof(*req), GFP_ATOMIC); | ||
516 | dgl_group_req_init(req); | ||
517 | for (i = 0; i < NUM_RESOURCES; i++) { | ||
518 | replicas = get_control_page(t)->requests[i]; | ||
519 | if (replicas) | ||
520 | set_req(req, i, replicas); | ||
521 | } | ||
522 | tsk_rt(t)->req = req; | ||
523 | |||
524 | /* Join system */ | ||
525 | raw_spin_lock(lock); | ||
526 | if (running) { | ||
527 | TRACE_TASK(t, "Already scheduled on %d\n", entry->server.cpu); | ||
528 | BUG_ON(entry->scheduled); | ||
529 | entry->scheduled = t; | ||
530 | tsk_rt(t)->scheduled_on = entry->server.cpu; | ||
531 | } else | ||
532 | requeue(task_dom(entry, t), t); | ||
533 | raw_spin_unlock(lock); | ||
534 | |||
535 | /* Trigger preemptions */ | ||
536 | if (is_be(t)) | ||
537 | check_for_fifo_preempt(); | ||
538 | else | ||
539 | litmus_reschedule(entry->server.cpu); | ||
540 | |||
541 | local_irq_restore(flags); | ||
542 | } | ||
543 | |||
544 | static void color_task_wake_up(struct task_struct *task) | ||
545 | { | ||
546 | unsigned long flags; | ||
547 | struct cpu_entry* entry = task_entry(task); | ||
548 | raw_spinlock_t *lock = task_lock(entry, task); | ||
549 | lt_t now = litmus_clock(); | ||
550 | |||
551 | TRACE_TASK(task, "Wake up at %llu\n", now); | ||
552 | |||
553 | local_irq_save(flags); | ||
554 | |||
555 | /* Abuse sporadic model */ | ||
556 | if (is_tardy(task, now)) { | ||
557 | release_at(task, now); | ||
558 | sched_trace_task_release(task); | ||
559 | } | ||
560 | |||
561 | /* Re-enter system */ | ||
562 | if (entry->scheduled != task) { | ||
563 | raw_spin_lock(lock); | ||
564 | requeue(task_dom(entry, task), task); | ||
565 | raw_spin_unlock(lock); | ||
566 | } else { | ||
567 | TRACE_TASK(task, "Is already scheduled on %d!\n", | ||
568 | entry->scheduled); | ||
569 | } | ||
570 | |||
571 | /* Trigger preemptions */ | ||
572 | if (is_be(task)) | ||
573 | check_for_fifo_preempt(); | ||
574 | else | ||
575 | litmus_reschedule(entry->server.cpu); | ||
576 | |||
577 | local_irq_restore(flags); | ||
578 | } | ||
579 | |||
580 | static void color_task_block(struct task_struct *t) | ||
581 | { | ||
582 | TRACE_TASK(t, "Block at %llu, state=%d\n", litmus_clock(), t->state); | ||
583 | BUG_ON(!is_realtime(t)); | ||
584 | BUG_ON(is_queued(t)); | ||
585 | } | ||
586 | |||
587 | static void color_task_exit(struct task_struct * t) | ||
588 | { | ||
589 | unsigned long flags; | ||
590 | struct cpu_entry *entry = task_entry(t); | ||
591 | raw_spinlock_t *lock = task_lock(entry, t); | ||
592 | |||
593 | TRACE_TASK(t, "RIP, now reschedule\n"); | ||
594 | |||
595 | local_irq_save(flags); | ||
596 | |||
597 | /* Remove from scheduler consideration */ | ||
598 | if (is_queued(t)) { | ||
599 | raw_spin_lock(lock); | ||
600 | remove(task_dom(entry, t), t); | ||
601 | raw_spin_unlock(lock); | ||
602 | } | ||
603 | |||
604 | /* Stop parent server */ | ||
605 | if (get_task_server(t)) | ||
606 | unlink(get_task_server(t)); | ||
607 | |||
608 | /* Unschedule running task */ | ||
609 | if (tsk_rt(t)->scheduled_on != NO_CPU) { | ||
610 | entry = remote_entry(tsk_rt(t)->scheduled_on); | ||
611 | |||
612 | raw_spin_lock(entry_lock(entry)); | ||
613 | |||
614 | tsk_rt(t)->scheduled_on = NO_CPU; | ||
615 | entry->scheduled = NULL; | ||
616 | litmus_reschedule(entry->server.cpu); | ||
617 | |||
618 | raw_spin_unlock(entry_lock(entry)); | ||
619 | } | ||
620 | |||
621 | /* Remove dgl request from system */ | ||
622 | raw_spin_lock(&dgl_lock); | ||
623 | release_resources(t); | ||
624 | raw_spin_unlock(&dgl_lock); | ||
625 | kfree(tsk_rt(t)->req); | ||
626 | |||
627 | local_irq_restore(flags); | ||
628 | } | ||
629 | |||
630 | /* | ||
631 | * Non-be tasks must have migrated to the right CPU. | ||
632 | */ | ||
633 | static long color_admit_task(struct task_struct* t) | ||
634 | { | ||
635 | int ret = is_be(t) || task_cpu(t) == get_partition(t) ? 0 : -EINVAL; | ||
636 | if (!ret) { | ||
637 | printk(KERN_WARNING "Task failed to migrate to CPU %d\n", | ||
638 | get_partition(t)); | ||
639 | } | ||
640 | return ret; | ||
641 | } | ||
642 | |||
643 | /* | ||
644 | * Load server parameters. | ||
645 | */ | ||
646 | static long color_activate_plugin(void) | ||
647 | { | ||
648 | int cpu, ret = 0; | ||
649 | struct rt_task tp; | ||
650 | struct task_struct *server_task; | ||
651 | struct cpu_entry *entry; | ||
652 | lt_t now = litmus_clock(); | ||
653 | |||
654 | for_each_online_cpu(cpu) { | ||
655 | entry = remote_entry(cpu); | ||
656 | server_task = entry->fifo_server.task; | ||
657 | |||
658 | raw_spin_lock(entry_lock(entry)); | ||
659 | |||
660 | ret = color_server_params(cpu, &tp.exec_cost, | ||
661 | &tp.period); | ||
662 | if (ret) { | ||
663 | printk(KERN_WARNING "Uninitialized server for CPU %d\n", | ||
664 | entry->server.cpu); | ||
665 | goto loop_end; | ||
666 | } | ||
667 | |||
668 | /* Fill rt parameters */ | ||
669 | tp.phase = 0; | ||
670 | tp.cpu = cpu; | ||
671 | tp.cls = RT_CLASS_SOFT; | ||
672 | tp.budget_policy = PRECISE_ENFORCEMENT; | ||
673 | tsk_rt(server_task)->task_params = tp; | ||
674 | tsk_rt(server_task)->present = 1; | ||
675 | |||
676 | /* Make runnable */ | ||
677 | release_at(server_task, now); | ||
678 | entry->fifo_server.start_time = 0; | ||
679 | entry->scheduled = NULL; | ||
680 | |||
681 | if (!is_queued(server_task)) | ||
682 | requeue(&entry->edf_domain, server_task); | ||
683 | |||
684 | TRACE_TASK(server_task, "Created server with wcet: %llu, " | ||
685 | "period: %llu\n", tp.exec_cost, tp.period); | ||
686 | |||
687 | loop_end: | ||
688 | raw_spin_unlock(entry_lock(entry)); | ||
689 | } | ||
690 | |||
691 | return ret; | ||
692 | } | ||
693 | |||
694 | /* | ||
695 | * Mark servers as unused, making future calls to requeue fail. | ||
696 | */ | ||
697 | static long color_deactivate_plugin(void) | ||
698 | { | ||
699 | int cpu; | ||
700 | struct cpu_entry *entry; | ||
701 | |||
702 | for_each_online_cpu(cpu) { | ||
703 | entry = remote_entry(cpu); | ||
704 | if (entry->fifo_server.task) { | ||
705 | tsk_rt(entry->fifo_server.task)->present = 0; | ||
706 | } | ||
707 | } | ||
708 | return 0; | ||
709 | } | ||
710 | |||
711 | /* | ||
712 | * Dump container and server parameters for tracing. | ||
713 | */ | ||
714 | static void color_release_ts(lt_t time) | ||
715 | { | ||
716 | int cpu, fifo_cid; | ||
717 | char fifo_name[TASK_COMM_LEN], cpu_name[TASK_COMM_LEN]; | ||
718 | struct cpu_entry *entry; | ||
719 | struct task_struct *stask; | ||
720 | |||
721 | strcpy(cpu_name, "CPU"); | ||
722 | strcpy(fifo_name, "BE"); | ||
723 | |||
724 | fifo_cid = num_online_cpus(); | ||
725 | trace_litmus_container_param(fifo_cid, fifo_name); | ||
726 | |||
727 | for_each_online_cpu(cpu) { | ||
728 | entry = remote_entry(cpu); | ||
729 | trace_litmus_container_param(cpu, cpu_name); | ||
730 | trace_litmus_server_param(entry->server.sid, cpu, 0, 0); | ||
731 | stask = entry->fifo_server.task; | ||
732 | trace_litmus_server_param(stask->pid, fifo_cid, | ||
733 | get_exec_cost(stask), | ||
734 | get_rt_period(stask)); | ||
735 | } | ||
736 | } | ||
737 | |||
738 | static struct sched_plugin color_plugin __cacheline_aligned_in_smp = { | ||
739 | .plugin_name = "COLOR", | ||
740 | .task_new = color_task_new, | ||
741 | .complete_job = complete_job, | ||
742 | .task_exit = color_task_exit, | ||
743 | .schedule = color_schedule, | ||
744 | .task_wake_up = color_task_wake_up, | ||
745 | .task_block = color_task_block, | ||
746 | .admit_task = color_admit_task, | ||
747 | |||
748 | .release_ts = color_release_ts, | ||
749 | |||
750 | .activate_plugin = color_activate_plugin, | ||
751 | .deactivate_plugin = color_deactivate_plugin, | ||
752 | }; | ||
753 | |||
754 | static int __init init_color(void) | ||
755 | { | ||
756 | int cpu; | ||
757 | struct cpu_entry *entry; | ||
758 | struct task_struct *server_task; | ||
759 | struct fifo_server *fifo_server; | ||
760 | struct rt_server *cpu_server; | ||
761 | |||
762 | for_each_online_cpu(cpu) { | ||
763 | entry = remote_entry(cpu); | ||
764 | edf_domain_init(&entry->edf_domain, NULL, color_edf_release); | ||
765 | |||
766 | entry->scheduled = NULL; | ||
767 | |||
768 | /* Create FIFO server */ | ||
769 | fifo_server = &entry->fifo_server; | ||
770 | init_rt_server(&fifo_server->server, | ||
771 | cpu + num_online_cpus() + 1, | ||
772 | cpu, | ||
773 | &fifo_domain, | ||
774 | fifo_preemption_needed, | ||
775 | fifo_requeue, fifo_update, fifo_take); | ||
776 | |||
777 | |||
778 | /* Create task struct for FIFO server */ | ||
779 | server_task = kmalloc(sizeof(struct task_struct), GFP_ATOMIC); | ||
780 | memset(server_task, 0, sizeof(*server_task)); | ||
781 | server_task->policy = SCHED_LITMUS; | ||
782 | strcpy(server_task->comm, "server"); | ||
783 | server_task->pid = fifo_server->server.sid; | ||
784 | fifo_server->task = server_task; | ||
785 | |||
786 | /* Create rt_params for FIFO server */ | ||
787 | tsk_rt(server_task)->heap_node = bheap_node_alloc(GFP_ATOMIC); | ||
788 | tsk_rt(server_task)->rel_heap = release_heap_alloc(GFP_ATOMIC); | ||
789 | bheap_node_init(&tsk_rt(server_task)->heap_node, server_task); | ||
790 | tsk_rt(server_task)->is_server = 1; | ||
791 | |||
792 | /* Create CPU server */ | ||
793 | cpu_server = &entry->server; | ||
794 | init_rt_server(cpu_server, cpu + 1, cpu, | ||
795 | &entry->edf_domain, edf_preemption_needed, | ||
796 | edf_requeue, NULL, NULL); | ||
797 | cpu_server->running = 1; | ||
798 | |||
799 | init_enforcement_timer(&fifo_server->timer); | ||
800 | } | ||
801 | |||
802 | fifo_domain_init(&fifo_domain, NULL, color_fifo_release); | ||
803 | raw_spin_lock_init(&fifo_lock); | ||
804 | |||
805 | dgl_init(&group_lock); | ||
806 | raw_spin_lock_init(&dgl_lock); | ||
807 | |||
808 | return register_sched_plugin(&color_plugin); | ||
809 | } | ||
810 | |||
811 | module_init(init_color); | ||
diff --git a/litmus/sched_litmus.c b/litmus/sched_litmus.c index 6553948407de..3de3c8605aae 100644 --- a/litmus/sched_litmus.c +++ b/litmus/sched_litmus.c | |||
@@ -160,7 +160,7 @@ static void enqueue_task_litmus(struct rq *rq, struct task_struct *p, | |||
160 | int flags) | 160 | int flags) |
161 | { | 161 | { |
162 | if (flags & ENQUEUE_WAKEUP) { | 162 | if (flags & ENQUEUE_WAKEUP) { |
163 | sched_trace_task_resume(p); | 163 | sched_trace_task_resume(p, 0); |
164 | tsk_rt(p)->present = 1; | 164 | tsk_rt(p)->present = 1; |
165 | /* LITMUS^RT plugins need to update the state | 165 | /* LITMUS^RT plugins need to update the state |
166 | * _before_ making it available in global structures. | 166 | * _before_ making it available in global structures. |
@@ -185,7 +185,7 @@ static void dequeue_task_litmus(struct rq *rq, struct task_struct *p, | |||
185 | if (flags & DEQUEUE_SLEEP) { | 185 | if (flags & DEQUEUE_SLEEP) { |
186 | litmus->task_block(p); | 186 | litmus->task_block(p); |
187 | tsk_rt(p)->present = 0; | 187 | tsk_rt(p)->present = 0; |
188 | sched_trace_task_block(p); | 188 | sched_trace_task_block(p, 0); |
189 | 189 | ||
190 | rq->litmus.nr_running--; | 190 | rq->litmus.nr_running--; |
191 | } else | 191 | } else |
diff --git a/litmus/sched_plugin.c b/litmus/sched_plugin.c index 00a1900d6457..123c7516fb76 100644 --- a/litmus/sched_plugin.c +++ b/litmus/sched_plugin.c | |||
@@ -95,6 +95,10 @@ static void litmus_dummy_task_exit(struct task_struct *task) | |||
95 | { | 95 | { |
96 | } | 96 | } |
97 | 97 | ||
98 | static void litmus_dummy_release_ts(lt_t time) | ||
99 | { | ||
100 | } | ||
101 | |||
98 | static long litmus_dummy_complete_job(void) | 102 | static long litmus_dummy_complete_job(void) |
99 | { | 103 | { |
100 | return -ENOSYS; | 104 | return -ENOSYS; |
@@ -136,6 +140,7 @@ struct sched_plugin linux_sched_plugin = { | |||
136 | .finish_switch = litmus_dummy_finish_switch, | 140 | .finish_switch = litmus_dummy_finish_switch, |
137 | .activate_plugin = litmus_dummy_activate_plugin, | 141 | .activate_plugin = litmus_dummy_activate_plugin, |
138 | .deactivate_plugin = litmus_dummy_deactivate_plugin, | 142 | .deactivate_plugin = litmus_dummy_deactivate_plugin, |
143 | .release_ts = litmus_dummy_release_ts, | ||
139 | #ifdef CONFIG_LITMUS_LOCKING | 144 | #ifdef CONFIG_LITMUS_LOCKING |
140 | .allocate_lock = litmus_dummy_allocate_lock, | 145 | .allocate_lock = litmus_dummy_allocate_lock, |
141 | #endif | 146 | #endif |
@@ -174,6 +179,7 @@ int register_sched_plugin(struct sched_plugin* plugin) | |||
174 | CHECK(complete_job); | 179 | CHECK(complete_job); |
175 | CHECK(activate_plugin); | 180 | CHECK(activate_plugin); |
176 | CHECK(deactivate_plugin); | 181 | CHECK(deactivate_plugin); |
182 | CHECK(release_ts); | ||
177 | #ifdef CONFIG_LITMUS_LOCKING | 183 | #ifdef CONFIG_LITMUS_LOCKING |
178 | CHECK(allocate_lock); | 184 | CHECK(allocate_lock); |
179 | #endif | 185 | #endif |
diff --git a/litmus/sync.c b/litmus/sync.c index bf75fde5450b..f3c9262f7022 100644 --- a/litmus/sync.c +++ b/litmus/sync.c | |||
@@ -73,6 +73,9 @@ static long do_release_ts(lt_t start) | |||
73 | 73 | ||
74 | complete_n(&ts_release, task_count); | 74 | complete_n(&ts_release, task_count); |
75 | 75 | ||
76 | /* TODO: remove this hack */ | ||
77 | litmus->release_ts(start); | ||
78 | |||
76 | return task_count; | 79 | return task_count; |
77 | } | 80 | } |
78 | 81 | ||