diff options
author | Christopher Kenna <cjk@cs.unc.edu> | 2010-10-31 16:59:40 -0400 |
---|---|---|
committer | Christopher Kenna <cjk@cs.unc.edu> | 2010-11-22 11:02:04 -0500 |
commit | 88d6578d9546a826136d5edbf8ea59c50fb40389 (patch) | |
tree | 181b85cd7c7d40041adfa21e0e9e887183e2c498 /litmus/sched_edf_hsb.c | |
parent | 05cf8f197fb336276a1298a9a3c7a5f82c21c92f (diff) |
remove complex initialization, add possible race conditions
Removed the complex initilization procedure by removing the
is_initialized atomic type. However, this introduces a slight chance
that we might activate the plugin with invalid parameters.
Diffstat (limited to 'litmus/sched_edf_hsb.c')
-rw-r--r-- | litmus/sched_edf_hsb.c | 145 |
1 files changed, 31 insertions, 114 deletions
diff --git a/litmus/sched_edf_hsb.c b/litmus/sched_edf_hsb.c index 4c4643226675..dbf912e889f3 100644 --- a/litmus/sched_edf_hsb.c +++ b/litmus/sched_edf_hsb.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <linux/ctype.h> | 7 | #include <linux/ctype.h> |
8 | #include <linux/time.h> | 8 | #include <linux/time.h> |
9 | #include <linux/string.h> | 9 | #include <linux/string.h> |
10 | #include <linux/sched.h> | ||
10 | 11 | ||
11 | #include <litmus/litmus.h> | 12 | #include <litmus/litmus.h> |
12 | #include <litmus/rt_domain.h> | 13 | #include <litmus/rt_domain.h> |
@@ -14,9 +15,9 @@ | |||
14 | #include <litmus/litmus_proc.h> | 15 | #include <litmus/litmus_proc.h> |
15 | #include <litmus/edf_common.h> | 16 | #include <litmus/edf_common.h> |
16 | 17 | ||
17 | /* synchronization point to start only when all HRT servers are set up */ | 18 | /* forward declaration so the below macro works */ |
18 | static atomic_t initialized = ATOMIC_INIT(0); | 19 | static struct sched_plugin edf_hsb_plugin __cacheline_aligned_in_smp; |
19 | #define is_initialized (atomic_read(&initialized)) | 20 | #define is_active_plugin (litmus == &edf_hsb_plugin) |
20 | 21 | ||
21 | struct hrt_server { | 22 | struct hrt_server { |
22 | int cpu; | 23 | int cpu; |
@@ -37,7 +38,8 @@ DEFINE_PER_CPU_SHARED_ALIGNED(struct hrt_server, hrt_servers); | |||
37 | /* | 38 | /* |
38 | * Set the WCET and period for an HRT server on a specific CPU. | 39 | * Set the WCET and period for an HRT server on a specific CPU. |
39 | * Times are given in milliseconds. | 40 | * Times are given in milliseconds. |
40 | * This should only be done in the initialization phase! | 41 | * There is a small race condition in checking we're not the active plugin |
42 | * before setting parameters, but we are not worried about that so much. | ||
41 | */ | 43 | */ |
42 | int set_hrt_params(unsigned long long cpu, unsigned long long wcet, | 44 | int set_hrt_params(unsigned long long cpu, unsigned long long wcet, |
43 | unsigned long long period) | 45 | unsigned long long period) |
@@ -64,17 +66,14 @@ int set_hrt_params(unsigned long long cpu, unsigned long long wcet, | |||
64 | goto out; | 66 | goto out; |
65 | } | 67 | } |
66 | 68 | ||
67 | hrt_server = &per_cpu(hrt_servers, cpu); | 69 | if (is_active_plugin) { |
68 | 70 | printk(KERN_WARNING "Can't set params on active plugin.\n"); | |
69 | write_lock_irq(&hrt_server->param_lock); | ||
70 | |||
71 | /* must do this check after getting the write lock for correctness */ | ||
72 | if (is_initialized){ | ||
73 | printk(KERN_WARNING "Attempt to set HRT params after init.\n"); | ||
74 | rv = -EPERM; | 71 | rv = -EPERM; |
75 | goto out_unlock; | 72 | goto out; |
76 | } | 73 | } |
77 | 74 | ||
75 | hrt_server = &per_cpu(hrt_servers, cpu); | ||
76 | write_lock_irq(&hrt_server->param_lock); | ||
78 | hrt_server->wcet = wcet * NSEC_PER_MSEC; | 77 | hrt_server->wcet = wcet * NSEC_PER_MSEC; |
79 | hrt_server->period = period * NSEC_PER_MSEC; | 78 | hrt_server->period = period * NSEC_PER_MSEC; |
80 | 79 | ||
@@ -82,59 +81,33 @@ int set_hrt_params(unsigned long long cpu, unsigned long long wcet, | |||
82 | * TODO probably need a function to reset hrtimers and stuff here | 81 | * TODO probably need a function to reset hrtimers and stuff here |
83 | */ | 82 | */ |
84 | 83 | ||
85 | out_unlock: | ||
86 | write_unlock_irq(&hrt_server->param_lock); | 84 | write_unlock_irq(&hrt_server->param_lock); |
87 | out: | 85 | out: |
88 | return rv; | 86 | return rv; |
89 | } | 87 | } |
90 | 88 | ||
91 | /* | 89 | /* |
92 | * do all hrt_servers have a non-zero WCET and period? if they do, set | 90 | * Do all hrt_servers have a non-zero WCET and period? Return 0 if so. |
93 | * the atomic initialized variable to 1. | ||
94 | */ | 91 | */ |
95 | static int check_hrt_servers_initialized(void) | 92 | static int check_hrt_servers_initialized(void) |
96 | { | 93 | { |
97 | struct hrt_server *hrt_server; | 94 | struct hrt_server *hrt_server; |
98 | int cpu, all_init = 1; | 95 | int cpu, all_init = 1; |
99 | 96 | ||
100 | /* | ||
101 | * we first acquire hrt server writer locks for each cpu to ensure that | ||
102 | * no one changes the value of the parameters from under us while we | ||
103 | * are checking that they are valid | ||
104 | * | ||
105 | * we don't support cpu hotplug (and I hope we never have to) | ||
106 | */ | ||
107 | |||
108 | for_each_online_cpu(cpu) { | 97 | for_each_online_cpu(cpu) { |
109 | 98 | ||
110 | hrt_server = &per_cpu(hrt_servers, cpu); | 99 | hrt_server = &per_cpu(hrt_servers, cpu); |
111 | 100 | read_lock_irq(&hrt_server->param_lock); | |
112 | /* | ||
113 | * acquire all the reader/writer locks as writers. | ||
114 | * this usually triggers a "recursive lock" warning in syslog. | ||
115 | */ | ||
116 | write_lock_irq(&hrt_server->param_lock); | ||
117 | 101 | ||
118 | /* if any parameter is zero, all_init will become zero */ | 102 | /* if any parameter is zero, all_init will become zero */ |
119 | all_init = all_init && hrt_server->wcet && | 103 | all_init = all_init && hrt_server->wcet && |
120 | hrt_server->period; | 104 | hrt_server->period; |
121 | } | ||
122 | |||
123 | /* | ||
124 | * now we hold all the writer locks, so we can make a decision about | ||
125 | * these HRT servers without worry about them getting re-set | ||
126 | * underneath us. | ||
127 | */ | ||
128 | if (all_init) | ||
129 | atomic_set(&initialized, 1); | ||
130 | 105 | ||
131 | for_each_online_cpu(cpu) { | 106 | read_unlock_irq(&hrt_server->param_lock); |
132 | hrt_server = &per_cpu(hrt_servers, cpu); | ||
133 | /* unlock all the reader/writer locks */ | ||
134 | write_unlock_irq(&hrt_server->param_lock); | ||
135 | } | 107 | } |
136 | 108 | ||
137 | return all_init; | 109 | /* inverted because zero is success */ |
110 | return !all_init; | ||
138 | } | 111 | } |
139 | 112 | ||
140 | void reset_hrt_servers(void) | 113 | void reset_hrt_servers(void) |
@@ -157,22 +130,30 @@ void reset_hrt_servers(void) | |||
157 | 130 | ||
158 | static long edf_hsb_deactivate_plugin(void) | 131 | static long edf_hsb_deactivate_plugin(void) |
159 | { | 132 | { |
160 | return 0; | ||
161 | atomic_set(&initialized, 0); | ||
162 | reset_hrt_servers(); | 133 | reset_hrt_servers(); |
134 | return 0; | ||
163 | } | 135 | } |
164 | 136 | ||
137 | /* | ||
138 | * There is a small race condition in checking that all the server parameters | ||
139 | * are valid, then having one of them change before setting the active plugin, | ||
140 | * but oh well. | ||
141 | */ | ||
165 | static long edf_hsb_activate_plugin(void) | 142 | static long edf_hsb_activate_plugin(void) |
166 | { | 143 | { |
167 | return 0; | 144 | long rv = 0; |
145 | |||
146 | if (check_hrt_servers_initialized()) | ||
147 | rv = -EINVAL; | ||
148 | |||
149 | return rv; | ||
168 | } | 150 | } |
169 | 151 | ||
170 | /************************************************************ | 152 | /************************************************************ |
171 | * Proc stuff | 153 | * Proc stuff |
172 | ************************************************************/ | 154 | ************************************************************/ |
173 | 155 | ||
174 | static struct proc_dir_entry *edf_hsb_proc_dir = NULL, *hrt_server_proc = NULL, | 156 | static struct proc_dir_entry *edf_hsb_proc_dir = NULL, *hrt_server_proc = NULL; |
175 | *initialized_proc = NULL; | ||
176 | 157 | ||
177 | static int hrt_proc_read(char* page, char **start, off_t off, int count, | 158 | static int hrt_proc_read(char* page, char **start, off_t off, int count, |
178 | int *eof, void *data) | 159 | int *eof, void *data) |
@@ -274,53 +255,8 @@ loop_end: | |||
274 | return count; | 255 | return count; |
275 | } | 256 | } |
276 | 257 | ||
277 | static int initialized_proc_read(char* page, char **start, off_t off, int count, | 258 | /* actual plugin object */ |
278 | int *eof, void *data) | 259 | /* static struct sched_plugin edf_hsb_plugin = { */ |
279 | { | ||
280 | int len = 0; | ||
281 | len += snprintf(page, PAGE_SIZE, "%d\n", is_initialized); | ||
282 | *eof = 1; | ||
283 | return len; | ||
284 | } | ||
285 | |||
286 | static int initialized_proc_write(struct file *file, const char __user *input, | ||
287 | unsigned long count, void *data) | ||
288 | { | ||
289 | #define INITIALIZED_PROC_BUF 3 | ||
290 | char buffer[INITIALIZED_PROC_BUF]; | ||
291 | int in_val = -1, num_read; | ||
292 | |||
293 | /* don't allow changes after initialized */ | ||
294 | if (is_initialized) | ||
295 | return -EPERM; | ||
296 | |||
297 | if (count >= INITIALIZED_PROC_BUF){ | ||
298 | printk(KERN_WARNING "proc buffer possibly too small in %s.\n", | ||
299 | __func__); | ||
300 | return -ENOSPC; | ||
301 | } | ||
302 | |||
303 | if (copy_from_user(buffer, input, (INITIALIZED_PROC_BUF - 1))) | ||
304 | return -EFAULT; | ||
305 | |||
306 | buffer[INITIALIZED_PROC_BUF-1] = '\0'; | ||
307 | |||
308 | num_read = sscanf(buffer, "%d", &in_val); | ||
309 | |||
310 | if (!num_read || (in_val!= 0 && in_val != 1)) { | ||
311 | printk(KERN_WARNING "Invalid HSB initialization in proc.\n"); | ||
312 | return -EIO; | ||
313 | } else if (in_val == 1) { | ||
314 | check_hrt_servers_initialized(); | ||
315 | if (!is_initialized) | ||
316 | printk(KERN_WARNING "Attempted to set initialized = 1 " | ||
317 | "without all HRT servers setup.\n"); | ||
318 | } | ||
319 | |||
320 | return count; | ||
321 | } | ||
322 | |||
323 | /* Plugin object */ | ||
324 | static struct sched_plugin edf_hsb_plugin __cacheline_aligned_in_smp = { | 260 | static struct sched_plugin edf_hsb_plugin __cacheline_aligned_in_smp = { |
325 | .plugin_name = "EDF-HSB", | 261 | .plugin_name = "EDF-HSB", |
326 | 262 | ||
@@ -349,15 +285,9 @@ static struct sched_plugin edf_hsb_plugin __cacheline_aligned_in_smp = { | |||
349 | }; | 285 | }; |
350 | 286 | ||
351 | #define HRT_SERVER_PROC_NAME "hrt_server" | 287 | #define HRT_SERVER_PROC_NAME "hrt_server" |
352 | #define INITIALIZED_PROC_NAME "initialized" | ||
353 | 288 | ||
354 | static void exit_proc(void) | 289 | static void exit_proc(void) |
355 | { | 290 | { |
356 | if (initialized_proc) { | ||
357 | remove_proc_entry(INITIALIZED_PROC_NAME, edf_hsb_proc_dir); | ||
358 | initialized_proc = NULL; | ||
359 | } | ||
360 | |||
361 | if (hrt_server_proc) { | 291 | if (hrt_server_proc) { |
362 | remove_proc_entry(HRT_SERVER_PROC_NAME, edf_hsb_proc_dir); | 292 | remove_proc_entry(HRT_SERVER_PROC_NAME, edf_hsb_proc_dir); |
363 | hrt_server_proc = NULL; | 293 | hrt_server_proc = NULL; |
@@ -399,19 +329,6 @@ static int __init init_edf_hsb(void) | |||
399 | hrt_server_proc->read_proc = hrt_proc_read; | 329 | hrt_server_proc->read_proc = hrt_proc_read; |
400 | hrt_server_proc->write_proc = hrt_proc_write; | 330 | hrt_server_proc->write_proc = hrt_proc_write; |
401 | 331 | ||
402 | initialized_proc = create_proc_entry(INITIALIZED_PROC_NAME, | ||
403 | 0644, edf_hsb_proc_dir); | ||
404 | if (!initialized_proc) { | ||
405 | printk(KERN_ERR "Could not create proc entry: %s.\n", | ||
406 | INITIALIZED_PROC_NAME); | ||
407 | rv = -ENOENT; | ||
408 | goto out_clean_proc; | ||
409 | } | ||
410 | |||
411 | initialized_proc->read_proc = initialized_proc_read; | ||
412 | initialized_proc->write_proc = initialized_proc_write; | ||
413 | |||
414 | atomic_set(&initialized, 0); | ||
415 | reset_hrt_servers(); | 332 | reset_hrt_servers(); |
416 | 333 | ||
417 | goto out; | 334 | goto out; |