aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/litmus/servers.h179
-rw-r--r--litmus/sched_edf_hsb.c53
-rw-r--r--litmus/servers.c275
3 files changed, 279 insertions, 228 deletions
diff --git a/include/litmus/servers.h b/include/litmus/servers.h
index 97fd0ce76207..d3e45857653b 100644
--- a/include/litmus/servers.h
+++ b/include/litmus/servers.h
@@ -3,125 +3,161 @@
3 3
4struct server; 4struct server;
5struct periodic_server; 5struct periodic_server;
6struct proc_read_args;
7struct proc_dir_entry; 6struct proc_dir_entry;
8struct server_domain; 7struct server_domain;
9struct server_release_heap; 8struct server_release_heap;
9struct completion_timer;
10struct server_proc;
10 11
11#define SERVER_RELEASE_QUEUE_SLOTS 127 12#define SERVER_RELEASE_QUEUE_SLOTS 127
12 13
13#define SERVER_FMT "{server/%d:%d}" 14#define SERVER_FMT "{server/%d:%d}"
14#define SERVER_ARGS(s) (s)->id, (s)->job_no 15#define SERVER_ARGS(s) (s)->id, (s)->job_no
15 16
17#define server_task(s) (((s)->cpu != NO_CPU)?s->domain->linked_tasks[(s)->cpu]:NULL)
18#define is_server_linked(s) ((s)->cpu != NO_CPU)
19
16/* 20/*
17 * Called when a server is released. 21 * A single schedulable server.
18 */
19typedef void (*post_release_t)(struct periodic_server *server);
20/*
21 * Called when a server exhausts its budget.
22 */
23typedef void (*server_completed_t)(struct server *server,
24 struct task_struct *was_running);
25/*
26 * Used to read server entries.
27 */
28typedef int (*admit_server_t)(unsigned long long wcet,
29 unsigned long long period, int cpu);
30/*
31 * Must call server_proc_read on each server to print.
32 */
33typedef void (*list_servers_t)(struct proc_read_args *args);
34/*
35 * Called after each proc write before new values are read.
36 */
37typedef void (*stop_servers_t)(void);
38/*
39 * Called when a group of servers release
40 */ 22 */
41typedef void (*servers_released_t)(struct list_head *servers);
42
43typedef struct server { 23typedef struct server {
44 /* Specified by the user */ 24 /* Specified by the user */
45 int id; 25 int id;
46 lt_t wcet; 26 lt_t wcet;
47 lt_t period; 27 lt_t period;
48 28
29 /* Optional */
30 int type;
31 void* data;
32
49 /* Managed internally */ 33 /* Managed internally */
50 lt_t deadline; 34 lt_t deadline;
51 lt_t release; 35 lt_t release;
52 lt_t budget; /* The remaining budget for current period */ 36 lt_t budget; /* The remaining budget for current period */
53 lt_t start_time; /* The time the server started executing or 0 */
54 int running; /* True if server is currently executing */
55 int job_no; /* Current job of server */ 37 int job_no; /* Current job of server */
38 int cpu; /* CPU the server is running on or NO_CPU */
56 39
57 int type; /* Optional */ 40 struct server_domain *domain;
58
59 /* Used for grouped releases */
60 struct server_release_heap *release_heap;
61 struct list_head release_list;
62 41
63 /* Useful in general */ 42 /* For membership in collections */
64 struct bheap_node *hn; 43 struct bheap_node *hn;
65 struct list_head list; 44 struct list_head list;
66 45
67 void* data; 46 /* Used for grouped releases */
68 47 struct server_release_heap *release_heap;
69 struct task_struct* scheduled; 48 struct list_head release_list;
70} server_t; 49} server_t;
71 50
72/* 51/*
73 * Because pointer arithmetic wasn't working. TODO: pointer arithmetic 52 * Called when a server exhausts its budget.
74 */ 53 */
75typedef struct completion_timer { 54typedef void (*server_completed_t)(struct server *server,
76 int armed; 55 struct task_struct *was_running);
77 int cpu; 56/*
78 struct hrtimer timer; 57 * Called when a group of servers release
79 struct hrtimer_start_on_info info; 58 */
80 struct server_domain *domain; 59typedef void (*servers_released_t)(struct list_head *servers);
81} completion_timer_t; 60/*
61 * Used to read server entries.
62 */
63typedef int (*admit_server_t)(unsigned long long wcet,
64 unsigned long long period, int cpu);
65/*
66 * Lists all servers for a proc entry by calling list_server on each.
67 */
68typedef void (*list_servers_t)(struct server_proc *proc);
69/*
70 * Stop all servers. Used to destroy servers on a proc entry rewrite.
71 */
72typedef void (*stop_servers_t)(void);
82 73
83/* 74/*
84 * Useful tools for scheduling servers. 75 * Useful tools for scheduling servers.
85 */ 76 */
86typedef struct server_domain { 77typedef struct server_domain {
78 /* Collection of grouped releases */
87 raw_spinlock_t release_lock; 79 raw_spinlock_t release_lock;
88 struct list_head release_queue[SERVER_RELEASE_QUEUE_SLOTS]; 80 struct list_head release_queue[SERVER_RELEASE_QUEUE_SLOTS];
89 81
90 int release_master; 82 /* List of tasks to be added to the grouped releases */
83 raw_spinlock_t tobe_lock;
84 struct list_head tobe_released;
91 85
92 completion_timer_t* completion_timers; 86 /* CPU on which to release servers */
93 server_t** running; 87 int release_master;
94 88
95 raw_spinlock_t* timer_lock; 89 /* Per CPU information for running servers */
90 struct completion_timer* completion_timers;
91 server_t** linked_servers;
92 struct task_struct** linked_tasks;
93 lt_t* start_times;
96 94
95 /* Used to lock firing of the completion timer.
96 * This is needed here and not for the release timer because
97 * the completion timer actually modifies the state of the
98 * server itself.
99 */
100 raw_spinlock_t* completion_lock;
101
102 /* Event callbacks */
97 server_completed_t server_completed; 103 server_completed_t server_completed;
98 servers_released_t servers_released; 104 servers_released_t servers_released;
99 105
100 struct kmem_cache *server_release_cache; 106 /* Proc entries for controlling groups of servers */
101 107 struct list_head server_procs;
102 raw_spinlock_t tobe_lock;
103 struct list_head tobe_released;
104} server_domain_t; 108} server_domain_t;
105 109
106/* 110/*
107 * A group of servers releasing simultaneously. 111 * A group of servers releasing simultaneously.
108 */ 112 */
109typedef struct server_release_heap { 113typedef struct server_release_heap {
110 struct list_head list; 114 /* Servers to be released */
111 lt_t release_time; 115 struct list_head servers;
116 lt_t release_time;
112 117
113 struct list_head servers; 118 /* For membership in the domain */
119 struct list_head list;
120
121 /* For callbacks */
122 server_domain_t *domain;
114 123
115 struct hrtimer timer; 124 struct hrtimer timer;
116 struct hrtimer_start_on_info info; 125 struct hrtimer_start_on_info info;
117
118 server_domain_t *domain;
119} server_release_heap_t; 126} server_release_heap_t;
120 127
121/* 128/*
129 * A timer for managing server completions. Can be managed concurrently.
130 */
131typedef struct completion_timer {
132 int armed; /* Is the timer armed or not? Seperate from the timer
133 * so that it can be used to disarm a timer which
134 * is already firing.
135 */
136 int cpu; /* CPU where the server is running. This is not the
137 * cpu on which the timer will fire.
138 */
139 struct hrtimer timer;
140 struct hrtimer_start_on_info info;
141 struct server_domain *domain; /* For callbacks */
142} completion_timer_t;
143
144/*
145 * A proc directory entry which controls a group of servers.
146 */
147typedef struct server_proc {
148 struct proc_dir_entry *entry;
149 struct list_head list;
150 admit_server_t admit_server; /* Add a server from the entry */
151 list_servers_t list_servers; /* List each server in the entry */
152 stop_servers_t stop_servers; /* Disables all servers in the entry */
153 char* page; /* Used internally by proc */
154 int length; /* Used internally by proc */
155} server_proc_t;
156
157/*
122 * Initialize and exit servers 158 * Initialize and exit servers
123 */ 159 */
124void server_init(server_t *server, int id, 160void server_init(server_t *server, server_domain_t *domain, int id,
125 lt_t wcet, lt_t period, int grouped); 161 lt_t wcet, lt_t period, int grouped);
126void server_destroy(server_t *server); 162void server_destroy(server_t *server);
127 163
@@ -137,7 +173,7 @@ void server_free(server_t *server);
137void server_domain_init(server_domain_t *domain, 173void server_domain_init(server_domain_t *domain,
138 servers_released_t servers_released, 174 servers_released_t servers_released,
139 server_completed_t server_completed, 175 server_completed_t server_completed,
140 int release_master, raw_spinlock_t* timer_lock); 176 int release_master, raw_spinlock_t* completion_lock);
141void server_domain_destroy(server_domain_t *domain); 177void server_domain_destroy(server_domain_t *domain);
142 178
143/* 179/*
@@ -148,13 +184,12 @@ int add_server_release(server_t *server, server_domain_t *server_domain);
148/* 184/*
149 * Runs a task on the server. 185 * Runs a task on the server.
150 */ 186 */
151void server_run(server_t *server, struct task_struct *task, 187void server_run(server_t *server, struct task_struct *task);
152 server_domain_t *server_domain);
153 188
154/* 189/*
155 * Stops server execution. 190 * Stops server execution.
156 */ 191 */
157void server_stop(server_t *server, server_domain_t *domain); 192void server_stop(server_t *server);
158 193
159/* 194/*
160 * Begins a server's next period. 195 * Begins a server's next period.
@@ -167,20 +202,18 @@ void server_release(server_t *server);
167void server_release_at(server_t *server, lt_t time); 202void server_release_at(server_t *server, lt_t time);
168 203
169/* 204/*
170 * Call once for every server which should be printed 205 * Call once for every server which should be printed by list_servers.
171 * out on a proc dir read. Should be called inside a list_servers_t
172 * method.
173 */ 206 */
174void server_proc_read_single(server_t *server, int cpu, 207void list_server(server_t *server, int cpu, server_proc_t *proc);
175 struct proc_read_args *args);
176 208
177/* 209/*
178 * Create and destroy a proc dir entry with the given file name. 210 * Create and destroy a proc dir entry with the given file name.
179 */ 211 */
180int server_proc_init(struct proc_dir_entry *proc_dir, char *file, 212server_proc_t* server_proc_init(server_domain_t *domain,
181 admit_server_t admit_server, 213 struct proc_dir_entry *proc_dir, char *file,
182 list_servers_t list_servers, 214 admit_server_t admit_server,
183 stop_servers_t stop_servers); 215 list_servers_t list_servers,
184void server_proc_exit(struct proc_dir_entry *proc_dir, char *file); 216 stop_servers_t stop_servers);
217void server_proc_exit(server_proc_t *proc);
185 218
186#endif 219#endif
diff --git a/litmus/sched_edf_hsb.c b/litmus/sched_edf_hsb.c
index e3cd78d29ce8..26f32d874916 100644
--- a/litmus/sched_edf_hsb.c
+++ b/litmus/sched_edf_hsb.c
@@ -293,7 +293,7 @@ static void donate_slack(server_t *donator, struct task_struct *was_scheduled)
293 TRACE_SERVER_SUB(donator, "donated %llu slack", TIME(donator->budget)); 293 TRACE_SERVER_SUB(donator, "donated %llu slack", TIME(donator->budget));
294 sched_trace_action(was_scheduled, 9); 294 sched_trace_action(was_scheduled, 9);
295 slack = server_alloc(GFP_ATOMIC); 295 slack = server_alloc(GFP_ATOMIC);
296 server_init(slack, donator->id, donator->budget, 296 server_init(slack, &server_domain, donator->id, donator->budget,
297 donator->period, 0); 297 donator->period, 0);
298 slack->type = S_SLACK; 298 slack->type = S_SLACK;
299 server_release_at(slack, donator->release); 299 server_release_at(slack, donator->release);
@@ -606,7 +606,7 @@ static noinline void link_server(cpu_entry_t *entry,
606 } 606 }
607 607
608 entry->linked_server = next_server; 608 entry->linked_server = next_server;
609 server_run(entry->linked_server, entry->linked, &server_domain); 609 server_run(entry->linked_server, entry->linked);
610} 610}
611 611
612/* 612/*
@@ -624,7 +624,7 @@ static noinline void unlink_server(cpu_entry_t *entry,
624 if (!entry->linked_server) 624 if (!entry->linked_server)
625 return; 625 return;
626 626
627 server_stop(entry->linked_server, &server_domain); 627 server_stop(entry->linked_server);
628 now = litmus_clock(); 628 now = litmus_clock();
629 629
630 if (is_hrt(entry->linked) && !hrt_server->ready) { 630 if (is_hrt(entry->linked) && !hrt_server->ready) {
@@ -837,8 +837,6 @@ static inline void catchup_server(server_t *server, lt_t time)
837 lt_t diff = time - server->deadline; 837 lt_t diff = time - server->deadline;
838 lt_t sub = diff % server->period; 838 lt_t sub = diff % server->period;
839 839
840 BUG_ON(server->running);
841
842 server_release_at(server, time - sub); 840 server_release_at(server, time - sub);
843 TRACE_SUB("catching up server %d to %llu", 841 TRACE_SUB("catching up server %d to %llu",
844 server->id, server->deadline); 842 server->id, server->deadline);
@@ -856,8 +854,9 @@ static struct task_struct* next_eligible_hrt(hrt_server_t *hrt_server)
856 lt_t now = litmus_clock(); 854 lt_t now = litmus_clock();
857 struct task_struct *task = NULL; 855 struct task_struct *task = NULL;
858 856
859 /* Catch up server if it is late */ 857 /* Catch up server if it is initialized, not running, and late */
860 if (hrt_server->server.deadline && !hrt_server->server.running && 858 if (hrt_server->server.deadline &&
859 !is_server_linked(&hrt_server->server) &&
861 lt_before_eq(hrt_server->server.deadline, now)) { 860 lt_before_eq(hrt_server->server.deadline, now)) {
862 catchup_server(&hrt_server->server, now); 861 catchup_server(&hrt_server->server, now);
863 slack_timer_arm(hrt_server); 862 slack_timer_arm(hrt_server);
@@ -1659,7 +1658,8 @@ static int admit_be_server(unsigned long long wcet,
1659 } 1658 }
1660 1659
1661 be_server = server_alloc(GFP_ATOMIC); 1660 be_server = server_alloc(GFP_ATOMIC);
1662 server_init(be_server, BE_SERVER_BASE + ++curr_be, 1661 server_init(be_server, &server_domain,
1662 BE_SERVER_BASE + ++curr_be,
1663 wcet, period, 1); 1663 wcet, period, 1);
1664 be_server->type = S_BE; 1664 be_server->type = S_BE;
1665 1665
@@ -1674,14 +1674,14 @@ static int admit_be_server(unsigned long long wcet,
1674/* 1674/*
1675 * Output all BE servers to a proc entry. 1675 * Output all BE servers to a proc entry.
1676 */ 1676 */
1677static void list_be_servers(struct proc_read_args *args) 1677static void list_be_servers(server_proc_t *proc)
1678{ 1678{
1679 struct list_head *pos; 1679 struct list_head *pos;
1680 server_t *be_server; 1680 server_t *be_server;
1681 1681
1682 list_for_each(pos, &be_servers) { 1682 list_for_each(pos, &be_servers) {
1683 be_server = list_entry(pos, server_t, list); 1683 be_server = list_entry(pos, server_t, list);
1684 server_proc_read_single(be_server, NO_CPU, args); 1684 list_server(be_server, NO_CPU, proc);
1685 } 1685 }
1686} 1686}
1687 1687
@@ -1724,7 +1724,8 @@ static int admit_hrt_server(unsigned long long wcet,
1724 1724
1725 hrt_server->no_slack = 0; 1725 hrt_server->no_slack = 0;
1726 1726
1727 server_init(&hrt_server->server, cpu, wcet, period, 1); 1727 server_init(&hrt_server->server, &server_domain,
1728 cpu, wcet, period, 1);
1728 hrt_server->server.type = S_HRT; 1729 hrt_server->server.type = S_HRT;
1729 1730
1730 edf_domain_init(&hrt_server->hrt_domain, NULL, 1731 edf_domain_init(&hrt_server->hrt_domain, NULL,
@@ -1741,16 +1742,16 @@ static int admit_hrt_server(unsigned long long wcet,
1741/* 1742/*
1742 * Print all HRT servers to a proc entry. 1743 * Print all HRT servers to a proc entry.
1743 */ 1744 */
1744static void list_hrt_servers(struct proc_read_args *args) 1745static void list_hrt_servers(server_proc_t *proc)
1745{ 1746{
1746 cpu_entry_t *entry; 1747 cpu_entry_t *entry;
1747 hrt_server_t *hrt_server; 1748 hrt_server_t *hrt_server;
1748 int cpu; 1749 int cpu;
1749 1750
1750 for_each_online_cpu(cpu) { 1751 for_each_online_cpu(cpu) {
1751 entry = &per_cpu(cpu_entries, cpu); 1752 entry = &per_cpu(cpu_entries, cpu);
1752 hrt_server = &entry->hrt_server; 1753 hrt_server = &entry->hrt_server;
1753 server_proc_read_single(&hrt_server->server, cpu, args); 1754 list_server(&hrt_server->server, cpu, proc);
1754 } 1755 }
1755} 1756}
1756 1757
@@ -2048,7 +2049,8 @@ static void edf_hsb_task_new(struct task_struct *task, int on_rq, int running)
2048 if (is_srt(task)) { 2049 if (is_srt(task)) {
2049 /* Create SRT server */ 2050 /* Create SRT server */
2050 srt_server = server_alloc(GFP_ATOMIC); 2051 srt_server = server_alloc(GFP_ATOMIC);
2051 server_init(srt_server, task->pid, get_exec_cost(task), 2052 server_init(srt_server, &server_domain,
2053 task->pid, get_exec_cost(task),
2052 get_rt_period(task), 0); 2054 get_rt_period(task), 0);
2053 srt_server->type = S_SRT; 2055 srt_server->type = S_SRT;
2054 srt_server->data = task; 2056 srt_server->data = task;
@@ -2157,13 +2159,6 @@ static int __init init_edf_hsb(void)
2157 goto out; 2159 goto out;
2158 } 2160 }
2159 2161
2160 /* Server proc interfaces */
2161 rv = server_proc_init(edf_hsb_proc_dir, BE_PROC_NAME,
2162 admit_be_server, list_be_servers,
2163 stop_be_servers);
2164 rv = server_proc_init(edf_hsb_proc_dir, HRT_PROC_NAME,
2165 admit_hrt_server, list_hrt_servers,
2166 stop_hrt_servers);
2167 2162
2168 task_data_cache = KMEM_CACHE(task_data, SLAB_PANIC); 2163 task_data_cache = KMEM_CACHE(task_data, SLAB_PANIC);
2169 2164
@@ -2174,6 +2169,17 @@ static int __init init_edf_hsb(void)
2174 server_domain_init(&server_domain, servers_released, 2169 server_domain_init(&server_domain, servers_released,
2175 server_completed, NO_CPU, global_lock); 2170 server_completed, NO_CPU, global_lock);
2176 2171
2172 /* Server proc interfaces */
2173 server_proc_init(&server_domain,
2174 edf_hsb_proc_dir, BE_PROC_NAME,
2175 admit_be_server, list_be_servers,
2176 stop_be_servers);
2177 server_proc_init(&server_domain,
2178 edf_hsb_proc_dir, HRT_PROC_NAME,
2179 admit_hrt_server, list_hrt_servers,
2180 stop_hrt_servers);
2181
2182
2177 /* Global collections */ 2183 /* Global collections */
2178 bheap_init(&cpu_heap); 2184 bheap_init(&cpu_heap);
2179 bheap_init(&be_ready_servers); 2185 bheap_init(&be_ready_servers);
@@ -2216,9 +2222,6 @@ static void exit_edf_hsb(void)
2216 stop_be_servers(); 2222 stop_be_servers();
2217 stop_hrt_servers(); 2223 stop_hrt_servers();
2218 2224
2219 server_proc_exit(edf_hsb_proc_dir, BE_PROC_NAME);
2220 server_proc_exit(edf_hsb_proc_dir, HRT_PROC_NAME);
2221
2222 server_domain_destroy(&server_domain); 2225 server_domain_destroy(&server_domain);
2223 2226
2224 for_each_online_cpu(cpu) { 2227 for_each_online_cpu(cpu) {
diff --git a/litmus/servers.c b/litmus/servers.c
index 4011bc3c144b..6ee70d928051 100644
--- a/litmus/servers.c
+++ b/litmus/servers.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * TODO: memory leaks for stopping 2 * TODO: change from destroy to exit, rename server proc stuff
3 */ 3 */
4#include <linux/hrtimer.h> 4#include <linux/hrtimer.h>
5#include <linux/percpu.h> 5#include <linux/percpu.h>
@@ -22,18 +22,17 @@
22 ({lt_t y = x; \ 22 ({lt_t y = x; \
23 do_div(y, NSEC_PER_MSEC); \ 23 do_div(y, NSEC_PER_MSEC); \
24 y;}) 24 y;})
25
26#ifdef DEBUG_SERVERS 25#ifdef DEBUG_SERVERS
27#define _TRACE_SUB(fmt, args...) \ 26#define _TRACE_SUB(fmt, args...) \
28 sched_trace_log_message("%d P%d -[%s@%s:%d]: " fmt "\n", \ 27 sched_trace_log_message("%d P%d -[%s@%s:%d]: " fmt "\n", \
29 TRACE_ARGS, ## args) 28 TRACE_ARGS, ## args)
30#define TRACE_SUB(s, fmt, args...) \ 29#define TRACE_SUB(s, fmt, args...) \
31 do {\ 30 do {\
32 if ((s)->running) \ 31 if (is_server_linked(s)) \
33 _TRACE_SUB("(%s/%d:%d) " SERVER_FMT " " fmt, \ 32 _TRACE_SUB("(%s/%d:%d) " SERVER_FMT " " fmt, \
34 (s)->scheduled->comm, \ 33 server_task(s)->comm, \
35 (s)->scheduled->pid, \ 34 server_task(s)->pid, \
36 (s)->scheduled->rt_param.job_params.job_no, \ 35 server_task(s)->rt_param.job_params.job_no, \
37 SERVER_ARGS(s), ##args); \ 36 SERVER_ARGS(s), ##args); \
38 else \ 37 else \
39 _TRACE_SUB("(NULL) " SERVER_FMT " " fmt, \ 38 _TRACE_SUB("(NULL) " SERVER_FMT " " fmt, \
@@ -45,11 +44,11 @@
45 TRACE_ARGS, ## args, TIME(litmus_clock())) 44 TRACE_ARGS, ## args, TIME(litmus_clock()))
46#define TRACE_TIMER(s, fmt, args...) \ 45#define TRACE_TIMER(s, fmt, args...) \
47 do { \ 46 do { \
48 if ((s)->running) \ 47 if (is_server_linked(s)) \
49 _TRACE_TIMER("(%s/%d:%d) " SERVER_FMT " " fmt, \ 48 _TRACE_TIMER("(%s/%d:%d) " SERVER_FMT " " fmt, \
50 (s)->scheduled->comm, \ 49 server_task(s)->comm, \
51 (s)->scheduled->pid, \ 50 server_task(s)->pid, \
52 (s)->scheduled->rt_param.job_params.job_no, \ 51 server_task(s)->rt_param.job_params.job_no, \
53 SERVER_ARGS(s), ##args); \ 52 SERVER_ARGS(s), ##args); \
54 else \ 53 else \
55 _TRACE_TIMER("(NULL) " SERVER_FMT " " fmt, \ 54 _TRACE_TIMER("(NULL) " SERVER_FMT " " fmt, \
@@ -69,17 +68,6 @@ DEFINE_PER_CPU(struct hrtimer_start_on_info, server_cpu_infos);
69struct kmem_cache *server_release_cache; 68struct kmem_cache *server_release_cache;
70struct kmem_cache *server_cache; 69struct kmem_cache *server_cache;
71 70
72typedef struct proc_read_args {
73 char *page;
74 int length;
75} proc_read_args_t;
76
77typedef struct {
78 admit_server_t admit_server;
79 list_servers_t list_servers;
80 stop_servers_t stop_servers;
81} methods_t;
82
83/* 71/*
84 * Okay to call if the timer is not armed. 72 * Okay to call if the timer is not armed.
85 */ 73 */
@@ -94,8 +82,8 @@ static inline int timer_cancel(struct hrtimer *timer)
94static int completion_timer_arm(server_domain_t* domain, int cpu) 82static int completion_timer_arm(server_domain_t* domain, int cpu)
95{ 83{
96 int err = 0, on_cpu; 84 int err = 0, on_cpu;
97 lt_t now = litmus_clock(); 85 lt_t now = domain->start_times[cpu];
98 server_t *server = domain->running[cpu]; 86 server_t *server = domain->linked_servers[cpu];
99 lt_t budget_exhausted = now + server->budget; 87 lt_t budget_exhausted = now + server->budget;
100 88
101 /* This happens when someone attempts to call server_run when 89 /* This happens when someone attempts to call server_run when
@@ -113,7 +101,7 @@ static int completion_timer_arm(server_domain_t* domain, int cpu)
113 return 0; 101 return 0;
114 } 102 }
115 103
116 TRACE_SUB(server, "start time: %llu", server->start_time); 104 TRACE_SUB(server, "start time: %llu", domain->start_times[cpu]);
117 105
118#ifdef COMPLETION_ON_MASTER 106#ifdef COMPLETION_ON_MASTER
119 if (domain->release_master != NO_CPU) 107 if (domain->release_master != NO_CPU)
@@ -151,26 +139,6 @@ static int completion_timer_arm(server_domain_t* domain, int cpu)
151 return 1; 139 return 1;
152} 140}
153 141
154void server_run(server_t *server, struct task_struct *task,
155 server_domain_t *domain)
156{
157 int cpu = task->rt_param.linked_on;
158
159 BUG_ON(server->scheduled);
160 BUG_ON(server->running);
161 BUG_ON(cpu == NO_CPU);
162 BUG_ON(domain->running[cpu]);
163
164 server->scheduled = task;
165 server->running = 1;
166 server->start_time = litmus_clock();
167
168 domain->running[cpu] = server;
169 domain->completion_timers[cpu].armed =completion_timer_arm(domain, cpu);
170
171 TRACE_SUB(server, "running on cpu P%d", task->rt_param.linked_on);
172}
173
174static enum hrtimer_restart completion_timer_fire(struct hrtimer *timer) 142static enum hrtimer_restart completion_timer_fire(struct hrtimer *timer)
175{ 143{
176 int cpu; 144 int cpu;
@@ -188,22 +156,22 @@ static enum hrtimer_restart completion_timer_fire(struct hrtimer *timer)
188 domain = completion_timer->domain; 156 domain = completion_timer->domain;
189 cpu = completion_timer->cpu; 157 cpu = completion_timer->cpu;
190 158
191 raw_spin_lock_irqsave(domain->timer_lock, flags); 159 raw_spin_lock_irqsave(domain->completion_lock, flags);
192 160
193 _TRACE_TIMER("completion timer firing on P%d"); 161 _TRACE_TIMER("completion timer firing on P%d");
194 162
195 /* We got the lock before someone tried to re-arm. Proceed. */ 163 /* We got the lock before someone tried to re-arm. Proceed. */
196 if (completion_timer->armed) { 164 if (completion_timer->armed) {
197 server = domain->running[cpu]; 165 server = domain->linked_servers[cpu];
198 TRACE_SUB(server, "completed"); 166 TRACE_SUB(server, "completed");
199 167
200 was_running = server->scheduled; 168 was_running = server_task(server);
201 169
202 server->budget = 0; 170 server->budget = 0;
203 server->running = 0; 171 server->cpu = NO_CPU;
204 server->scheduled = NULL; 172 domain->start_times[cpu] = 0;
205 server->start_time = 0; 173 domain->linked_servers[cpu] = NULL;
206 domain->running[cpu] = NULL; 174 domain->linked_tasks[cpu] = NULL;
207 175
208 domain->server_completed(server, was_running); 176 domain->server_completed(server, was_running);
209 } 177 }
@@ -211,10 +179,12 @@ static enum hrtimer_restart completion_timer_fire(struct hrtimer *timer)
211 /* Someone either beat us to the lock or hooked up a new server 179 /* Someone either beat us to the lock or hooked up a new server
212 * when we called server_completed. Rearm the timer. 180 * when we called server_completed. Rearm the timer.
213 */ 181 */
214 if (domain->running[cpu] && !completion_timer->armed) { 182 if (domain->linked_servers[cpu] && !completion_timer->armed) {
215 server = domain->running[cpu]; 183 server = domain->linked_servers[cpu];
184
216 TRACE_SUB(server, "rearming on P%d", cpu); 185 TRACE_SUB(server, "rearming on P%d", cpu);
217 budget_exhausted = server->start_time + server->budget; 186
187 budget_exhausted = domain->start_times[cpu] + server->budget;
218 hrtimer_set_expires(timer, ns_to_ktime(budget_exhausted)); 188 hrtimer_set_expires(timer, ns_to_ktime(budget_exhausted));
219 completion_timer->armed = 1; 189 completion_timer->armed = 1;
220 rv = HRTIMER_RESTART; 190 rv = HRTIMER_RESTART;
@@ -222,7 +192,7 @@ static enum hrtimer_restart completion_timer_fire(struct hrtimer *timer)
222 completion_timer->armed = 0; 192 completion_timer->armed = 0;
223 } 193 }
224 194
225 raw_spin_unlock_irqrestore(domain->timer_lock, flags); 195 raw_spin_unlock_irqrestore(domain->completion_lock, flags);
226 196
227 return rv; 197 return rv;
228} 198}
@@ -249,7 +219,8 @@ static void release_heap_free(server_release_heap_t* rh)
249 kmem_cache_free(server_release_cache, rh); 219 kmem_cache_free(server_release_cache, rh);
250} 220}
251 221
252void server_init(server_t *server, int id, lt_t wcet, lt_t period, int grouped) 222void server_init(server_t *server, server_domain_t *domain,
223 int id, lt_t wcet, lt_t period, int grouped)
253{ 224{
254 server->id = id; 225 server->id = id;
255 server->wcet = wcet; 226 server->wcet = wcet;
@@ -258,19 +229,18 @@ void server_init(server_t *server, int id, lt_t wcet, lt_t period, int grouped)
258 server->deadline = 0; 229 server->deadline = 0;
259 server->release = 0; 230 server->release = 0;
260 server->budget = 0; 231 server->budget = 0;
261 server->start_time = 0;
262
263 server->running = 0;
264 server->job_no = 0; 232 server->job_no = 0;
265 server->scheduled = NULL; 233 server->cpu = NO_CPU;
234
235 server->domain = domain;
266 236
267 server->data = NULL; 237 server->data = NULL;
268 238
269 server->hn = bheap_node_alloc(GFP_ATOMIC); 239 server->hn = bheap_node_alloc(GFP_ATOMIC);
270 bheap_node_init(&server->hn, server); 240 bheap_node_init(&server->hn, server);
271 INIT_LIST_HEAD(&server->list); 241 INIT_LIST_HEAD(&server->list);
272 server->release_heap = NULL;
273 242
243 server->release_heap = NULL;
274 if (grouped) { 244 if (grouped) {
275 server->release_heap = release_heap_alloc(GFP_ATOMIC); 245 server->release_heap = release_heap_alloc(GFP_ATOMIC);
276 INIT_LIST_HEAD(&server->release_list); 246 INIT_LIST_HEAD(&server->release_list);
@@ -307,37 +277,58 @@ static inline lt_t lt_subtract(lt_t a, lt_t b)
307 return 0; 277 return 0;
308} 278}
309 279
310void server_stop(server_t *server, server_domain_t *domain) 280void server_run(server_t *server, struct task_struct *task)
281{
282 int armed, cpu = task->rt_param.linked_on;
283 server_domain_t *domain = server->domain;
284
285 BUG_ON(is_server_linked(server));
286 BUG_ON(server-> cpu != NO_CPU);
287 BUG_ON(cpu == NO_CPU);
288 BUG_ON(domain->linked_servers[cpu]);
289 BUG_ON(domain->linked_tasks[cpu]);
290
291 server->cpu = cpu;
292 domain->linked_servers[cpu] = server;
293 domain->linked_tasks[cpu] = task;
294 domain->start_times[cpu] = litmus_clock();
295 armed = completion_timer_arm(domain, cpu);
296 domain->completion_timers[cpu].armed = armed;
297
298 TRACE_SUB(server, "running on cpu P%d", task->rt_param.linked_on);
299}
300
301void server_stop(server_t *server)
311{ 302{
312 int cpu; 303 int cpu;
313 lt_t elapsed_time, now = litmus_clock(); 304 lt_t elapsed_time, now = litmus_clock();
305 server_domain_t *domain = server->domain;
314 306
315 if (!server->running) { 307 if (!is_server_linked(server)) {
316 TRACE_SUB(server, "already stopped"); 308 TRACE_SUB(server, "already stopped");
317 return; 309 return;
318 } 310 }
319 311
320 BUG_ON(!server->running); 312 cpu = server->cpu;
321 TRACE_SUB(server, "stopping server, start: %llu, end: %llu", 313 BUG_ON(cpu == NO_CPU);
322 server->start_time, now);
323 314
315 TRACE_SUB(server, "stopping server, start: %llu, end: %llu",
316 domain->start_times[cpu], now);
324 317
325 /* Calculate remaining budget */ 318 /* Calculate remaining budget */
326 elapsed_time = lt_subtract(now, server->start_time); 319 elapsed_time = lt_subtract(now, domain->start_times[cpu]);
327 server->budget -= elapsed_time; 320 server->budget -= elapsed_time;
328 321
322 server->cpu = NO_CPU;
323
329 TRACE_SUB(server, "new budget: %llu", TIME(server->budget)); 324 TRACE_SUB(server, "new budget: %llu", TIME(server->budget));
325 BUG_ON(domain->linked_servers[cpu] != server);
330 326
331 /* Set domain state */ 327 /* Set domain state */
332 cpu = server->scheduled->rt_param.linked_on;
333 domain->completion_timers[cpu].armed = 0; 328 domain->completion_timers[cpu].armed = 0;
334 domain->running[cpu] = NULL; 329 domain->linked_servers[cpu] = NULL;
330 domain->linked_tasks[cpu] = NULL;
335 timer_cancel(&domain->completion_timers[cpu].timer); 331 timer_cancel(&domain->completion_timers[cpu].timer);
336
337 /* Make server inactive */
338 server->running = 0;
339 server->scheduled = NULL;
340 server->start_time = 0;
341} 332}
342 333
343void server_release(server_t *server) 334void server_release(server_t *server)
@@ -351,16 +342,12 @@ void server_release(server_t *server)
351 342
352 TRACE_SUB(server, "budget: %llu, release: %llu," 343 TRACE_SUB(server, "budget: %llu, release: %llu,"
353 "deadline: %llu, period: %llu, job: %d", 344 "deadline: %llu, period: %llu, job: %d",
354 server->budget, server->release, server->deadline,
355 server->period, server->job_no);
356 TRACE_SUB(server, "budget: %llu, release: %llu,"
357 "deadline: %llu, period: %llu, job: %d",
358 TIME(server->budget), TIME(server->release), TIME(server->deadline), 345 TIME(server->budget), TIME(server->release), TIME(server->deadline),
359 TIME(server->period), server->job_no); 346 TIME(server->period), server->job_no);
360 347
361 /* Need to reset for budget calculations */ 348 /* Need to reset for budget calculations */
362 if (server->running) 349 if (is_server_linked(server))
363 server->start_time = litmus_clock(); 350 server->domain->start_times[server->cpu] = litmus_clock();
364} 351}
365 352
366void server_release_at(server_t *server, lt_t time) 353void server_release_at(server_t *server, lt_t time)
@@ -379,34 +366,33 @@ static int server_proc_read(char* page, char **start, off_t off,
379 int count, int *eof, void *data) 366 int count, int *eof, void *data)
380{ 367{
381 int length; 368 int length;
382 methods_t *methods = (methods_t*)data; 369 server_proc_t *proc = (server_proc_t*)data;
383 proc_read_args_t *args = kmalloc(sizeof(proc_read_args_t),
384 GFP_ATOMIC);
385 370
386 args->page = page; 371 proc->page = page;
387 args->length = 0; 372 proc->length = 0;
388 methods->list_servers(args); 373 proc->list_servers(proc);
389 374
390 length = args->length; 375 length = proc->length;
391 kfree(args);
392 *eof = 1; 376 *eof = 1;
393 377
378 proc->length = 0;
379 proc->page = NULL;
380
394 return length; 381 return length;
395} 382}
396 383
397void server_proc_read_single(server_t *server, int cpu, 384void list_server(server_t *server, int cpu, server_proc_t *proc)
398 struct proc_read_args *args)
399{ 385{
400 if (cpu == NO_CPU) { 386 if (cpu == NO_CPU) {
401 args->length += 387 proc->length +=
402 snprintf(args->page + args->length, 388 snprintf(proc->page + proc->length,
403 PAGE_SIZE - args->length, 389 PAGE_SIZE - proc->length,
404 "%8llu %8llu\n", 390 "%8llu %8llu\n",
405 server->wcet, server->period); 391 server->wcet, server->period);
406 } else { 392 } else {
407 args->length += 393 proc->length +=
408 snprintf(args->page + args->length, 394 snprintf(proc->page + proc->length,
409 PAGE_SIZE - args->length, 395 PAGE_SIZE - proc->length,
410 "%8llu %8llu %3d\n", 396 "%8llu %8llu %3d\n",
411 server->wcet, server->period, cpu); 397 server->wcet, server->period, cpu);
412 } 398 }
@@ -455,7 +441,7 @@ static inline int server_param_check(unsigned long long wcet,
455static int server_proc_write(struct file *file, const char __user *input, 441static int server_proc_write(struct file *file, const char __user *input,
456 unsigned long count, void *data) 442 unsigned long count, void *data)
457{ 443{
458 methods_t *methods = (methods_t*)data; 444 server_proc_t *proc = (server_proc_t*)data;
459#define SERVER_PROC_BUF 512 445#define SERVER_PROC_BUF 512
460 char buffer[SERVER_PROC_BUF]; 446 char buffer[SERVER_PROC_BUF];
461 unsigned long long wcet, period; 447 unsigned long long wcet, period;
@@ -463,7 +449,7 @@ static int server_proc_write(struct file *file, const char __user *input,
463 int nums_converted, chars_seen, ret, cpu; 449 int nums_converted, chars_seen, ret, cpu;
464 450
465 /* Allow plugin to stop any running servers */ 451 /* Allow plugin to stop any running servers */
466 methods->stop_servers(); 452 proc->stop_servers();
467 453
468 if (count >= SERVER_PROC_BUF){ 454 if (count >= SERVER_PROC_BUF){
469 printk(KERN_WARNING "proc buffer possibly too small in %s.\n", 455 printk(KERN_WARNING "proc buffer possibly too small in %s.\n",
@@ -513,7 +499,7 @@ static int server_proc_write(struct file *file, const char __user *input,
513 ret = server_param_check(wcet, period, cpu); 499 ret = server_param_check(wcet, period, cpu);
514 if (ret) goto loop_end; 500 if (ret) goto loop_end;
515 501
516 ret = methods->admit_server(wcet, period, cpu); 502 ret = proc->admit_server(wcet, period, cpu);
517 if (ret) { 503 if (ret) {
518 printk(KERN_WARNING "Litmus plugin rejects server with " 504 printk(KERN_WARNING "Litmus plugin rejects server with "
519 "period: %llu, wcet: %llu, cpu: %d\n", 505 "period: %llu, wcet: %llu, cpu: %d\n",
@@ -527,39 +513,46 @@ loop_end:
527 return count; 513 return count;
528} 514}
529 515
530int server_proc_init(struct proc_dir_entry *proc_dir, char *file, 516server_proc_t* server_proc_init(server_domain_t *domain,
531 admit_server_t admit_server, 517 struct proc_dir_entry *proc_dir, char *file,
532 list_servers_t list_servers, 518 admit_server_t admit_server,
533 stop_servers_t stop_servers) 519 list_servers_t list_servers,
520 stop_servers_t stop_servers)
534{ 521{
535 int rv; 522 server_proc_t *server_proc = NULL;
536 methods_t *methods; 523 struct proc_dir_entry *entry;
537 struct proc_dir_entry *server_entry;
538 524
539 server_entry = create_proc_entry(file, 0644, proc_dir); 525 entry = create_proc_entry(file, 0644, proc_dir);
540 if (!server_entry) { 526 if (!entry) {
541 printk(KERN_ERR "Could not create proc entry: %s.\n", file); 527 printk(KERN_ERR "Could not create proc entry: %s.\n", file);
542 rv = -ENOENT;
543 goto out; 528 goto out;
544 } 529 }
545 530
546 /* Ack memory leak TODO */ 531 server_proc = kmalloc(sizeof(server_proc_t), GFP_ATOMIC);
547 methods = kmalloc(sizeof(methods_t), GFP_ATOMIC); 532
548 methods->admit_server = admit_server; 533 entry->data = server_proc;
549 methods->list_servers = list_servers; 534 entry->read_proc = server_proc_read;
550 methods->stop_servers = stop_servers; 535 entry->write_proc = server_proc_write;
551 server_entry->data = methods; 536
537 server_proc->entry = entry;
538 server_proc->admit_server = admit_server;
539 server_proc->list_servers = list_servers;
540 server_proc->stop_servers = stop_servers;
541 server_proc->length = 0;
542 server_proc->page = NULL;
552 543
553 server_entry->read_proc = server_proc_read; 544 INIT_LIST_HEAD(&server_proc->list);
554 server_entry->write_proc = server_proc_write; 545 list_add(&server_proc->list, &domain->server_procs);
555 546
556 out: 547 out:
557 return rv; 548 return server_proc;
558} 549}
559 550
560void server_proc_exit(struct proc_dir_entry *proc_dir, char *file) 551void server_proc_exit(server_proc_t *proc)
561{ 552{
562 remove_proc_entry(file, proc_dir); 553 remove_proc_entry(proc->entry->name, proc->entry->parent);
554 list_del(&proc->list);
555 kfree(proc);
563} 556}
564 557
565/****************************************************************************** 558/******************************************************************************
@@ -569,7 +562,7 @@ void server_proc_exit(struct proc_dir_entry *proc_dir, char *file)
569void server_domain_init(server_domain_t *domain, 562void server_domain_init(server_domain_t *domain,
570 servers_released_t servers_released, 563 servers_released_t servers_released,
571 server_completed_t server_completed, 564 server_completed_t server_completed,
572 int release_master, raw_spinlock_t *timer_lock) 565 int release_master, raw_spinlock_t *completion_lock)
573{ 566{
574 int i; 567 int i;
575 BUG_ON(!servers_released || !server_completed); 568 BUG_ON(!servers_released || !server_completed);
@@ -582,17 +575,28 @@ void server_domain_init(server_domain_t *domain,
582 raw_spin_lock_init(&domain->tobe_lock); 575 raw_spin_lock_init(&domain->tobe_lock);
583 576
584 577
585 domain->release_master = release_master; 578 domain->release_master = release_master;
586 domain->timer_lock = timer_lock; 579 domain->completion_lock = completion_lock;
587 domain->server_completed = server_completed; 580 domain->server_completed = server_completed;
588 domain->servers_released = servers_released; 581 domain->servers_released = servers_released;
589 582
590 domain->completion_timers = kmalloc(NR_CPUS*sizeof(completion_timer_t), 583 INIT_LIST_HEAD(&domain->server_procs);
591 GFP_ATOMIC); 584
592 domain->running = kmalloc(NR_CPUS*sizeof(server_t*), GFP_ATOMIC); 585 domain->completion_timers =
586 kmalloc(NR_CPUS*sizeof(completion_timer_t), GFP_ATOMIC);
587 domain->linked_servers =
588 kmalloc(NR_CPUS*sizeof(server_t*), GFP_ATOMIC);
589 domain->linked_tasks =
590 kmalloc(NR_CPUS*sizeof(struct task_struct*), GFP_ATOMIC);
591 domain->start_times =
592 kmalloc(NR_CPUS*sizeof(lt_t), GFP_ATOMIC);
593 593
594 for_each_online_cpu(i) { 594 for_each_online_cpu(i) {
595 domain->running[i] = NULL; 595 domain->linked_tasks[i] = NULL;
596 domain->linked_servers[i] = NULL;
597 domain->start_times[i] = 0;
598
599 /* Initialize the completion timer info */
596 domain->completion_timers[i].armed = 0; 600 domain->completion_timers[i].armed = 0;
597 domain->completion_timers[i].cpu = i; 601 domain->completion_timers[i].cpu = i;
598 hrtimer_init(&domain->completion_timers[i].timer, 602 hrtimer_init(&domain->completion_timers[i].timer,
@@ -607,8 +611,18 @@ void server_domain_init(server_domain_t *domain,
607 611
608void server_domain_destroy(server_domain_t *domain) 612void server_domain_destroy(server_domain_t *domain)
609{ 613{
614 struct list_head *pos, *safe;
615 server_proc_t *proc;
616
610 kfree(domain->completion_timers); 617 kfree(domain->completion_timers);
611 kfree(domain->running); 618 kfree(domain->linked_tasks);
619 kfree(domain->linked_servers);
620 kfree(domain->start_times);
621
622 list_for_each_safe(pos, safe, &domain->server_procs) {
623 proc = list_entry(pos, server_proc_t, list);
624 server_proc_exit(proc);
625 }
612} 626}
613 627
614static unsigned int time2slot(lt_t time) 628static unsigned int time2slot(lt_t time)
@@ -821,10 +835,11 @@ int add_server_release(server_t *server, server_domain_t *domain)
821 return arm_release_timer(domain); 835 return arm_release_timer(domain);
822} 836}
823 837
824static void init_servers(void) 838static int __init init_servers(void)
825{ 839{
826 server_cache = KMEM_CACHE(server, SLAB_PANIC); 840 server_cache = KMEM_CACHE(server, SLAB_PANIC);
827 server_release_cache = KMEM_CACHE(server_release_heap, SLAB_PANIC); 841 server_release_cache = KMEM_CACHE(server_release_heap, SLAB_PANIC);
842 return 1;
828} 843}
829 844
830static void exit_servers(void) 845static void exit_servers(void)