1 /******************************************************************************
2 * sched_arinc653.c
3 *
4 * An ARINC653-compatible scheduling algorithm for use in Xen.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Copyright (c) 2010, DornerWorks, Ltd. <DornerWorks.com>
25 */
26
27 #include <xen/lib.h>
28 #include <xen/sched.h>
29 #include <xen/timer.h>
30 #include <xen/softirq.h>
31 #include <xen/time.h>
32 #include <xen/errno.h>
33 #include <xen/list.h>
34 #include <xen/guest_access.h>
35 #include <public/sysctl.h>
36
37 #include "private.h"
38
39 /**************************************************************************
40 * Private Macros *
41 **************************************************************************/
42
43 /**
44 * Default timeslice for domain 0.
45 */
46 #define DEFAULT_TIMESLICE MILLISECS(10)
47
48 /**
49 * Retrieve the idle UNIT for a given physical CPU
50 */
51 #define IDLETASK(cpu) (sched_idle_unit(cpu))
52
53 /**
54 * Return a pointer to the ARINC 653-specific scheduler data information
55 * associated with the given UNIT (unit)
56 */
57 #define AUNIT(unit) ((arinc653_unit_t *)(unit)->priv)
58
59 /**
60 * Return the global scheduler private data given the scheduler ops pointer
61 */
62 #define SCHED_PRIV(s) ((a653sched_priv_t *)((s)->sched_data))
63
64 /**************************************************************************
65 * Private Type Definitions *
66 **************************************************************************/
67
68 /**
69 * The arinc653_unit_t structure holds ARINC 653-scheduler-specific
70 * information for all non-idle UNITs
71 */
72 typedef struct arinc653_unit_s
73 {
74 /* unit points to Xen's struct sched_unit so we can get to it from an
75 * arinc653_unit_t pointer. */
76 struct sched_unit * unit;
77 /* awake holds whether the UNIT has been woken with vcpu_wake() */
78 bool awake;
79 /* list holds the linked list information for the list this UNIT
80 * is stored in */
81 struct list_head list;
82 } arinc653_unit_t;
83
84 /**
85 * The sched_entry_t structure holds a single entry of the
86 * ARINC 653 schedule.
87 */
88 typedef struct sched_entry_s
89 {
90 /* dom_handle holds the handle ("UUID") for the domain that this
91 * schedule entry refers to. */
92 xen_domain_handle_t dom_handle;
93 /* unit_id holds the UNIT number for the UNIT that this schedule
94 * entry refers to. */
95 int unit_id;
96 /* runtime holds the number of nanoseconds that the UNIT for this
97 * schedule entry should be allowed to run per major frame. */
98 s_time_t runtime;
99 /* unit holds a pointer to the Xen sched_unit structure */
100 struct sched_unit * unit;
101 } sched_entry_t;
102
103 /**
104 * This structure defines data that is global to an instance of the scheduler
105 */
106 typedef struct a653sched_priv_s
107 {
108 /* lock for the whole pluggable scheduler, nests inside cpupool_lock */
109 spinlock_t lock;
110
111 /**
112 * This array holds the active ARINC 653 schedule.
113 *
114 * When the system tries to start a new UNIT, this schedule is scanned
115 * to look for a matching (handle, UNIT #) pair. If both the handle (UUID)
116 * and UNIT number match, then the UNIT is allowed to run. Its run time
117 * (per major frame) is given in the third entry of the schedule.
118 */
119 sched_entry_t schedule[ARINC653_MAX_DOMAINS_PER_SCHEDULE];
120
121 /**
122 * This variable holds the number of entries that are valid in
123 * the arinc653_schedule table.
124 *
125 * This is not necessarily the same as the number of domains in the
126 * schedule. A domain could be listed multiple times within the schedule,
127 * or a domain with multiple UNITs could have a different
128 * schedule entry for each UNIT.
129 */
130 unsigned int num_schedule_entries;
131
132 /**
133 * the major frame time for the ARINC 653 schedule.
134 */
135 s_time_t major_frame;
136
137 /**
138 * the time that the next major frame starts
139 */
140 s_time_t next_major_frame;
141
142 /**
143 * pointers to all Xen UNIT structures for iterating through
144 */
145 struct list_head unit_list;
146 } a653sched_priv_t;
147
148 /**************************************************************************
149 * Helper functions *
150 **************************************************************************/
151
152 /**
153 * This function compares two domain handles.
154 *
155 * @param h1 Pointer to handle 1
156 * @param h2 Pointer to handle 2
157 *
158 * @return <ul>
159 * <li> <0: handle 1 is less than handle 2
160 * <li> 0: handle 1 is equal to handle 2
161 * <li> >0: handle 1 is greater than handle 2
162 * </ul>
163 */
dom_handle_cmp(const xen_domain_handle_t h1,const xen_domain_handle_t h2)164 static int dom_handle_cmp(const xen_domain_handle_t h1,
165 const xen_domain_handle_t h2)
166 {
167 return memcmp(h1, h2, sizeof(xen_domain_handle_t));
168 }
169
170 /**
171 * This function searches the unit list to find a UNIT that matches
172 * the domain handle and UNIT ID specified.
173 *
174 * @param ops Pointer to this instance of the scheduler structure
175 * @param handle Pointer to handler
176 * @param unit_id UNIT ID
177 *
178 * @return <ul>
179 * <li> Pointer to the matching UNIT if one is found
180 * <li> NULL otherwise
181 * </ul>
182 */
find_unit(const struct scheduler * ops,xen_domain_handle_t handle,int unit_id)183 static struct sched_unit *find_unit(
184 const struct scheduler *ops,
185 xen_domain_handle_t handle,
186 int unit_id)
187 {
188 arinc653_unit_t *aunit;
189
190 /* loop through the unit_list looking for the specified UNIT */
191 list_for_each_entry ( aunit, &SCHED_PRIV(ops)->unit_list, list )
192 if ( (dom_handle_cmp(aunit->unit->domain->handle, handle) == 0)
193 && (unit_id == aunit->unit->unit_id) )
194 return aunit->unit;
195
196 return NULL;
197 }
198
199 /**
200 * This function updates the pointer to the Xen UNIT structure for each entry
201 * in the ARINC 653 schedule.
202 *
203 * @param ops Pointer to this instance of the scheduler structure
204 * @return <None>
205 */
update_schedule_units(const struct scheduler * ops)206 static void update_schedule_units(const struct scheduler *ops)
207 {
208 unsigned int i, n_entries = SCHED_PRIV(ops)->num_schedule_entries;
209
210 for ( i = 0; i < n_entries; i++ )
211 SCHED_PRIV(ops)->schedule[i].unit =
212 find_unit(ops,
213 SCHED_PRIV(ops)->schedule[i].dom_handle,
214 SCHED_PRIV(ops)->schedule[i].unit_id);
215 }
216
217 /**
218 * This function is called by the adjust_global scheduler hook to put
219 * in place a new ARINC653 schedule.
220 *
221 * @param ops Pointer to this instance of the scheduler structure
222 *
223 * @return <ul>
224 * <li> 0 = success
225 * <li> !0 = error
226 * </ul>
227 */
228 static int
arinc653_sched_set(const struct scheduler * ops,struct xen_sysctl_arinc653_schedule * schedule)229 arinc653_sched_set(
230 const struct scheduler *ops,
231 struct xen_sysctl_arinc653_schedule *schedule)
232 {
233 a653sched_priv_t *sched_priv = SCHED_PRIV(ops);
234 s_time_t total_runtime = 0;
235 unsigned int i;
236 unsigned long flags;
237 int rc = -EINVAL;
238
239 spin_lock_irqsave(&sched_priv->lock, flags);
240
241 /* Check for valid major frame and number of schedule entries. */
242 if ( (schedule->major_frame <= 0)
243 || (schedule->num_sched_entries < 1)
244 || (schedule->num_sched_entries > ARINC653_MAX_DOMAINS_PER_SCHEDULE) )
245 goto fail;
246
247 for ( i = 0; i < schedule->num_sched_entries; i++ )
248 {
249 /* Check for a valid run time. */
250 if ( schedule->sched_entries[i].runtime <= 0 )
251 goto fail;
252
253 /* Add this entry's run time to total run time. */
254 total_runtime += schedule->sched_entries[i].runtime;
255 }
256
257 /*
258 * Error if the major frame is not large enough to run all entries as
259 * indicated by comparing the total run time to the major frame length.
260 */
261 if ( total_runtime > schedule->major_frame )
262 goto fail;
263
264 /* Copy the new schedule into place. */
265 sched_priv->num_schedule_entries = schedule->num_sched_entries;
266 sched_priv->major_frame = schedule->major_frame;
267 for ( i = 0; i < schedule->num_sched_entries; i++ )
268 {
269 memcpy(sched_priv->schedule[i].dom_handle,
270 schedule->sched_entries[i].dom_handle,
271 sizeof(sched_priv->schedule[i].dom_handle));
272 sched_priv->schedule[i].unit_id =
273 schedule->sched_entries[i].vcpu_id;
274 sched_priv->schedule[i].runtime =
275 schedule->sched_entries[i].runtime;
276 }
277 update_schedule_units(ops);
278
279 /*
280 * The newly-installed schedule takes effect immediately. We do not even
281 * wait for the current major frame to expire.
282 *
283 * Signal a new major frame to begin. The next major frame is set up by
284 * the do_schedule callback function when it is next invoked.
285 */
286 sched_priv->next_major_frame = NOW();
287
288 rc = 0;
289
290 fail:
291 spin_unlock_irqrestore(&sched_priv->lock, flags);
292 return rc;
293 }
294
295 /**
296 * This function is called by the adjust_global scheduler hook to read the
297 * current ARINC 653 schedule
298 *
299 * @param ops Pointer to this instance of the scheduler structure
300 * @return <ul>
301 * <li> 0 = success
302 * <li> !0 = error
303 * </ul>
304 */
305 static int
arinc653_sched_get(const struct scheduler * ops,struct xen_sysctl_arinc653_schedule * schedule)306 arinc653_sched_get(
307 const struct scheduler *ops,
308 struct xen_sysctl_arinc653_schedule *schedule)
309 {
310 a653sched_priv_t *sched_priv = SCHED_PRIV(ops);
311 unsigned int i;
312 unsigned long flags;
313
314 spin_lock_irqsave(&sched_priv->lock, flags);
315
316 schedule->num_sched_entries = sched_priv->num_schedule_entries;
317 schedule->major_frame = sched_priv->major_frame;
318 for ( i = 0; i < sched_priv->num_schedule_entries; i++ )
319 {
320 memcpy(schedule->sched_entries[i].dom_handle,
321 sched_priv->schedule[i].dom_handle,
322 sizeof(sched_priv->schedule[i].dom_handle));
323 schedule->sched_entries[i].vcpu_id = sched_priv->schedule[i].unit_id;
324 schedule->sched_entries[i].runtime = sched_priv->schedule[i].runtime;
325 }
326
327 spin_unlock_irqrestore(&sched_priv->lock, flags);
328
329 return 0;
330 }
331
332 /**************************************************************************
333 * Scheduler callback functions *
334 **************************************************************************/
335
336 /**
337 * This function performs initialization for an instance of the scheduler.
338 *
339 * @param ops Pointer to this instance of the scheduler structure
340 *
341 * @return <ul>
342 * <li> 0 = success
343 * <li> !0 = error
344 * </ul>
345 */
346 static int
a653sched_init(struct scheduler * ops)347 a653sched_init(struct scheduler *ops)
348 {
349 a653sched_priv_t *prv;
350
351 prv = xzalloc(a653sched_priv_t);
352 if ( prv == NULL )
353 return -ENOMEM;
354
355 ops->sched_data = prv;
356
357 prv->next_major_frame = 0;
358 spin_lock_init(&prv->lock);
359 INIT_LIST_HEAD(&prv->unit_list);
360
361 return 0;
362 }
363
364 /**
365 * This function performs deinitialization for an instance of the scheduler
366 *
367 * @param ops Pointer to this instance of the scheduler structure
368 */
369 static void
a653sched_deinit(struct scheduler * ops)370 a653sched_deinit(struct scheduler *ops)
371 {
372 xfree(SCHED_PRIV(ops));
373 ops->sched_data = NULL;
374 }
375
376 /**
377 * This function allocates scheduler-specific data for a UNIT
378 *
379 * @param ops Pointer to this instance of the scheduler structure
380 * @param unit Pointer to struct sched_unit
381 *
382 * @return Pointer to the allocated data
383 */
384 static void *
a653sched_alloc_udata(const struct scheduler * ops,struct sched_unit * unit,void * dd)385 a653sched_alloc_udata(const struct scheduler *ops, struct sched_unit *unit,
386 void *dd)
387 {
388 a653sched_priv_t *sched_priv = SCHED_PRIV(ops);
389 arinc653_unit_t *svc;
390 unsigned int entry;
391 unsigned long flags;
392
393 /*
394 * Allocate memory for the ARINC 653-specific scheduler data information
395 * associated with the given UNIT (unit).
396 */
397 svc = xmalloc(arinc653_unit_t);
398 if ( svc == NULL )
399 return NULL;
400
401 spin_lock_irqsave(&sched_priv->lock, flags);
402
403 /*
404 * Add every one of dom0's units to the schedule, as long as there are
405 * slots available.
406 */
407 if ( unit->domain->domain_id == 0 )
408 {
409 entry = sched_priv->num_schedule_entries;
410
411 if ( entry < ARINC653_MAX_DOMAINS_PER_SCHEDULE )
412 {
413 sched_priv->schedule[entry].dom_handle[0] = '\0';
414 sched_priv->schedule[entry].unit_id = unit->unit_id;
415 sched_priv->schedule[entry].runtime = DEFAULT_TIMESLICE;
416 sched_priv->schedule[entry].unit = unit;
417
418 sched_priv->major_frame += DEFAULT_TIMESLICE;
419 ++sched_priv->num_schedule_entries;
420 }
421 }
422
423 /*
424 * Initialize our ARINC 653 scheduler-specific information for the UNIT.
425 * The UNIT starts "asleep." When Xen is ready for the UNIT to run, it
426 * will call the vcpu_wake scheduler callback function and our scheduler
427 * will mark the UNIT awake.
428 */
429 svc->unit = unit;
430 svc->awake = false;
431 if ( !is_idle_unit(unit) )
432 list_add(&svc->list, &SCHED_PRIV(ops)->unit_list);
433 update_schedule_units(ops);
434
435 spin_unlock_irqrestore(&sched_priv->lock, flags);
436
437 return svc;
438 }
439
440 /**
441 * This function frees scheduler-specific UNIT data
442 *
443 * @param ops Pointer to this instance of the scheduler structure
444 */
445 static void
a653sched_free_udata(const struct scheduler * ops,void * priv)446 a653sched_free_udata(const struct scheduler *ops, void *priv)
447 {
448 a653sched_priv_t *sched_priv = SCHED_PRIV(ops);
449 arinc653_unit_t *av = priv;
450 unsigned long flags;
451
452 if (av == NULL)
453 return;
454
455 spin_lock_irqsave(&sched_priv->lock, flags);
456
457 if ( !is_idle_unit(av->unit) )
458 list_del(&av->list);
459
460 xfree(av);
461 update_schedule_units(ops);
462
463 spin_unlock_irqrestore(&sched_priv->lock, flags);
464 }
465
466 /**
467 * Xen scheduler callback function to sleep a UNIT
468 *
469 * @param ops Pointer to this instance of the scheduler structure
470 * @param unit Pointer to struct sched_unit
471 */
472 static void
a653sched_unit_sleep(const struct scheduler * ops,struct sched_unit * unit)473 a653sched_unit_sleep(const struct scheduler *ops, struct sched_unit *unit)
474 {
475 if ( AUNIT(unit) != NULL )
476 AUNIT(unit)->awake = false;
477
478 /*
479 * If the UNIT being put to sleep is the same one that is currently
480 * running, raise a softirq to invoke the scheduler to switch domains.
481 */
482 if ( get_sched_res(sched_unit_master(unit))->curr == unit )
483 cpu_raise_softirq(sched_unit_master(unit), SCHEDULE_SOFTIRQ);
484 }
485
486 /**
487 * Xen scheduler callback function to wake up a UNIT
488 *
489 * @param ops Pointer to this instance of the scheduler structure
490 * @param unit Pointer to struct sched_unit
491 */
492 static void
a653sched_unit_wake(const struct scheduler * ops,struct sched_unit * unit)493 a653sched_unit_wake(const struct scheduler *ops, struct sched_unit *unit)
494 {
495 if ( AUNIT(unit) != NULL )
496 AUNIT(unit)->awake = true;
497
498 cpu_raise_softirq(sched_unit_master(unit), SCHEDULE_SOFTIRQ);
499 }
500
501 /**
502 * Xen scheduler callback function to select a UNIT to run.
503 * This is the main scheduler routine.
504 *
505 * @param ops Pointer to this instance of the scheduler structure
506 * @param now Current time
507 */
508 static void
a653sched_do_schedule(const struct scheduler * ops,struct sched_unit * prev,s_time_t now,bool tasklet_work_scheduled)509 a653sched_do_schedule(
510 const struct scheduler *ops,
511 struct sched_unit *prev,
512 s_time_t now,
513 bool tasklet_work_scheduled)
514 {
515 struct sched_unit *new_task = NULL;
516 static unsigned int sched_index = 0;
517 static s_time_t next_switch_time;
518 a653sched_priv_t *sched_priv = SCHED_PRIV(ops);
519 const unsigned int cpu = sched_get_resource_cpu(smp_processor_id());
520 unsigned long flags;
521
522 spin_lock_irqsave(&sched_priv->lock, flags);
523
524 if ( sched_priv->num_schedule_entries < 1 )
525 sched_priv->next_major_frame = now + DEFAULT_TIMESLICE;
526 else if ( now >= sched_priv->next_major_frame )
527 {
528 /* time to enter a new major frame
529 * the first time this function is called, this will be true */
530 /* start with the first domain in the schedule */
531 sched_index = 0;
532 sched_priv->next_major_frame = now + sched_priv->major_frame;
533 next_switch_time = now + sched_priv->schedule[0].runtime;
534 }
535 else
536 {
537 while ( (now >= next_switch_time)
538 && (sched_index < sched_priv->num_schedule_entries) )
539 {
540 /* time to switch to the next domain in this major frame */
541 sched_index++;
542 next_switch_time += sched_priv->schedule[sched_index].runtime;
543 }
544 }
545
546 /*
547 * If we exhausted the domains in the schedule and still have time left
548 * in the major frame then switch next at the next major frame.
549 */
550 if ( sched_index >= sched_priv->num_schedule_entries )
551 next_switch_time = sched_priv->next_major_frame;
552
553 /*
554 * If there are more domains to run in the current major frame, set
555 * new_task equal to the address of next domain's sched_unit structure.
556 * Otherwise, set new_task equal to the address of the idle task's
557 * sched_unit structure.
558 */
559 new_task = (sched_index < sched_priv->num_schedule_entries)
560 ? sched_priv->schedule[sched_index].unit
561 : IDLETASK(cpu);
562
563 /* Check to see if the new task can be run (awake & runnable). */
564 if ( !((new_task != NULL)
565 && (AUNIT(new_task) != NULL)
566 && AUNIT(new_task)->awake
567 && unit_runnable_state(new_task)) )
568 new_task = IDLETASK(cpu);
569 BUG_ON(new_task == NULL);
570
571 /*
572 * Check to make sure we did not miss a major frame.
573 * This is a good test for robust partitioning.
574 */
575 BUG_ON(now >= sched_priv->next_major_frame);
576
577 spin_unlock_irqrestore(&sched_priv->lock, flags);
578
579 /* Tasklet work (which runs in idle UNIT context) overrides all else. */
580 if ( tasklet_work_scheduled )
581 new_task = IDLETASK(cpu);
582
583 /* Running this task would result in a migration */
584 if ( !is_idle_unit(new_task)
585 && (sched_unit_master(new_task) != cpu) )
586 new_task = IDLETASK(cpu);
587
588 /*
589 * Return the amount of time the next domain has to run and the address
590 * of the selected task's UNIT structure.
591 */
592 prev->next_time = next_switch_time - now;
593 prev->next_task = new_task;
594 new_task->migrated = false;
595
596 BUG_ON(prev->next_time <= 0);
597 }
598
599 /**
600 * Xen scheduler callback function to select a resource for the UNIT to run on
601 *
602 * @param ops Pointer to this instance of the scheduler structure
603 * @param unit Pointer to struct sched_unit
604 *
605 * @return Scheduler resource to run on
606 */
607 static struct sched_resource *
a653sched_pick_resource(const struct scheduler * ops,const struct sched_unit * unit)608 a653sched_pick_resource(const struct scheduler *ops,
609 const struct sched_unit *unit)
610 {
611 const cpumask_t *online;
612 unsigned int cpu;
613
614 /*
615 * If present, prefer unit's current processor, else
616 * just find the first valid unit.
617 */
618 online = cpupool_domain_master_cpumask(unit->domain);
619
620 cpu = cpumask_first(online);
621
622 if ( cpumask_test_cpu(sched_unit_master(unit), online)
623 || (cpu >= nr_cpu_ids) )
624 cpu = sched_unit_master(unit);
625
626 return get_sched_res(cpu);
627 }
628
629 /**
630 * Xen scheduler callback to change the scheduler of a cpu
631 *
632 * @param new_ops Pointer to this instance of the scheduler structure
633 * @param cpu The cpu that is changing scheduler
634 * @param pdata scheduler specific PCPU data (we don't have any)
635 * @param vdata scheduler specific UNIT data of the idle unit
636 */
637 static spinlock_t *
a653_switch_sched(struct scheduler * new_ops,unsigned int cpu,void * pdata,void * vdata)638 a653_switch_sched(struct scheduler *new_ops, unsigned int cpu,
639 void *pdata, void *vdata)
640 {
641 struct sched_resource *sr = get_sched_res(cpu);
642 const arinc653_unit_t *svc = vdata;
643
644 ASSERT(!pdata && svc && is_idle_unit(svc->unit));
645
646 sched_idle_unit(cpu)->priv = vdata;
647
648 return &sr->_lock;
649 }
650
651 /**
652 * Xen scheduler callback function to perform a global (not domain-specific)
653 * adjustment. It is used by the ARINC 653 scheduler to put in place a new
654 * ARINC 653 schedule or to retrieve the schedule currently in place.
655 *
656 * @param ops Pointer to this instance of the scheduler structure
657 * @param sc Pointer to the scheduler operation specified by Domain 0
658 */
659 static int
a653sched_adjust_global(const struct scheduler * ops,struct xen_sysctl_scheduler_op * sc)660 a653sched_adjust_global(const struct scheduler *ops,
661 struct xen_sysctl_scheduler_op *sc)
662 {
663 struct xen_sysctl_arinc653_schedule local_sched;
664 int rc = -EINVAL;
665
666 switch ( sc->cmd )
667 {
668 case XEN_SYSCTL_SCHEDOP_putinfo:
669 if ( copy_from_guest(&local_sched, sc->u.sched_arinc653.schedule, 1) )
670 {
671 rc = -EFAULT;
672 break;
673 }
674
675 rc = arinc653_sched_set(ops, &local_sched);
676 break;
677 case XEN_SYSCTL_SCHEDOP_getinfo:
678 memset(&local_sched, -1, sizeof(local_sched));
679 rc = arinc653_sched_get(ops, &local_sched);
680 if ( rc )
681 break;
682
683 if ( copy_to_guest(sc->u.sched_arinc653.schedule, &local_sched, 1) )
684 rc = -EFAULT;
685 break;
686 }
687
688 return rc;
689 }
690
691 /**
692 * This structure defines our scheduler for Xen.
693 * The entries tell Xen where to find our scheduler-specific
694 * callback functions.
695 * The symbol must be visible to the rest of Xen at link time.
696 */
697 static const struct scheduler sched_arinc653_def = {
698 .name = "ARINC 653 Scheduler",
699 .opt_name = "arinc653",
700 .sched_id = XEN_SCHEDULER_ARINC653,
701 .sched_data = NULL,
702
703 .init = a653sched_init,
704 .deinit = a653sched_deinit,
705
706 .free_udata = a653sched_free_udata,
707 .alloc_udata = a653sched_alloc_udata,
708
709 .insert_unit = NULL,
710 .remove_unit = NULL,
711
712 .sleep = a653sched_unit_sleep,
713 .wake = a653sched_unit_wake,
714 .yield = NULL,
715 .context_saved = NULL,
716
717 .do_schedule = a653sched_do_schedule,
718
719 .pick_resource = a653sched_pick_resource,
720
721 .switch_sched = a653_switch_sched,
722
723 .adjust = NULL,
724 .adjust_global = a653sched_adjust_global,
725
726 .dump_settings = NULL,
727 .dump_cpu_state = NULL,
728 };
729
730 REGISTER_SCHEDULER(sched_arinc653_def);
731
732 /*
733 * Local variables:
734 * mode: C
735 * c-file-style: "BSD"
736 * c-basic-offset: 4
737 * tab-width: 4
738 * indent-tabs-mode: nil
739 * End:
740 */
741