aboutsummaryrefslogtreecommitdiffstats
path: root/litmus/servers.c
diff options
context:
space:
mode:
Diffstat (limited to 'litmus/servers.c')
-rw-r--r--litmus/servers.c475
1 files changed, 330 insertions, 145 deletions
diff --git a/litmus/servers.c b/litmus/servers.c
index a43aad336367..9ee58198b0d6 100644
--- a/litmus/servers.c
+++ b/litmus/servers.c
@@ -1,9 +1,13 @@
1/*
2 * TODO: memory leaks for stopping
3 */
1#include <linux/hrtimer.h> 4#include <linux/hrtimer.h>
2#include <linux/percpu.h> 5#include <linux/percpu.h>
3#include <linux/sched.h> 6#include <linux/sched.h>
4#include <linux/uaccess.h> 7#include <linux/uaccess.h>
5#include <linux/ctype.h> 8#include <linux/ctype.h>
6 9
10#include <litmus/bheap.h>
7#include <litmus/litmus.h> 11#include <litmus/litmus.h>
8#include <litmus/litmus_proc.h> 12#include <litmus/litmus_proc.h>
9#include <litmus/sched_trace.h> 13#include <litmus/sched_trace.h>
@@ -11,6 +15,9 @@
11 15
12#define DEBUG_SERVERS 16#define DEBUG_SERVERS
13 17
18/* Not working */
19/* #define COMPLETION_ON_MASTER */
20
14#define TIME(x) \ 21#define TIME(x) \
15 ({lt_t y = x; \ 22 ({lt_t y = x; \
16 do_div(y, NSEC_PER_MSEC); \ 23 do_div(y, NSEC_PER_MSEC); \
@@ -81,6 +88,7 @@ static inline int timer_cancel(struct hrtimer *timer)
81 88
82static int completion_timer_arm(server_domain_t* domain, int cpu) 89static int completion_timer_arm(server_domain_t* domain, int cpu)
83{ 90{
91 int err = 0, on_cpu;
84 lt_t now = litmus_clock(); 92 lt_t now = litmus_clock();
85 server_t *server = domain->running[cpu]; 93 server_t *server = domain->running[cpu];
86 lt_t budget_exhausted = now + server->budget; 94 lt_t budget_exhausted = now + server->budget;
@@ -95,13 +103,40 @@ static int completion_timer_arm(server_domain_t* domain, int cpu)
95 return 0; 103 return 0;
96 } 104 }
97 105
106 if (domain->completion_timers[cpu].armed) {
107 TRACE_SUB(server, "cannot arm completion, waiting for arm");
108 return 0;
109 }
110
111 /* This happens when a server is run late enough that it would complete
112 * after its released. This will almost certainly cause a reschedule,
113 * so we just force the server to complete here and trust the callback
114 * to get things right.
115 */
116 if (lt_before_eq(server->deadline, budget_exhausted)) {
117 budget_exhausted = server->deadline;
118 }
119
98 TRACE_SUB(server, "start time: %llu", server->start_time); 120 TRACE_SUB(server, "start time: %llu", server->start_time);
99 121
122#ifdef COMPLETION_ON_MASTER
123 if (domain->release_master != NO_CPU)
124 on_cpu = domain->release_master;
125 else
126#endif
127 on_cpu = cpu;
128
100 if (cpu != smp_processor_id()) { 129 if (cpu != smp_processor_id()) {
101 hrtimer_start_on(cpu, &domain->completion_timers[cpu].info, 130 err = hrtimer_start_on(on_cpu,
102 &domain->completion_timers[cpu].timer, 131 &domain->completion_timers[cpu].info,
103 ns_to_ktime(budget_exhausted), 132 &domain->completion_timers[cpu].timer,
104 HRTIMER_MODE_ABS_PINNED); 133 ns_to_ktime(budget_exhausted),
134 HRTIMER_MODE_ABS_PINNED);
135 if (err) {
136 TRACE_SUB(server, "failed to arm completion");
137 } else {
138 TRACE_SUB(server, "success on P%d!", on_cpu);
139 }
105 } else { 140 } else {
106 __hrtimer_start_range_ns(&domain->completion_timers[cpu].timer, 141 __hrtimer_start_range_ns(&domain->completion_timers[cpu].timer,
107 ns_to_ktime(budget_exhausted), 142 ns_to_ktime(budget_exhausted),
@@ -132,9 +167,6 @@ void server_run(server_t *server, struct task_struct *task,
132 server->running = 1; 167 server->running = 1;
133 server->start_time = litmus_clock(); 168 server->start_time = litmus_clock();
134 169
135 /* TODO REMOVE ME */
136 server->domain = domain;
137
138 domain->running[cpu] = server; 170 domain->running[cpu] = server;
139 domain->completion_timers[cpu].armed =completion_timer_arm(domain, cpu); 171 domain->completion_timers[cpu].armed =completion_timer_arm(domain, cpu);
140 172
@@ -147,28 +179,26 @@ static enum hrtimer_restart completion_timer_fire(struct hrtimer *timer)
147 unsigned long flags; 179 unsigned long flags;
148 enum hrtimer_restart rv; 180 enum hrtimer_restart rv;
149 struct task_struct *was_running; 181 struct task_struct *was_running;
150 completion_timer_t *container; 182 completion_timer_t *completion_timer;
151 server_domain_t *domain; 183 server_domain_t *domain;
152 server_t *server; 184 server_t *server;
153 lt_t budget_exhausted; 185 lt_t budget_exhausted;
154 186
155 rv = HRTIMER_NORESTART; 187 rv = HRTIMER_NORESTART;
156 cpu = smp_processor_id();
157 188
158 189 completion_timer = container_of(timer, completion_timer_t, timer);
159 /* Use fancy pointer arithmetic to get the domain */ 190 domain = completion_timer->domain;
160 container = container_of(timer, completion_timer_t, timer); 191 cpu = completion_timer->cpu;
161 domain = container->domain;
162 192
163 raw_spin_lock_irqsave(domain->timer_lock, flags); 193 raw_spin_lock_irqsave(domain->timer_lock, flags);
164 194
165 server = domain->running[cpu]; 195 _TRACE_TIMER("completion timer firing on P%d");
166 TRACE_TIMER(server, "completion timer firing on P%d, remaining budget: %llu",
167 cpu, server->budget);
168 196
169 /* We got the lock before someone tried to re-arm. Proceed. */ 197 /* We got the lock before someone tried to re-arm. Proceed. */
170 if (domain->completion_timers[cpu].armed) { 198 if (completion_timer->armed) {
199 server = domain->running[cpu];
171 TRACE_SUB(server, "completed"); 200 TRACE_SUB(server, "completed");
201
172 was_running = server->scheduled; 202 was_running = server->scheduled;
173 203
174 server->budget = 0; 204 server->budget = 0;
@@ -183,13 +213,17 @@ static enum hrtimer_restart completion_timer_fire(struct hrtimer *timer)
183 /* Someone either beat us to the lock or hooked up a new server 213 /* Someone either beat us to the lock or hooked up a new server
184 * when we called server_completed. Rearm the timer. 214 * when we called server_completed. Rearm the timer.
185 */ 215 */
186 if (domain->running[cpu] && !domain->completion_timers[cpu].armed) { 216 if (domain->running[cpu] && !completion_timer->armed) {
187 TRACE_SUB(server, "rearming on P%d", cpu);
188 server = domain->running[cpu]; 217 server = domain->running[cpu];
218 TRACE_SUB(server, "rearming on P%d", cpu);
189 budget_exhausted = server->start_time + server->budget; 219 budget_exhausted = server->start_time + server->budget;
190 hrtimer_set_expires(timer, ns_to_ktime(budget_exhausted)); 220 hrtimer_set_expires(timer, ns_to_ktime(budget_exhausted));
191 domain->completion_timers[cpu].armed = 1; 221 completion_timer->armed = 1;
192 rv = HRTIMER_RESTART; 222 rv = HRTIMER_RESTART;
223 } else {
224 atomic_set(&completion_timer->info.state,
225 HRTIMER_START_ON_INACTIVE);
226
193 } 227 }
194 228
195 raw_spin_unlock_irqrestore(domain->timer_lock, flags); 229 raw_spin_unlock_irqrestore(domain->timer_lock, flags);
@@ -197,83 +231,48 @@ static enum hrtimer_restart completion_timer_fire(struct hrtimer *timer)
197 return rv; 231 return rv;
198} 232}
199 233
200static enum hrtimer_restart release_timer_fire(struct hrtimer *timer) 234struct kmem_cache *server_release_cache; /* In litmus.c */
201{ 235static enum hrtimer_restart release_servers_fire(struct hrtimer *timer);
202 unsigned long flags;
203 int was_running;
204 pserver_t *server = container_of(timer, pserver_t, release_timer);
205 struct task_struct *was_scheduled;
206
207 if (server->server.timer_lock)
208 raw_spin_lock_irqsave(server->server.timer_lock, flags);
209 else
210 local_irq_save(flags);
211
212 was_scheduled = server->server.scheduled;
213
214 TRACE_TIMER(&server->server,
215 "release timer firing, remaining budget: %llu",
216 get_server_budget(server));
217
218 was_running = server->server.running;
219
220 /* This would have been armed if the budget would exhaust
221 * after the server release.
222 */
223 if (was_running)
224 timer_cancel(&server->server.domain->completion_timers[
225 server->server.scheduled->rt_param.linked_on].timer);
226
227
228 pserver_release(server);
229 server->post_release(server);
230
231 /* Need to arm the budget timer if the server continues running
232 * the same task.
233 */
234 if (was_running && was_scheduled == get_server_scheduled(server))
235 completion_timer_arm(server->server.domain, was_scheduled->rt_param.linked_on );
236
237 hrtimer_set_expires(timer, ns_to_ktime(server->deadline));
238
239 if (server->server.timer_lock)
240 raw_spin_unlock_irqrestore(server->server.timer_lock, flags);
241 else
242 local_irq_restore(flags);
243 236
244 return HRTIMER_RESTART; 237/*
238 * Initialize heap.
239 */
240static server_release_heap_t* release_heap_alloc(int gfp_flags)
241{
242 server_release_heap_t *rh;
243 rh = kmem_cache_alloc(server_release_cache, gfp_flags);
244 if (rh) {
245 hrtimer_init(&rh->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
246 rh->timer.function = release_servers_fire;
247 }
248 return rh;
245} 249}
246 250
247void server_init(server_t *server, int id, raw_spinlock_t *timer_lock) 251void server_init(server_t *server, int id, lt_t wcet, lt_t period, int grouped)
248{ 252{
249 server->id = id; 253 server->id = id;
254 server->wcet = wcet;
255 server->period = period;
250 256
251 server->running = 0; 257 server->deadline = 0;
252 server->budget = 0; 258 server->release = 0;
253 server->job_no = 1; /* NOT SURE */ 259 server->budget = 0;
254 server->start_time = 0; 260 server->start_time = 0;
255 server->scheduled = NULL;
256 server->timer_lock = timer_lock;
257}
258 261
259void pserver_init(pserver_t *server, int id, raw_spinlock_t *timer_lock, 262 server->running = 0;
260 lt_t wcet, lt_t period) 263 server->job_no = 0;
261{ 264 server->scheduled = NULL;
262 server_init(&server->server, id, timer_lock);
263
264 server->wcet = wcet;
265 server->period = period;
266 265
267 server->deadline = 0; 266 server->hn = kmalloc(sizeof(struct bheap_node), GFP_ATOMIC);
268 server->post_release = NULL; 267 bheap_node_init(&server->hn, server);
268 INIT_LIST_HEAD(&server->list);
269 269
270 hrtimer_init(&server->release_timer, 270 if (grouped) {
271 CLOCK_MONOTONIC, 271 server->release_heap = release_heap_alloc(GFP_ATOMIC);
272 HRTIMER_MODE_ABS); 272 INIT_LIST_HEAD(&server->release_list);
273 server->release_timer.function = release_timer_fire; 273 }
274} 274}
275 275
276
277/* 276/*
278 * Handles subtraction of lt_t without underflows. 277 * Handles subtraction of lt_t without underflows.
279 */ 278 */
@@ -297,75 +296,62 @@ void server_stop(server_t *server, server_domain_t *domain)
297 } 296 }
298 297
299 BUG_ON(!server->running); 298 BUG_ON(!server->running);
300 cpu = server->scheduled->rt_param.linked_on;
301
302 TRACE_SUB(server, "stopping server, start: %llu, end: %llu", 299 TRACE_SUB(server, "stopping server, start: %llu, end: %llu",
303 server->start_time, now); 300 server->start_time, now);
304 301
302
303 /* Calculate remaining budget */
305 elapsed_time = lt_subtract(now, server->start_time); 304 elapsed_time = lt_subtract(now, server->start_time);
306 server->budget -= elapsed_time; 305 server->budget -= elapsed_time;
307 306
307 TRACE_SUB(server, "new budget: %llu", TIME(server->budget));
308
309 /* Set domain state */
310 cpu = server->scheduled->rt_param.linked_on;
308 domain->completion_timers[cpu].armed = 0; 311 domain->completion_timers[cpu].armed = 0;
309 domain->running[cpu] = NULL; 312 domain->running[cpu] = NULL;
310 timer_cancel(&domain->completion_timers[cpu].timer); 313 timer_cancel(&domain->completion_timers[cpu].timer);
311 314
312 TRACE_SUB(server, "new budget: %llu", TIME(server->budget)); 315 /* Make server inactive */
313 316 server->running = 0;
314 server->running = 0; 317 server->scheduled = NULL;
315 server->scheduled = NULL;
316 server->start_time = 0; 318 server->start_time = 0;
317} 319}
318 320
319void pserver_start_releasing(pserver_t *server, lt_t time) 321void server_release(server_t *server)
320{ 322{
321 if (hrtimer_active(&server->release_timer)) 323 BUG_ON(!server->deadline);
322 timer_cancel(&server->release_timer);
323 324
324 server->deadline = time; 325 server->budget = server->wcet;
325 pserver_release(server); 326 server->release = server->deadline;
326 327 server->deadline += server->period;
327 __hrtimer_start_range_ns(&server->release_timer, 328 ++server->job_no;
328 ns_to_ktime(server->deadline),
329 0 /* delta */,
330 HRTIMER_MODE_ABS_PINNED,
331 0 /* no wakeup */);
332}
333
334void pserver_start_cpu_releasing(pserver_t *server, lt_t time, int cpu)
335{
336 if (hrtimer_active(&server->release_timer))
337 timer_cancel(&server->release_timer);
338
339 server->deadline = time;
340 pserver_release(server);
341 329
342 hrtimer_start_on_info_init(&per_cpu(server_cpu_infos, cpu)); 330 TRACE_SUB(server, "budget: %llu, release: %llu,"
331 "deadline: %llu, period: %llu, job: %d",
332 server->budget, server->release, server->deadline,
333 server->period, server->job_no);
334 TRACE_SUB(server, "budget: %llu, release: %llu,"
335 "deadline: %llu, period: %llu, job: %d",
336 TIME(server->budget), TIME(server->release), TIME(server->deadline),
337 TIME(server->period), server->job_no);
343 338
344 hrtimer_start_on(cpu, &per_cpu(server_cpu_infos, cpu), 339 /* Need to reset for budget calculations */
345 &server->release_timer, 340 if (server->running)
346 ns_to_ktime(server->deadline), 341 server->start_time = litmus_clock();
347 HRTIMER_MODE_ABS_PINNED);
348} 342}
349 343
350void pserver_stop_releasing(pserver_t *server) 344void server_release_at(server_t *server, lt_t time)
351{ 345{
352 if (hrtimer_active(&server->release_timer)) 346 server->deadline = time;
353 timer_cancel(&server->release_timer); 347 server_release(server);
354
355 BUG_ON(get_server_running(server));
356 348
357 server->deadline = 0; 349 TRACE_SUB(server, "releasing at %llu", time);
358} 350}
359 351
360void server_release(server_t *server, lt_t budget) 352/******************************************************************************
361{ 353 * Proc methods
362 server->budget = budget; 354 ******************************************************************************/
363 ++server->job_no;
364
365 /* Need to reset for budget calculations */
366 if (server->running)
367 server->start_time = litmus_clock();
368}
369 355
370static int server_proc_read(char* page, char **start, off_t off, 356static int server_proc_read(char* page, char **start, off_t off,
371 int count, int *eof, void *data) 357 int count, int *eof, void *data)
@@ -386,25 +372,21 @@ static int server_proc_read(char* page, char **start, off_t off,
386 return length; 372 return length;
387} 373}
388 374
389void server_proc_read_single(pserver_t *server, int cpu, 375void server_proc_read_single(server_t *server, int cpu,
390 struct proc_read_args *args) 376 struct proc_read_args *args)
391{ 377{
392 lt_t wcet, period;
393 wcet = get_server_wcet(server);
394 period = get_server_period(server);
395
396 if (cpu == NO_CPU) { 378 if (cpu == NO_CPU) {
397 args->length += 379 args->length +=
398 snprintf(args->page + args->length, 380 snprintf(args->page + args->length,
399 PAGE_SIZE - args->length, 381 PAGE_SIZE - args->length,
400 "%8llu %8llu\n", 382 "%8llu %8llu\n",
401 TIME(wcet), TIME(period)); 383 server->wcet, server->period);
402 } else { 384 } else {
403 args->length += 385 args->length +=
404 snprintf(args->page + args->length, 386 snprintf(args->page + args->length,
405 PAGE_SIZE - args->length, 387 PAGE_SIZE - args->length,
406 "%8llu %8llu %3d\n", 388 "%8llu %8llu %3d\n",
407 TIME(wcet), TIME(period), cpu); 389 server->wcet, server->period, cpu);
408 } 390 }
409} 391}
410 392
@@ -509,8 +491,7 @@ static int server_proc_write(struct file *file, const char __user *input,
509 ret = server_param_check(wcet, period, cpu); 491 ret = server_param_check(wcet, period, cpu);
510 if (ret) goto loop_end; 492 if (ret) goto loop_end;
511 493
512 ret = methods->admit_server(wcet * NSEC_PER_MSEC, 494 ret = methods->admit_server(wcet, period, cpu);
513 period * NSEC_PER_MSEC, cpu);
514 if (ret) { 495 if (ret) {
515 printk(KERN_WARNING "Litmus plugin rejects server with " 496 printk(KERN_WARNING "Litmus plugin rejects server with "
516 "period: %llu, wcet: %llu, cpu: %d\n", 497 "period: %llu, wcet: %llu, cpu: %d\n",
@@ -559,6 +540,10 @@ void server_proc_exit(struct proc_dir_entry *proc_dir, char *file)
559 remove_proc_entry(file, proc_dir); 540 remove_proc_entry(file, proc_dir);
560} 541}
561 542
543/******************************************************************************
544 * Domain methods
545 ******************************************************************************/
546
562void server_domain_init(server_domain_t *domain, 547void server_domain_init(server_domain_t *domain,
563 servers_released_t servers_released, 548 servers_released_t servers_released,
564 server_completed_t server_completed, 549 server_completed_t server_completed,
@@ -575,7 +560,7 @@ void server_domain_init(server_domain_t *domain,
575 raw_spin_lock_init(&domain->tobe_lock); 560 raw_spin_lock_init(&domain->tobe_lock);
576 561
577 562
578 domain->release_master = NO_CPU; 563 domain->release_master = release_master;
579 domain->timer_lock = timer_lock; 564 domain->timer_lock = timer_lock;
580 domain->server_completed = server_completed; 565 domain->server_completed = server_completed;
581 domain->servers_released = servers_released; 566 domain->servers_released = servers_released;
@@ -587,6 +572,7 @@ void server_domain_init(server_domain_t *domain,
587 for_each_online_cpu(i) { 572 for_each_online_cpu(i) {
588 domain->running[i] = NULL; 573 domain->running[i] = NULL;
589 domain->completion_timers[i].armed = 0; 574 domain->completion_timers[i].armed = 0;
575 domain->completion_timers[i].cpu = i;
590 hrtimer_init(&domain->completion_timers[i].timer, 576 hrtimer_init(&domain->completion_timers[i].timer,
591 CLOCK_MONOTONIC, 577 CLOCK_MONOTONIC,
592 HRTIMER_MODE_ABS); 578 HRTIMER_MODE_ABS);
@@ -603,13 +589,212 @@ void server_domain_exit(server_domain_t *domain)
603 kfree(domain->running); 589 kfree(domain->running);
604} 590}
605 591
606void add_server_release(server_t *server, server_domain_t *server_domain) 592static unsigned int time2slot(lt_t time)
593{
594 return (unsigned int) time2quanta(time, FLOOR) %
595 SERVER_RELEASE_QUEUE_SLOTS;
596}
597
598/*
599 * Send a list of servers to a client callback.
600 */
601static enum hrtimer_restart release_servers_fire(struct hrtimer *timer)
602{
603 unsigned long flags;
604 server_release_heap_t *rh;
605
606 _TRACE_SUB("on_release_timer(0x%p) starts.", timer);
607
608 rh = container_of(timer, server_release_heap_t, timer);
609
610 raw_spin_lock_irqsave(&rh->domain->release_lock, flags);
611 _TRACE_SUB("CB has the release_lock");
612
613 /* Remove from release queue */
614 list_del(&rh->list);
615
616 raw_spin_unlock_irqrestore(&rh->domain->release_lock, flags);
617 _TRACE_SUB("CB returned release_lock");
618
619 /* Call release callback */
620 rh->domain->servers_released(&rh->servers);
621 /* WARNING: rh can be referenced from other CPUs from now on. */
622
623 _TRACE_SUB("on_release_timer(0x%p) ends.", timer);
624
625 return HRTIMER_NORESTART;
626}
627
628/*
629 * Caller must hold release lock.
630 * Will return heap for given time. If no such heap exists prior to
631 * the invocation it will be created.
632 */
633static server_release_heap_t* get_release_heap(server_domain_t *rt,
634 server_t *server,
635 int use_server_heap)
636{
637 struct list_head *pos;
638 server_release_heap_t *heap = NULL;
639 server_release_heap_t *rh;
640 lt_t release_time = server->release;
641 unsigned int slot = time2slot(release_time);
642
643 _TRACE_SUB("searching for release time %llu", release_time);
644
645 /* Initialize pos for the case that the list is empty */
646 pos = rt->release_queue[slot].next;
647 list_for_each(pos, &rt->release_queue[slot]) {
648 rh = list_entry(pos, server_release_heap_t, list);
649 if (release_time == rh->release_time) {
650 /* Perfect match -- this happens on hyperperiod
651 * boundaries
652 */
653 heap = rh;
654 break;
655 } else if (lt_before(release_time, rh->release_time)) {
656 /* We need to insert a new node since rh is
657 * already in the future
658 */
659 break;
660 }
661 }
662 if (!heap && use_server_heap) {
663 /* Use pre-allocated release heap */
664 rh = server->release_heap;
665 rh->domain = rt;
666 rh->release_time = release_time;
667
668 /* Add to release queue */
669 list_add(&rh->list, pos->prev);
670 heap = rh;
671 }
672 return heap;
673}
674
675/*
676 * Prepare a server's release_heap for use.
677 */
678static int reinit_release_heap(server_t *server)
607{ 679{
608 TRACE_SUB(server, "adding to release"); 680 int rv = 0;
681 server_release_heap_t* rh;
682
683 /* Use pre-allocated release heap */
684 rh = server->release_heap;
685
686 /* WARNING: If the CPU still holds the release_lock at this point,
687 * deadlock may occur!
688 */
689 rv = hrtimer_try_to_cancel(&rh->timer);
690
691 /* The timer callback is running, it is useless to add
692 * to the release heap now.
693 */
694 if (rv == -1) {
695 rv = 0;
696 goto out;
697 }
698
699 /* Under no cirumstances should the timer have been active
700 * but not running.
701 */
702 /* TODO: stop living dangerously */
703 //BUG_ON(rv == 1);
704 rv = 1;
705
706 /* initialize */
707 INIT_LIST_HEAD(&rh->servers);
708 atomic_set(&rh->info.state, HRTIMER_START_ON_INACTIVE);
709 out:
710 return rv;
609} 711}
610 712
611void stop_server_releasing(server_domain_t *server_domain) 713/*
714 * Arm the release timer for the next set of servers.
715 */
716static int arm_release_timer(server_domain_t *domain)
612{ 717{
718 int rv = 1;
719 struct list_head list;
720 struct list_head *pos, *safe;
721 server_t *server;
722 server_release_heap_t *rh;
723
724 _TRACE_SUB("arm_release_timer() at %llu", litmus_clock());
725 list_replace_init(&domain->tobe_released, &list);
726
727 list_for_each_safe(pos, safe, &list) {
728 /* Pick server from work list */
729 server = list_entry(pos, server_t, release_list);
730 list_del(pos);
731
732 /* Put into release heap while holding release_lock */
733 raw_spin_lock(&domain->release_lock);
734 TRACE_SUB(server, "I have the release_lock");
735
736 rh = get_release_heap(domain, server, 0);
737 if (!rh) {
738 /* Need to use our own, but drop lock first */
739 raw_spin_unlock(&domain->release_lock);
740 TRACE_SUB(server, "Dropped release_lock");
741
742 rv = reinit_release_heap(server);
743
744 /* Bail! We missed the release time */
745 if (!rv) {
746 TRACE_SUB(server, "missed release");
747 rv = 0;
748 goto out;
749 }
750
751 TRACE_SUB(server, "release_heap ready");
752
753 raw_spin_lock(&domain->release_lock);
754 TRACE_SUB(server, "Re-acquired release_lock");
613 755
756 rh = get_release_heap(domain, server, 1);
757 }
758
759 list_add(&server->release_list, &rh->servers);
760 TRACE_SUB(server, "arm_release_timer(): added to release heap");
761
762 raw_spin_unlock(&domain->release_lock);
763 TRACE_SUB(server, "Returned the release_lock");
764
765 /* To avoid arming the timer multiple times, we only let the
766 * owner do the arming (which is the "first" task to reference
767 * this release_heap anyway).
768 */
769 if (rh == server->release_heap) {
770 TRACE_SUB(server, "arming timer 0x%p at %llu on P%d",
771 &rh->timer, rh->release_time,
772 domain->release_master);
773 /* We cannot arm the timer using hrtimer_start()
774 * as it may deadlock on rq->lock
775 *
776 * PINNED mode is ok on both local and remote CPU
777 */
778 if (domain->release_master == NO_CPU) {
779 __hrtimer_start_range_ns(&rh->timer,
780 ns_to_ktime(rh->release_time),
781 0, HRTIMER_MODE_ABS_PINNED, 0);
782 } else {
783 hrtimer_start_on(domain->release_master,
784 &rh->info, &rh->timer,
785 ns_to_ktime(rh->release_time),
786 HRTIMER_MODE_ABS_PINNED);
787 }
788 } else
789 TRACE_SUB(server, "0x%p is not my timer", &rh->timer);
790 }
791 out:
792 return rv;
614} 793}
615 794
795int add_server_release(server_t *server, server_domain_t *domain)
796{
797 TRACE_SUB(server, "adding to release at %llu", server->release);
798 list_add(&server->release_list, &domain->tobe_released);
799 return arm_release_timer(domain);
800}