debuggers.hg

annotate xen/common/sched_atropos.c @ 3658:0ef6e8e6e85d

bitkeeper revision 1.1159.212.71 (4200f0afX_JumfbEHQex6TdFENULMQ)

Merge labyrinth.cl.cam.ac.uk:/auto/groups/xeno-xenod/BK/xen-unstable.bk
into labyrinth.cl.cam.ac.uk:/auto/groups/xeno/users/iap10/xeno-clone/xen-unstable.bk
author iap10@labyrinth.cl.cam.ac.uk
date Wed Feb 02 15:24:31 2005 +0000 (2005-02-02)
parents 51052c8b6456 f98fa170a9f4
children bbe8541361dd 4294cfa9fad3
rev   line source
mwilli2@1284 1 /*
kaf24@3568 2 * atropos.c
kaf24@3568 3 * ---------
mwilli2@1284 4 *
mwilli2@1284 5 * Copyright (c) 1994 University of Cambridge Computer Laboratory.
mwilli2@1284 6 * This is part of Nemesis; consult your contract for terms and conditions.
mwilli2@1284 7 *
mwilli2@1284 8 * ID : $Id: atropos.c 1.1 Tue, 13 Apr 1999 13:30:49 +0100 dr10009 $
mwilli2@1284 9 *
mwilli2@1284 10 * This is the "atropos" CPU scheduler.
mwilli2@1284 11 */
mwilli2@1284 12
mwilli2@1284 13 /* Ported to Xen's generic scheduler interface by Mark Williamson
mwilli2@1284 14 * these modifications are (C) 2004 Intel Research Cambridge
mwilli2@1284 15 */
mwilli2@1284 16
kaf24@1304 17 #include <xen/config.h>
kaf24@1304 18 #include <xen/init.h>
kaf24@1304 19 #include <xen/lib.h>
mwilli2@1284 20 #include <xen/time.h>
mwilli2@1284 21 #include <xen/sched.h>
mwilli2@1284 22 #include <xen/sched-if.h>
kaf24@2827 23 #include <public/sched_ctl.h>
mwilli2@1284 24 #include <xen/trace.h>
mwilli2@1284 25
mwilli2@1284 26 #define ATROPOS_TASK_UNBLOCKED 16
mwilli2@1284 27 #define ATROPOS_TASK_WAIT 32
gm281@2564 28 #define ATROPOS_TASK_BLOCKED 48
mwilli2@1284 29
mwilli2@1345 30 /* Atropos-specific per-domain data */
mwilli2@1284 31 struct at_dom_info
mwilli2@1284 32 {
mwilli2@1284 33 /* MAW Xen additions */
kaf24@1543 34 struct domain *owner; /* the domain this data belongs to */
gm281@2564 35 struct list_head run_list; /* runqueue */
kaf24@1304 36 struct list_head waitq; /* wait queue */
mwilli2@1284 37
mwilli2@1284 38 /* (what remains of) the original fields */
mwilli2@1284 39
mwilli2@1345 40 s_time_t deadline; /* Next deadline */
mwilli2@1345 41 s_time_t prevddln; /* Previous deadline */
mwilli2@1284 42
mwilli2@1345 43 s_time_t remain; /* Time remaining this period */
mwilli2@1345 44 s_time_t period; /* Current period of time allocation */
mwilli2@1345 45 s_time_t nat_period; /* Natural period */
mwilli2@1345 46 s_time_t slice; /* Current length of allocation */
mwilli2@1345 47 s_time_t nat_slice; /* Natural length of allocation */
mwilli2@1345 48 s_time_t latency; /* Unblocking latency */
mwilli2@1284 49
mwilli2@1345 50 int xtratime; /* Prepared to accept extra time? */
gm281@2564 51 int state; /* Keeps Atropos domain state */
mwilli2@1284 52 };
mwilli2@1284 53
mwilli2@1345 54 /* Atropos-specific per-CPU data */
mwilli2@1284 55 struct at_cpu_info
mwilli2@1284 56 {
kaf24@2634 57 struct list_head runq;
kaf24@2634 58 struct list_head waitq;
mwilli2@1284 59 };
mwilli2@1284 60
mwilli2@1284 61
kaf24@1489 62 #define DOM_INFO(_p) ((struct at_dom_info *)((_p)->sched_priv))
gm281@2564 63 #define CPU_INFO(_c) ((struct at_cpu_info *)((schedule_data[_c]).sched_priv))
gm281@2564 64 #define WAITQ(cpu) (&CPU_INFO(cpu)->waitq)
gm281@2564 65 #define RUNQ(cpu) (&CPU_INFO(cpu)->runq)
gm281@2564 66 #define RUNLIST(_d) (&DOM_INFO(_d)->run_list)
mwilli2@1284 67
mwilli2@1284 68 #define BESTEFFORT_QUANTUM MILLISECS(5)
mwilli2@1284 69
gm281@2564 70 static void at_dump_cpu_state(int cpu);
gm281@2564 71
gm281@2564 72 static inline void __add_to_runqueue_head(struct domain *d)
gm281@2564 73 {
gm281@2564 74 list_add(RUNLIST(d), RUNQ(d->processor));
gm281@2564 75 }
gm281@2564 76
gm281@2564 77 static inline void __add_to_runqueue_tail(struct domain *d)
gm281@2564 78 {
gm281@2564 79 list_add_tail(RUNLIST(d), RUNQ(d->processor));
gm281@2564 80 }
gm281@2564 81
gm281@2564 82 static inline void __del_from_runqueue(struct domain *d)
gm281@2564 83 {
gm281@2564 84 struct list_head *runlist = RUNLIST(d);
gm281@2564 85 list_del(runlist);
gm281@2564 86 runlist->next = NULL;
gm281@2564 87 }
gm281@2564 88
gm281@2564 89 static inline int __task_on_runqueue(struct domain *d)
gm281@2564 90 {
gm281@2564 91 return (RUNLIST(d))->next != NULL;
gm281@2564 92 }
gm281@2564 93
mwilli2@1345 94
mwilli2@1284 95 /** calculate the length of a linked list */
mwilli2@1284 96 static int q_len(struct list_head *q)
mwilli2@1284 97 {
mwilli2@1284 98 int i = 0;
kaf24@3568 99 struct at_dom_info *tmp;
kaf24@3568 100 list_for_each_entry ( tmp, q, waitq )
kaf24@3568 101 i++;
mwilli2@1284 102 return i;
mwilli2@1284 103 }
mwilli2@1284 104
mwilli2@1284 105
kaf24@1543 106 /** waitq_el - get the domain that owns a wait queue list element */
kaf24@1543 107 static inline struct domain *waitq_el(struct list_head *l)
mwilli2@1284 108 {
mwilli2@1284 109 struct at_dom_info *inf;
mwilli2@1284 110 inf = list_entry(l, struct at_dom_info, waitq);
mwilli2@1284 111 return inf->owner;
mwilli2@1284 112 }
mwilli2@1284 113
mwilli2@1284 114
mwilli2@1284 115 /*
mwilli2@1284 116 * requeue
mwilli2@1284 117 *
mwilli2@1284 118 * Places the specified domain on the appropriate queue.
mwilli2@1284 119 * The wait queue is ordered by the time at which the domain
mwilli2@1284 120 * will receive more CPU time. If a domain has no guaranteed time
mwilli2@1284 121 * left then the domain will be placed on the WAIT queue until
mwilli2@1284 122 * its next period.
mwilli2@1284 123 *
mwilli2@1284 124 * Note that domains can be on the wait queue with remain > 0
mwilli2@1284 125 * as a result of being blocked for a short time.
mwilli2@1284 126 * These are scheduled in preference to domains with remain < 0
mwilli2@1284 127 * in an attempt to improve interactive performance.
mwilli2@1284 128 */
kaf24@1543 129 static void requeue(struct domain *sdom)
mwilli2@1284 130 {
kaf24@3568 131 struct at_dom_info *i, *inf = DOM_INFO(sdom);
mwilli2@1284 132
kaf24@3568 133 if ( !domain_runnable(sdom) )
kaf24@3568 134 return;
gm281@2564 135
kaf24@3568 136 if ( (inf->state == ATROPOS_TASK_WAIT) ||
kaf24@3568 137 (inf->state == ATROPOS_TASK_UNBLOCKED) )
mwilli2@1284 138 {
kaf24@3568 139 list_for_each_entry ( i, WAITQ(sdom->processor), waitq )
mwilli2@1284 140 {
kaf24@1304 141 if ( i->deadline > inf->deadline )
mwilli2@1284 142 {
kaf24@3568 143 __list_add(&inf->waitq, i->waitq.prev, &i->waitq);
mwilli2@1284 144 break;
mwilli2@1284 145 }
mwilli2@1284 146 }
mwilli2@1284 147
kaf24@3568 148 if ( &i->waitq == WAITQ(sdom->processor) )
mwilli2@1284 149 list_add_tail(&inf->waitq, WAITQ(sdom->processor));
mwilli2@1284 150 }
kaf24@1543 151 else if ( domain_runnable(sdom) )
mwilli2@1284 152 {
kaf24@3568 153 list_for_each_entry ( i, RUNQ(sdom->processor), run_list )
mwilli2@1284 154 {
kaf24@3568 155 if ( (i->deadline > inf->deadline) || is_idle_task(i->owner) )
mwilli2@1284 156 {
kaf24@3568 157 __list_add(&inf->run_list, i->run_list.prev, &i->run_list);
mwilli2@1284 158 break;
mwilli2@1284 159 }
mwilli2@1284 160 }
mwilli2@1284 161
kaf24@3568 162 if ( &i->waitq == RUNQ(sdom->processor) )
gm281@2564 163 list_add_tail(&inf->run_list, RUNQ(sdom->processor));
mwilli2@1284 164 }
mwilli2@1284 165 /* silently ignore tasks in other states like BLOCKED, DYING, STOPPED, etc
mwilli2@1284 166 * - they shouldn't be on any queue */
mwilli2@1284 167 }
mwilli2@1284 168
gm281@2564 169 /** at_alloc_task - allocate private info for a task */
gm281@2564 170 static int at_alloc_task(struct domain *p)
gm281@2564 171 {
gm281@2564 172 ASSERT(p != NULL);
gm281@2564 173
iap10@3650 174 p->sched_priv = xmalloc(struct at_dom_info);
kaf24@3568 175 if ( p->sched_priv == NULL )
gm281@2564 176 return -1;
gm281@2564 177
gm281@2564 178 return 0;
gm281@2564 179 }
gm281@2564 180
gm281@2564 181
kaf24@2217 182 /* prepare a task to be added to scheduling */
kaf24@2217 183 static void at_add_task(struct domain *p)
mwilli2@1284 184 {
mwilli2@1284 185 s_time_t now = NOW();
mwilli2@1284 186
mwilli2@1284 187 ASSERT( p->sched_priv != NULL );
mwilli2@1284 188
mwilli2@1284 189 DOM_INFO(p)->owner = p;
mwilli2@1284 190 p->lastschd = now;
mwilli2@1284 191
mwilli2@1345 192 /* DOM 0's parameters must be set here for it to boot the system! */
kaf24@2748 193 if(p->id == 0)
mwilli2@1284 194 {
mwilli2@1284 195 DOM_INFO(p)->remain = MILLISECS(15);
mwilli2@1345 196 DOM_INFO(p)->nat_period =
mwilli2@1345 197 DOM_INFO(p)->period = MILLISECS(20);
mwilli2@1345 198 DOM_INFO(p)->nat_slice =
mwilli2@1345 199 DOM_INFO(p)->slice = MILLISECS(15);
mwilli2@1345 200 DOM_INFO(p)->latency = MILLISECS(5);
mwilli2@1284 201 DOM_INFO(p)->xtratime = 1;
mwilli2@1284 202 DOM_INFO(p)->deadline = now;
mwilli2@1284 203 DOM_INFO(p)->prevddln = now;
mwilli2@1284 204 }
mwilli2@1284 205 else /* other domains run basically best effort unless otherwise set */
mwilli2@1284 206 {
mwilli2@1284 207 DOM_INFO(p)->remain = 0;
mwilli2@1345 208 DOM_INFO(p)->nat_period =
mwilli2@1345 209 DOM_INFO(p)->period = SECONDS(10);
mwilli2@1345 210 DOM_INFO(p)->nat_slice =
mwilli2@1345 211 DOM_INFO(p)->slice = MILLISECS(10);
mwilli2@1345 212 DOM_INFO(p)->latency = SECONDS(10);
mwilli2@1284 213 DOM_INFO(p)->xtratime = 1;
gm281@2564 214 DOM_INFO(p)->deadline = now;
gm281@2564 215 // DOM_INFO(p)->deadline = now + SECONDS(10);
mwilli2@1284 216 DOM_INFO(p)->prevddln = 0;
mwilli2@1284 217 }
mwilli2@1284 218
gm281@2564 219 INIT_LIST_HEAD(&(DOM_INFO(p)->run_list));
mwilli2@1284 220 INIT_LIST_HEAD(&(DOM_INFO(p)->waitq));
mwilli2@1284 221 }
mwilli2@1284 222
mwilli2@1284 223 /**
mwilli2@1284 224 * dequeue - remove a domain from any queues it is on.
mwilli2@1284 225 * @sdom: the task to remove
mwilli2@1284 226 */
kaf24@1543 227 static void dequeue(struct domain *sdom)
mwilli2@1284 228 {
mwilli2@1284 229 struct at_dom_info *inf = DOM_INFO(sdom);
gm281@2564 230
kaf24@2748 231 ASSERT(sdom->id != IDLE_DOMAIN_ID);
mwilli2@1284 232
mwilli2@1284 233 /* just delete it from all the queues! */
mwilli2@1284 234 list_del(&inf->waitq);
mwilli2@1284 235 INIT_LIST_HEAD(&inf->waitq);
gm281@2564 236
mwilli2@1284 237
mwilli2@1284 238 if(__task_on_runqueue(sdom))
mwilli2@1284 239 __del_from_runqueue(sdom);
mwilli2@1284 240 }
mwilli2@1284 241
mwilli2@1284 242
mwilli2@1284 243 /*
mwilli2@1284 244 * unblock
mwilli2@1284 245 *
mwilli2@1284 246 * This function deals with updating the sdom for a domain
mwilli2@1284 247 * which has just been unblocked.
mwilli2@1284 248 *
mwilli2@1345 249 * Xen's Atropos treats unblocking slightly differently to Nemesis:
mwilli2@1345 250 *
mwilli2@1345 251 * - "Short blocking" domains (i.e. that unblock before their deadline has
mwilli2@1345 252 * expired) are treated the same as in nemesis (put on the wait queue and
mwilli2@1345 253 * given preferential treatment in selecting domains for extra time).
mwilli2@1345 254 *
mwilli2@1345 255 * - "Long blocking" domains do not simply have their period truncated to their
mwilli2@1345 256 * unblocking latency as before but also have their slice recomputed to be the
mwilli2@1345 257 * same fraction of their new period. Each time the domain is scheduled, the
mwilli2@1345 258 * period and slice are doubled until they reach their original ("natural")
mwilli2@1345 259 * values, as set by the user (and stored in nat_period and nat_slice). The
mwilli2@1345 260 * idea is to give better response times to unblocking whilst preserving QoS
mwilli2@1345 261 * guarantees to other domains.
mwilli2@1284 262 */
kaf24@1543 263 static void unblock(struct domain *sdom)
mwilli2@1284 264 {
mwilli2@1284 265 s_time_t time = NOW();
mwilli2@1284 266 struct at_dom_info *inf = DOM_INFO(sdom);
gm281@2564 267
mwilli2@1284 268 dequeue(sdom);
mwilli2@1284 269
mwilli2@1284 270 /* We distinguish two cases... short and long blocks */
mwilli2@1345 271 if ( inf->deadline < time )
mwilli2@1345 272 {
mwilli2@1345 273 /* Long blocking case */
mwilli2@1345 274
kaf24@3568 275 /* The sdom has passed its deadline since it was blocked.
kaf24@3568 276 Give it its new deadline based on the latency value. */
kaf24@3568 277 inf->prevddln = time;
mwilli2@1345 278
mwilli2@1345 279 /* Scale the scheduling parameters as requested by the latency hint. */
kaf24@3568 280 inf->deadline = time + inf->latency;
mwilli2@1345 281 inf->slice = inf->nat_slice / ( inf->nat_period / inf->latency );
mwilli2@1345 282 inf->period = inf->latency;
kaf24@3568 283 inf->remain = inf->slice;
mwilli2@1345 284 }
gm281@2564 285 else
mwilli2@1345 286 {
mwilli2@1345 287 /* Short blocking case */
mwilli2@1345 288
kaf24@3568 289 /* We leave REMAIN intact, but put this domain on the WAIT
kaf24@3568 290 queue marked as recently unblocked. It will be given
kaf24@3568 291 priority over other domains on the wait queue until while
kaf24@3568 292 REMAIN>0 in a generous attempt to help it make up for its
kaf24@3568 293 own foolishness. */
kaf24@3568 294 if(inf->remain > 0)
gm281@2564 295 inf->state = ATROPOS_TASK_UNBLOCKED;
mwilli2@1284 296 else
gm281@2564 297 inf->state = ATROPOS_TASK_WAIT;
mwilli2@1284 298 }
mwilli2@1284 299
mwilli2@1284 300 requeue(sdom);
gm281@2564 301 }
mwilli2@1284 302
gm281@2564 303
gm281@2564 304 static int at_init_idle_task(struct domain *p)
gm281@2564 305 {
gm281@2564 306 if(at_alloc_task(p) < 0) return -1;
gm281@2564 307
gm281@2564 308 at_add_task(p);
gm281@2564 309
gm281@2564 310 dequeue(p);
gm281@2564 311 requeue(p);
gm281@2564 312
gm281@2564 313 return 0;
mwilli2@1284 314 }
mwilli2@1284 315
gm281@2564 316
gm281@2564 317 static void block(struct domain* sdom)
gm281@2564 318 {
gm281@2564 319 DOM_INFO(sdom)->state = ATROPOS_TASK_BLOCKED;
gm281@2564 320 dequeue(sdom);
gm281@2564 321 requeue(sdom);
gm281@2564 322 }
gm281@2564 323
gm281@2564 324
mwilli2@1284 325 /**
mwilli2@1284 326 * ATROPOS - main scheduler function
mwilli2@1284 327 */
mwilli2@1284 328 task_slice_t ksched_scheduler(s_time_t time)
mwilli2@1284 329 {
kaf24@3568 330 struct domain *cur_sdom = current; /* Current sdom */
kaf24@3568 331 s_time_t newtime;
kaf24@3568 332 s_time_t ranfor; /* How long the domain ran */
kaf24@3568 333 struct domain *sdom; /* tmp. scheduling domain */
mwilli2@1284 334 int cpu = cur_sdom->processor; /* current CPU */
mwilli2@1284 335 struct at_dom_info *cur_info;
mwilli2@1284 336 static unsigned long waitq_rrobin = 0;
mwilli2@1284 337 int i;
mwilli2@1284 338 task_slice_t ret;
mwilli2@1284 339
gm281@2564 340
mwilli2@1284 341 cur_info = DOM_INFO(cur_sdom);
mwilli2@1284 342
mwilli2@1284 343 ASSERT( cur_sdom != NULL);
mwilli2@1284 344
mwilli2@1284 345 /* If we were spinning in the idle loop, there is no current
mwilli2@1284 346 * domain to deschedule. */
mwilli2@1345 347 if (is_idle_task(cur_sdom))
kaf24@3568 348 goto deschedule_done;
mwilli2@1284 349
mwilli2@1284 350 /*****************************
mwilli2@1284 351 *
mwilli2@1284 352 * Deschedule the current scheduling domain
mwilli2@1284 353 *
mwilli2@1284 354 ****************************/
mwilli2@1284 355
kaf24@3568 356 /* Record the time the domain was preempted and for how long it
mwilli2@1284 357 ran. Work out if the domain is going to be blocked to save
mwilli2@1284 358 some pointless queue shuffling */
mwilli2@1284 359 cur_sdom->lastdeschd = time;
mwilli2@1284 360
mwilli2@1284 361 ranfor = (time - cur_sdom->lastschd);
mwilli2@1284 362
mwilli2@1284 363 dequeue(cur_sdom);
mwilli2@1284 364
kaf24@1543 365 if ( domain_runnable(cur_sdom) ||
gm281@2564 366 (cur_info->state == ATROPOS_TASK_UNBLOCKED) )
mwilli2@1345 367 {
mwilli2@1284 368
kaf24@3568 369 /* In this block, we are doing accounting for an sdom which has
kaf24@3568 370 been running in contracted time. Note that this could now happen
kaf24@3568 371 even if the domain is on the wait queue (i.e. if it blocked) */
mwilli2@1284 372
kaf24@3568 373 /* Deduct guaranteed time from the domain */
kaf24@3568 374 cur_info->remain -= ranfor;
mwilli2@1284 375
kaf24@3568 376 /* If guaranteed time has run out... */
kaf24@3568 377 if ( cur_info->remain <= 0 )
mwilli2@1345 378 {
kaf24@3568 379 /* Move domain to correct position in WAIT queue */
mwilli2@1284 380 /* XXX sdom_unblocked doesn't need this since it is
mwilli2@1345 381 already in the correct place. */
kaf24@3568 382 cur_info->state = ATROPOS_TASK_WAIT;
kaf24@3568 383 }
mwilli2@1284 384 }
mwilli2@1284 385
mwilli2@1284 386 requeue(cur_sdom);
mwilli2@1284 387
kaf24@3568 388 deschedule_done:
mwilli2@1284 389 /*****************************
mwilli2@1284 390 *
mwilli2@1284 391 * We have now successfully descheduled the current sdom.
mwilli2@1284 392 * The next task is the allocate CPU time to any sdom it is due to.
mwilli2@1284 393 *
gm281@2564 394 ****************************/
mwilli2@1284 395 cur_sdom = NULL;
mwilli2@1284 396
mwilli2@1284 397 /*****************************
mwilli2@1284 398 *
mwilli2@1284 399 * Allocate CPU time to any waiting domains who have passed their
mwilli2@1284 400 * period deadline. If necessary, move them to run queue.
mwilli2@1284 401 *
mwilli2@1284 402 ****************************/
gm281@2564 403
mwilli2@1284 404 while(!list_empty(WAITQ(cpu)) &&
kaf24@3568 405 DOM_INFO(sdom = waitq_el(WAITQ(cpu)->next))->deadline <= time )
gm281@2564 406 {
mwilli2@1284 407
kaf24@3568 408 struct at_dom_info *inf = DOM_INFO(sdom);
mwilli2@1284 409 dequeue(sdom);
gm281@2564 410
mwilli2@1345 411 if ( inf->period != inf->nat_period )
mwilli2@1345 412 {
mwilli2@1345 413 /* This domain has had its parameters adjusted as a result of
mwilli2@1345 414 * unblocking and they need to be adjusted before requeuing it */
mwilli2@1345 415 inf->slice *= 2;
mwilli2@1345 416 inf->period *= 2;
mwilli2@1345 417
mwilli2@1345 418 if ( inf->period > inf->nat_period )
mwilli2@1345 419 {
mwilli2@1345 420 inf->period = inf->nat_period;
mwilli2@1345 421 inf->slice = inf->nat_slice;
mwilli2@1345 422 }
mwilli2@1345 423 }
mwilli2@1345 424
kaf24@3568 425 /* Domain begins a new period and receives a slice of CPU
kaf24@3568 426 * If this domain has been blocking then throw away the
kaf24@3568 427 * rest of it's remain - it can't be trusted */
kaf24@3568 428 if (inf->remain > 0)
kaf24@3568 429 inf->remain = inf->slice;
gm281@2564 430 else
kaf24@3568 431 inf->remain += inf->slice;
mwilli2@1345 432
kaf24@3568 433 inf->prevddln = inf->deadline;
kaf24@3568 434 inf->deadline += inf->period;
mwilli2@1345 435
kaf24@1543 436 if ( inf->remain <= 0 )
gm281@2564 437 inf->state = ATROPOS_TASK_WAIT;
mwilli2@1284 438
kaf24@3568 439 /* Place on the appropriate queue */
kaf24@3568 440 requeue(sdom);
mwilli2@1284 441 }
mwilli2@1284 442
mwilli2@1284 443 /*****************************
mwilli2@1284 444 *
mwilli2@1284 445 * Next we need to pick an sdom to run.
mwilli2@1284 446 * If anything is actually 'runnable', we run that.
mwilli2@1284 447 * If nothing is, we pick a waiting sdom to run optimistically.
mwilli2@1284 448 * If there aren't even any of those, we have to spin waiting for an
mwilli2@1284 449 * event or a suitable time condition to happen.
mwilli2@1284 450 *
mwilli2@1284 451 ****************************/
mwilli2@1284 452
mwilli2@1284 453 /* we guarantee there's always something on the runqueue */
gm281@2564 454 cur_info = list_entry(RUNQ(cpu)->next,
gm281@2564 455 struct at_dom_info, run_list);
mwilli2@1284 456
gm281@2564 457 cur_sdom = cur_info->owner;
mwilli2@1284 458 newtime = time + cur_info->remain;
mwilli2@1284 459
mwilli2@1284 460 /* MAW - the idle domain is always on the run queue. We run from the
mwilli2@1284 461 * runqueue if it's NOT the idle domain or if there's nothing on the wait
mwilli2@1284 462 * queue */
kaf24@2748 463 if (cur_sdom->id == IDLE_DOMAIN_ID && !list_empty(WAITQ(cpu)))
mwilli2@1345 464 {
kaf24@3568 465 struct at_dom_info *inf;
kaf24@3568 466
kaf24@3568 467 /* Try running a domain on the WAIT queue - this part of the
kaf24@3568 468 scheduler isn't particularly efficient but then again, we
kaf24@3568 469 don't have any guaranteed domains to worry about. */
mwilli2@1284 470
kaf24@3568 471 /* See if there are any unblocked domains on the WAIT
kaf24@3568 472 queue who we can give preferential treatment to. */
gm281@2564 473
kaf24@3568 474 list_for_each_entry ( inf, WAITQ(cpu), waitq )
mwilli2@1284 475 {
mwilli2@1284 476 sdom = inf->owner;
mwilli2@1284 477
kaf24@3568 478 if (inf->state == ATROPOS_TASK_UNBLOCKED)
gm281@2564 479 {
kaf24@3568 480 cur_sdom = sdom;
kaf24@3568 481 cur_info = inf;
kaf24@3568 482 newtime = time + inf->remain;
kaf24@3568 483 goto found;
kaf24@3568 484 }
kaf24@3568 485 }
mwilli2@1284 486
mwilli2@1284 487 /* init values needed to approximate round-robin for slack time */
mwilli2@1284 488 i = 0;
mwilli2@1284 489 if ( waitq_rrobin >= q_len(WAITQ(cpu)))
mwilli2@1284 490 waitq_rrobin = 0;
mwilli2@1284 491
gm281@2564 492
kaf24@3568 493 /* Last chance: pick a domain on the wait queue with the XTRA
kaf24@3568 494 flag set. The NEXT_OPTM field is used to cheaply achieve
kaf24@3568 495 an approximation of round-robin order */
kaf24@3568 496 list_for_each_entry ( inf, WAITQ(cpu), waitq )
mwilli2@1345 497 {
mwilli2@1345 498 sdom = inf->owner;
mwilli2@1345 499
gm281@2564 500 if (inf->xtratime && i >= waitq_rrobin)
gm281@2564 501 {
mwilli2@1345 502 cur_sdom = sdom;
mwilli2@1345 503 cur_info = inf;
mwilli2@1345 504 newtime = time + BESTEFFORT_QUANTUM;
mwilli2@1345 505 waitq_rrobin = i + 1; /* set this value ready for next */
mwilli2@1345 506 goto found;
mwilli2@1284 507 }
mwilli2@1345 508
mwilli2@1345 509 i++;
mwilli2@1345 510 }
mwilli2@1284 511 }
mwilli2@1284 512
kaf24@3568 513 found:
mwilli2@1284 514 /**********************
mwilli2@1284 515 *
mwilli2@1284 516 * We now have to work out the time when we next need to
mwilli2@1284 517 * make a scheduling decision. We set the alarm timer
mwilli2@1284 518 * to cause an interrupt at that time.
mwilli2@1284 519 *
mwilli2@1284 520 **********************/
mwilli2@1284 521
mwilli2@1284 522 #define MIN(x,y) ( ( x < y ) ? x : y )
mwilli2@1284 523 #define MAX(x,y) ( ( x > y ) ? x : y )
mwilli2@1284 524
mwilli2@1284 525 /* If we might be able to run a waiting domain before this one has */
mwilli2@1284 526 /* exhausted its time, cut short the time allocation */
mwilli2@1284 527 if (!list_empty(WAITQ(cpu)))
mwilli2@1284 528 {
kaf24@3568 529 newtime = MIN(newtime,
mwilli2@1284 530 DOM_INFO(waitq_el(WAITQ(cpu)->next))->deadline);
mwilli2@1284 531 }
mwilli2@1284 532
mwilli2@1284 533 /* don't allow pointlessly small time slices */
mwilli2@1284 534 newtime = MAX(newtime, time + BESTEFFORT_QUANTUM);
mwilli2@1284 535
mwilli2@1284 536 ret.task = cur_sdom;
mwilli2@1284 537 ret.time = newtime - time;
mwilli2@1284 538
kaf24@2748 539 TRACE_1D(0, cur_sdom->id);
mwilli2@1284 540
mwilli2@1284 541 return ret;
mwilli2@1284 542 }
mwilli2@1284 543
mwilli2@1284 544
mwilli2@1284 545 /* set up some private data structures */
mwilli2@1284 546 static int at_init_scheduler()
mwilli2@1284 547 {
mwilli2@1284 548 int i;
mwilli2@1284 549
kaf24@1489 550 for ( i = 0; i < NR_CPUS; i++ )
mwilli2@1284 551 {
kaf24@1958 552 schedule_data[i].sched_priv = xmalloc(sizeof(struct at_cpu_info));
kaf24@1489 553 if ( schedule_data[i].sched_priv == NULL )
mwilli2@1284 554 return -1;
gm281@2564 555 INIT_LIST_HEAD(WAITQ(i));
gm281@2564 556 INIT_LIST_HEAD(RUNQ(i));
mwilli2@1284 557 }
mwilli2@1284 558
mwilli2@1284 559 return 0;
mwilli2@1284 560 }
mwilli2@1284 561
mwilli2@1284 562
mwilli2@1284 563 /* print relevant per-domain info for a run queue dump */
kaf24@1543 564 static void at_dump_runq_el(struct domain *p)
mwilli2@1284 565 {
mwilli2@1284 566 printk("lastschd = %llu, xtratime = %d ",
mwilli2@1284 567 p->lastschd, DOM_INFO(p)->xtratime);
mwilli2@1284 568 }
mwilli2@1284 569
mwilli2@1284 570
gm281@2564 571 /* dump relevant per-cpu state for a run queue dump */
gm281@2564 572 static void at_dump_cpu_state(int cpu)
gm281@2564 573 {
kaf24@3568 574 struct list_head *queue;
gm281@2564 575 int loop = 0;
gm281@2564 576 struct at_dom_info *d_inf;
gm281@2564 577 struct domain *d;
gm281@2564 578
gm281@2564 579 queue = RUNQ(cpu);
gm281@2564 580 printk("\nRUNQUEUE rq %lx n: %lx, p: %lx\n", (unsigned long)queue,
kaf24@3568 581 (unsigned long) queue->next, (unsigned long) queue->prev);
gm281@2564 582
kaf24@3568 583 list_for_each_entry ( d_inf, queue, run_list )
gm281@2564 584 {
gm281@2564 585 d = d_inf->owner;
kaf24@2748 586 printk("%3d: %d has=%c ", loop++, d->id,
kaf24@3568 587 test_bit(DF_RUNNING, &d->flags) ? 'T':'F');
gm281@2564 588 at_dump_runq_el(d);
gm281@2564 589 printk("c=0x%X%08X\n", (u32)(d->cpu_time>>32), (u32)d->cpu_time);
gm281@2564 590 printk(" l: %lx n: %lx p: %lx\n",
kaf24@3568 591 (unsigned long)&d_inf->run_list,
kaf24@3568 592 (unsigned long)d_inf->run_list.next,
kaf24@3568 593 (unsigned long)d_inf->run_list.prev);
gm281@2564 594 }
gm281@2564 595
gm281@2564 596
gm281@2564 597 queue = WAITQ(cpu);
gm281@2564 598 printk("\nWAITQUEUE rq %lx n: %lx, p: %lx\n", (unsigned long)queue,
kaf24@3568 599 (unsigned long) queue->next, (unsigned long) queue->prev);
gm281@2564 600
kaf24@3568 601 list_for_each_entry ( d_inf, queue, waitq )
gm281@2564 602 {
gm281@2564 603 d = d_inf->owner;
kaf24@2748 604 printk("%3d: %d has=%c ", loop++, d->id,
kaf24@3568 605 test_bit(DF_RUNNING, &d->flags) ? 'T':'F');
gm281@2564 606 at_dump_runq_el(d);
gm281@2564 607 printk("c=0x%X%08X\n", (u32)(d->cpu_time>>32), (u32)d->cpu_time);
gm281@2564 608 printk(" l: %lx n: %lx p: %lx\n",
kaf24@3568 609 (unsigned long)&d_inf->waitq,
kaf24@3568 610 (unsigned long)d_inf->waitq.next,
kaf24@3568 611 (unsigned long)d_inf->waitq.prev);
gm281@2564 612 }
gm281@2564 613
gm281@2564 614 }
gm281@2564 615
mwilli2@1284 616 /* set or fetch domain scheduling parameters */
kaf24@1543 617 static int at_adjdom(struct domain *p, struct sched_adjdom_cmd *cmd)
mwilli2@1284 618 {
mwilli2@1284 619 if ( cmd->direction == SCHED_INFO_PUT )
mwilli2@1284 620 {
mwilli2@1345 621 /* sanity checking! */
mwilli2@1345 622 if( cmd->u.atropos.latency > cmd->u.atropos.nat_period
mwilli2@1345 623 || cmd->u.atropos.latency == 0
mwilli2@1345 624 || cmd->u.atropos.nat_slice > cmd->u.atropos.nat_period )
mwilli2@1345 625 return -EINVAL;
mwilli2@1345 626
mwilli2@1345 627 DOM_INFO(p)->nat_period = cmd->u.atropos.nat_period;
mwilli2@1345 628 DOM_INFO(p)->nat_slice = cmd->u.atropos.nat_slice;
mwilli2@1284 629 DOM_INFO(p)->latency = cmd->u.atropos.latency;
mwilli2@1284 630 DOM_INFO(p)->xtratime = !!cmd->u.atropos.xtratime;
mwilli2@1284 631 }
mwilli2@1284 632 else if ( cmd->direction == SCHED_INFO_GET )
mwilli2@1284 633 {
mwilli2@1345 634 cmd->u.atropos.nat_period = DOM_INFO(p)->nat_period;
mwilli2@1345 635 cmd->u.atropos.nat_slice = DOM_INFO(p)->nat_slice;
mwilli2@1284 636 cmd->u.atropos.latency = DOM_INFO(p)->latency;
mwilli2@1284 637 cmd->u.atropos.xtratime = DOM_INFO(p)->xtratime;
mwilli2@1284 638 }
mwilli2@1284 639
mwilli2@1284 640 return 0;
mwilli2@1284 641 }
mwilli2@1284 642
mwilli2@1284 643 /* free memory associated with a task */
kaf24@1543 644 static void at_free_task(struct domain *p)
mwilli2@1284 645 {
iap10@3651 646 xfree( DOM_INFO(p) );
mwilli2@1284 647 }
mwilli2@1284 648
mwilli2@1345 649
mwilli2@1284 650 /* print decoded domain private state value (if known) */
mwilli2@1284 651 static int at_prn_state(int state)
mwilli2@1284 652 {
mwilli2@1284 653 int ret = 0;
mwilli2@1284 654
mwilli2@1284 655 switch(state)
mwilli2@1284 656 {
mwilli2@1284 657 case ATROPOS_TASK_UNBLOCKED:
mwilli2@1284 658 printk("Unblocked");
mwilli2@1284 659 break;
mwilli2@1284 660 case ATROPOS_TASK_WAIT:
mwilli2@1284 661 printk("Wait");
mwilli2@1284 662 break;
mwilli2@1284 663 default:
mwilli2@1284 664 ret = -1;
mwilli2@1284 665 }
mwilli2@1284 666
mwilli2@1284 667 return ret;
mwilli2@1284 668 }
mwilli2@1284 669
mwilli2@1284 670 struct scheduler sched_atropos_def = {
mwilli2@1284 671 .name = "Atropos Soft Real Time Scheduler",
mwilli2@1284 672 .opt_name = "atropos",
mwilli2@1284 673 .sched_id = SCHED_ATROPOS,
mwilli2@1284 674 .init_scheduler = at_init_scheduler,
gm281@2564 675 .init_idle_task = at_init_idle_task,
mwilli2@1284 676 .alloc_task = at_alloc_task,
mwilli2@1284 677 .add_task = at_add_task,
mwilli2@1284 678 .free_task = at_free_task,
gm281@2564 679 .wake = unblock,
gm281@2564 680 .sleep = block,
mwilli2@1284 681 .do_schedule = ksched_scheduler,
mwilli2@1284 682 .adjdom = at_adjdom,
mwilli2@1284 683 .dump_cpu_state = at_dump_cpu_state,
mwilli2@1284 684 .prn_state = at_prn_state,
mwilli2@1284 685 };