Xenomai  3.1-devel
sched.h
1 /*
2  * Copyright (C) 2008 Philippe Gerum <rpm@xenomai.org>.
3  *
4  * Xenomai is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published
6  * by the Free Software Foundation; either version 2 of the License,
7  * or (at your option) any later version.
8  *
9  * Xenomai is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with Xenomai; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17  * 02111-1307, USA.
18  */
19 #ifndef _COBALT_KERNEL_SCHED_H
20 #define _COBALT_KERNEL_SCHED_H
21 
22 #include <linux/percpu.h>
23 #include <cobalt/kernel/lock.h>
24 #include <cobalt/kernel/thread.h>
25 #include <cobalt/kernel/schedqueue.h>
26 #include <cobalt/kernel/sched-tp.h>
27 #include <cobalt/kernel/sched-weak.h>
28 #include <cobalt/kernel/sched-sporadic.h>
29 #include <cobalt/kernel/sched-quota.h>
30 #include <cobalt/kernel/vfile.h>
31 #include <cobalt/kernel/assert.h>
32 #include <asm/xenomai/machine.h>
33 
39 /* Sched status flags */
40 #define XNRESCHED 0x10000000 /* Needs rescheduling */
41 #define XNINSW 0x20000000 /* In context switch */
42 #define XNINTCK 0x40000000 /* In master tick handler context */
43 
44 /* Sched local flags */
45 #define XNIDLE 0x00010000 /* Idle (no outstanding timer) */
46 #define XNHTICK 0x00008000 /* Host tick pending */
47 #define XNINIRQ 0x00004000 /* In IRQ handling context */
48 #define XNHDEFER 0x00002000 /* Host tick deferred */
49 
50 struct xnsched_rt {
51  xnsched_queue_t runnable;
52 };
53 
58 struct xnsched {
60  unsigned long status;
62  unsigned long lflags;
64  struct xnthread *curr;
65 #ifdef CONFIG_SMP
66 
67  int cpu;
69  cpumask_t resched;
70 #endif
71 
72  struct xnsched_rt rt;
73 #ifdef CONFIG_XENO_OPT_SCHED_WEAK
74 
75  struct xnsched_weak weak;
76 #endif
77 #ifdef CONFIG_XENO_OPT_SCHED_TP
78 
79  struct xnsched_tp tp;
80 #endif
81 #ifdef CONFIG_XENO_OPT_SCHED_SPORADIC
82 
83  struct xnsched_sporadic pss;
84 #endif
85 #ifdef CONFIG_XENO_OPT_SCHED_QUOTA
86 
87  struct xnsched_quota quota;
88 #endif
89 
90  volatile unsigned inesting;
92  struct xntimer htimer;
94  struct xntimer rrbtimer;
96  struct xnthread rootcb;
97 #ifdef CONFIG_IPIPE_WANT_PREEMPTIBLE_SWITCH
98  struct xnthread *last;
99 #endif
100 #ifdef CONFIG_XENO_ARCH_FPU
101 
102  struct xnthread *fpuholder;
103 #endif
104 #ifdef CONFIG_XENO_OPT_WATCHDOG
105 
106  struct xntimer wdtimer;
108  int wdcount;
109 #endif
110 #ifdef CONFIG_XENO_OPT_STATS
111 
112  xnticks_t last_account_switch;
114  xnstat_exectime_t *current_account;
115 #endif
116 };
117 
118 DECLARE_PER_CPU(struct xnsched, nksched);
119 
120 extern cpumask_t cobalt_cpu_affinity;
121 
122 extern struct list_head nkthreadq;
123 
124 extern int cobalt_nrthreads;
125 
126 #ifdef CONFIG_XENO_OPT_VFILE
127 extern struct xnvfile_rev_tag nkthreadlist_tag;
128 #endif
129 
130 union xnsched_policy_param;
131 
132 struct xnsched_class {
133  void (*sched_init)(struct xnsched *sched);
134  void (*sched_enqueue)(struct xnthread *thread);
135  void (*sched_dequeue)(struct xnthread *thread);
136  void (*sched_requeue)(struct xnthread *thread);
137  struct xnthread *(*sched_pick)(struct xnsched *sched);
138  void (*sched_tick)(struct xnsched *sched);
139  void (*sched_rotate)(struct xnsched *sched,
140  const union xnsched_policy_param *p);
141  void (*sched_migrate)(struct xnthread *thread,
142  struct xnsched *sched);
168  bool (*sched_setparam)(struct xnthread *thread,
169  const union xnsched_policy_param *p);
170  void (*sched_getparam)(struct xnthread *thread,
171  union xnsched_policy_param *p);
172  void (*sched_trackprio)(struct xnthread *thread,
173  const union xnsched_policy_param *p);
174  void (*sched_protectprio)(struct xnthread *thread, int prio);
175  int (*sched_declare)(struct xnthread *thread,
176  const union xnsched_policy_param *p);
177  void (*sched_forget)(struct xnthread *thread);
178  void (*sched_kick)(struct xnthread *thread);
179 #ifdef CONFIG_XENO_OPT_VFILE
180  int (*sched_init_vfile)(struct xnsched_class *schedclass,
181  struct xnvfile_directory *vfroot);
182  void (*sched_cleanup_vfile)(struct xnsched_class *schedclass);
183 #endif
184  int nthreads;
185  struct xnsched_class *next;
186  int weight;
187  int policy;
188  const char *name;
189 };
190 
191 #define XNSCHED_CLASS_WEIGHT(n) (n * XNSCHED_CLASS_WEIGHT_FACTOR)
192 
193 /* Placeholder for current thread priority */
194 #define XNSCHED_RUNPRIO 0x80000000
195 
196 #define xnsched_for_each_thread(__thread) \
197  list_for_each_entry(__thread, &nkthreadq, glink)
198 
199 #ifdef CONFIG_SMP
200 static inline int xnsched_cpu(struct xnsched *sched)
201 {
202  return sched->cpu;
203 }
204 #else /* !CONFIG_SMP */
205 static inline int xnsched_cpu(struct xnsched *sched)
206 {
207  return 0;
208 }
209 #endif /* CONFIG_SMP */
210 
211 static inline struct xnsched *xnsched_struct(int cpu)
212 {
213  return &per_cpu(nksched, cpu);
214 }
215 
216 static inline struct xnsched *xnsched_current(void)
217 {
218  /* IRQs off */
219  return raw_cpu_ptr(&nksched);
220 }
221 
222 static inline struct xnthread *xnsched_current_thread(void)
223 {
224  return xnsched_current()->curr;
225 }
226 
227 /* Test resched flag of given sched. */
228 static inline int xnsched_resched_p(struct xnsched *sched)
229 {
230  return sched->status & XNRESCHED;
231 }
232 
233 /* Set self resched flag for the current scheduler. */
234 static inline void xnsched_set_self_resched(struct xnsched *sched)
235 {
236  sched->status |= XNRESCHED;
237 }
238 
239 #define xnsched_realtime_domain cobalt_pipeline.domain
240 
241 /* Set resched flag for the given scheduler. */
242 #ifdef CONFIG_SMP
243 
244 static inline void xnsched_set_resched(struct xnsched *sched)
245 {
246  struct xnsched *current_sched = xnsched_current();
247 
248  if (current_sched == sched)
249  current_sched->status |= XNRESCHED;
250  else if (!xnsched_resched_p(sched)) {
251  cpumask_set_cpu(xnsched_cpu(sched), &current_sched->resched);
252  sched->status |= XNRESCHED;
253  current_sched->status |= XNRESCHED;
254  }
255 }
256 
257 #define xnsched_realtime_cpus cobalt_pipeline.supported_cpus
258 
259 static inline int xnsched_supported_cpu(int cpu)
260 {
261  return cpumask_test_cpu(cpu, &xnsched_realtime_cpus);
262 }
263 
264 #else /* !CONFIG_SMP */
265 
266 static inline void xnsched_set_resched(struct xnsched *sched)
267 {
268  xnsched_set_self_resched(sched);
269 }
270 
271 #define xnsched_realtime_cpus CPU_MASK_ALL
272 
273 static inline int xnsched_supported_cpu(int cpu)
274 {
275  return 1;
276 }
277 
278 #endif /* !CONFIG_SMP */
279 
280 #define for_each_realtime_cpu(cpu) \
281  for_each_online_cpu(cpu) \
282  if (xnsched_supported_cpu(cpu)) \
283 
284 int ___xnsched_run(struct xnsched *sched);
285 
286 void __xnsched_run_handler(void);
287 
288 static inline int __xnsched_run(struct xnsched *sched)
289 {
290  /*
291  * NOTE: Since ___xnsched_run() won't run immediately if an
292  * escalation to primary domain is needed, we won't use
293  * critical scheduler information before we actually run in
294  * primary mode; therefore we can first test the scheduler
295  * status then escalate.
296  *
297  * Running in the primary domain means that no Linux-triggered
298  * CPU migration may occur from that point either. Finally,
299  * since migration is always a self-directed operation for
300  * Xenomai threads, we can safely read the scheduler state
301  * bits without holding the nklock.
302  *
303  * Said differently, if we race here because of a CPU
304  * migration, it must have been Linux-triggered because we run
305  * in secondary mode; in which case we will escalate to the
306  * primary domain, then unwind the current call frame without
307  * running the rescheduling procedure in
308  * ___xnsched_run(). Therefore, the scheduler slot
309  * (i.e. "sched") will be either valid, or unused.
310  */
311  if (((sched->status|sched->lflags) &
312  (XNINIRQ|XNINSW|XNRESCHED)) != XNRESCHED)
313  return 0;
314 
315  return ___xnsched_run(sched);
316 }
317 
318 static inline int xnsched_run(void)
319 {
320  struct xnsched *sched = xnsched_current();
321  /*
322  * No rescheduling is possible, either if:
323  *
324  * - the current thread holds the scheduler lock
325  * - an ISR context is active
326  * - we are caught in the middle of an unlocked context switch.
327  */
328  smp_rmb();
329  if (unlikely(sched->curr->lock_count > 0))
330  return 0;
331 
332  return __xnsched_run(sched);
333 }
334 
335 void xnsched_lock(void);
336 
337 void xnsched_unlock(void);
338 
339 static inline int xnsched_interrupt_p(void)
340 {
341  return xnsched_current()->lflags & XNINIRQ;
342 }
343 
344 static inline int xnsched_root_p(void)
345 {
346  return xnthread_test_state(xnsched_current_thread(), XNROOT);
347 }
348 
349 static inline int xnsched_unblockable_p(void)
350 {
351  return xnsched_interrupt_p() || xnsched_root_p();
352 }
353 
354 static inline int xnsched_primary_p(void)
355 {
356  return !xnsched_unblockable_p();
357 }
358 
359 #ifdef CONFIG_IPIPE_WANT_PREEMPTIBLE_SWITCH
360 
361 struct xnsched *xnsched_finish_unlocked_switch(struct xnsched *sched);
362 
363 #define xnsched_resched_after_unlocked_switch() xnsched_run()
364 
365 static inline
366 int xnsched_maybe_resched_after_unlocked_switch(struct xnsched *sched)
367 {
368  return sched->status & XNRESCHED;
369 }
370 
371 #else /* !CONFIG_IPIPE_WANT_PREEMPTIBLE_SWITCH */
372 
373 static inline struct xnsched *
374 xnsched_finish_unlocked_switch(struct xnsched *sched)
375 {
376  XENO_BUG_ON(COBALT, !hard_irqs_disabled());
377  return xnsched_current();
378 }
379 
380 static inline void xnsched_resched_after_unlocked_switch(void) { }
381 
382 static inline int
383 xnsched_maybe_resched_after_unlocked_switch(struct xnsched *sched)
384 {
385  return 0;
386 }
387 
388 #endif /* !CONFIG_IPIPE_WANT_PREEMPTIBLE_SWITCH */
389 
390 #ifdef CONFIG_XENO_OPT_WATCHDOG
391 static inline void xnsched_reset_watchdog(struct xnsched *sched)
392 {
393  sched->wdcount = 0;
394 }
395 #else /* !CONFIG_XENO_OPT_WATCHDOG */
396 static inline void xnsched_reset_watchdog(struct xnsched *sched)
397 {
398 }
399 #endif /* CONFIG_XENO_OPT_WATCHDOG */
400 
401 bool xnsched_set_effective_priority(struct xnthread *thread,
402  int prio);
403 
404 #include <cobalt/kernel/sched-idle.h>
405 #include <cobalt/kernel/sched-rt.h>
406 
407 int xnsched_init_proc(void);
408 
409 void xnsched_cleanup_proc(void);
410 
411 void xnsched_register_classes(void);
412 
413 void xnsched_init(struct xnsched *sched, int cpu);
414 
415 void xnsched_destroy(struct xnsched *sched);
416 
417 struct xnthread *xnsched_pick_next(struct xnsched *sched);
418 
419 void xnsched_putback(struct xnthread *thread);
420 
421 int xnsched_set_policy(struct xnthread *thread,
422  struct xnsched_class *sched_class,
423  const union xnsched_policy_param *p);
424 
425 void xnsched_track_policy(struct xnthread *thread,
426  struct xnthread *target);
427 
428 void xnsched_protect_priority(struct xnthread *thread,
429  int prio);
430 
431 void xnsched_migrate(struct xnthread *thread,
432  struct xnsched *sched);
433 
434 void xnsched_migrate_passive(struct xnthread *thread,
435  struct xnsched *sched);
436 
459 static inline void xnsched_rotate(struct xnsched *sched,
460  struct xnsched_class *sched_class,
461  const union xnsched_policy_param *sched_param)
462 {
463  sched_class->sched_rotate(sched, sched_param);
464 }
465 
466 static inline int xnsched_init_thread(struct xnthread *thread)
467 {
468  int ret = 0;
469 
470  xnsched_idle_init_thread(thread);
471  xnsched_rt_init_thread(thread);
472 
473 #ifdef CONFIG_XENO_OPT_SCHED_TP
474  ret = xnsched_tp_init_thread(thread);
475  if (ret)
476  return ret;
477 #endif /* CONFIG_XENO_OPT_SCHED_TP */
478 #ifdef CONFIG_XENO_OPT_SCHED_SPORADIC
479  ret = xnsched_sporadic_init_thread(thread);
480  if (ret)
481  return ret;
482 #endif /* CONFIG_XENO_OPT_SCHED_SPORADIC */
483 #ifdef CONFIG_XENO_OPT_SCHED_QUOTA
484  ret = xnsched_quota_init_thread(thread);
485  if (ret)
486  return ret;
487 #endif /* CONFIG_XENO_OPT_SCHED_QUOTA */
488 
489  return ret;
490 }
491 
492 static inline int xnsched_root_priority(struct xnsched *sched)
493 {
494  return sched->rootcb.cprio;
495 }
496 
497 static inline struct xnsched_class *xnsched_root_class(struct xnsched *sched)
498 {
499  return sched->rootcb.sched_class;
500 }
501 
502 static inline void xnsched_tick(struct xnsched *sched)
503 {
504  struct xnthread *curr = sched->curr;
505  struct xnsched_class *sched_class = curr->sched_class;
506  /*
507  * A thread that undergoes round-robin scheduling only
508  * consumes its time slice when it runs within its own
509  * scheduling class, which excludes temporary PI boosts, and
510  * does not hold the scheduler lock.
511  */
512  if (sched_class == curr->base_class &&
513  sched_class->sched_tick &&
514  xnthread_test_state(curr, XNTHREAD_BLOCK_BITS|XNRRB) == XNRRB &&
515  curr->lock_count == 0)
516  sched_class->sched_tick(sched);
517 }
518 
519 static inline int xnsched_declare(struct xnsched_class *sched_class,
520  struct xnthread *thread,
521  const union xnsched_policy_param *p)
522 {
523  int ret;
524 
525  if (sched_class->sched_declare) {
526  ret = sched_class->sched_declare(thread, p);
527  if (ret)
528  return ret;
529  }
530  if (sched_class != thread->base_class)
531  sched_class->nthreads++;
532 
533  return 0;
534 }
535 
536 static inline int xnsched_calc_wprio(struct xnsched_class *sched_class,
537  int prio)
538 {
539  return prio + sched_class->weight;
540 }
541 
542 #ifdef CONFIG_XENO_OPT_SCHED_CLASSES
543 
544 static inline void xnsched_enqueue(struct xnthread *thread)
545 {
546  struct xnsched_class *sched_class = thread->sched_class;
547 
548  if (sched_class != &xnsched_class_idle)
549  sched_class->sched_enqueue(thread);
550 }
551 
552 static inline void xnsched_dequeue(struct xnthread *thread)
553 {
554  struct xnsched_class *sched_class = thread->sched_class;
555 
556  if (sched_class != &xnsched_class_idle)
557  sched_class->sched_dequeue(thread);
558 }
559 
560 static inline void xnsched_requeue(struct xnthread *thread)
561 {
562  struct xnsched_class *sched_class = thread->sched_class;
563 
564  if (sched_class != &xnsched_class_idle)
565  sched_class->sched_requeue(thread);
566 }
567 
568 static inline
569 bool xnsched_setparam(struct xnthread *thread,
570  const union xnsched_policy_param *p)
571 {
572  return thread->base_class->sched_setparam(thread, p);
573 }
574 
575 static inline void xnsched_getparam(struct xnthread *thread,
576  union xnsched_policy_param *p)
577 {
578  thread->sched_class->sched_getparam(thread, p);
579 }
580 
581 static inline void xnsched_trackprio(struct xnthread *thread,
582  const union xnsched_policy_param *p)
583 {
584  thread->sched_class->sched_trackprio(thread, p);
585  thread->wprio = xnsched_calc_wprio(thread->sched_class, thread->cprio);
586 }
587 
588 static inline void xnsched_protectprio(struct xnthread *thread, int prio)
589 {
590  thread->sched_class->sched_protectprio(thread, prio);
591  thread->wprio = xnsched_calc_wprio(thread->sched_class, thread->cprio);
592 }
593 
594 static inline void xnsched_forget(struct xnthread *thread)
595 {
596  struct xnsched_class *sched_class = thread->base_class;
597 
598  --sched_class->nthreads;
599 
600  if (sched_class->sched_forget)
601  sched_class->sched_forget(thread);
602 }
603 
604 static inline void xnsched_kick(struct xnthread *thread)
605 {
606  struct xnsched_class *sched_class = thread->base_class;
607 
608  xnthread_set_info(thread, XNKICKED);
609 
610  if (sched_class->sched_kick)
611  sched_class->sched_kick(thread);
612 
613  xnsched_set_resched(thread->sched);
614 }
615 
616 #else /* !CONFIG_XENO_OPT_SCHED_CLASSES */
617 
618 /*
619  * If only the RT and IDLE scheduling classes are compiled in, we can
620  * fully inline common helpers for dealing with those.
621  */
622 
623 static inline void xnsched_enqueue(struct xnthread *thread)
624 {
625  struct xnsched_class *sched_class = thread->sched_class;
626 
627  if (sched_class != &xnsched_class_idle)
628  __xnsched_rt_enqueue(thread);
629 }
630 
631 static inline void xnsched_dequeue(struct xnthread *thread)
632 {
633  struct xnsched_class *sched_class = thread->sched_class;
634 
635  if (sched_class != &xnsched_class_idle)
636  __xnsched_rt_dequeue(thread);
637 }
638 
639 static inline void xnsched_requeue(struct xnthread *thread)
640 {
641  struct xnsched_class *sched_class = thread->sched_class;
642 
643  if (sched_class != &xnsched_class_idle)
644  __xnsched_rt_requeue(thread);
645 }
646 
647 static inline bool xnsched_setparam(struct xnthread *thread,
648  const union xnsched_policy_param *p)
649 {
650  struct xnsched_class *sched_class = thread->base_class;
651 
652  if (sched_class == &xnsched_class_idle)
653  return __xnsched_idle_setparam(thread, p);
654 
655  return __xnsched_rt_setparam(thread, p);
656 }
657 
658 static inline void xnsched_getparam(struct xnthread *thread,
659  union xnsched_policy_param *p)
660 {
661  struct xnsched_class *sched_class = thread->sched_class;
662 
663  if (sched_class == &xnsched_class_idle)
664  __xnsched_idle_getparam(thread, p);
665  else
666  __xnsched_rt_getparam(thread, p);
667 }
668 
669 static inline void xnsched_trackprio(struct xnthread *thread,
670  const union xnsched_policy_param *p)
671 {
672  struct xnsched_class *sched_class = thread->sched_class;
673 
674  if (sched_class == &xnsched_class_idle)
675  __xnsched_idle_trackprio(thread, p);
676  else
677  __xnsched_rt_trackprio(thread, p);
678 
679  thread->wprio = xnsched_calc_wprio(sched_class, thread->cprio);
680 }
681 
682 static inline void xnsched_protectprio(struct xnthread *thread, int prio)
683 {
684  struct xnsched_class *sched_class = thread->sched_class;
685 
686  if (sched_class == &xnsched_class_idle)
687  __xnsched_idle_protectprio(thread, prio);
688  else
689  __xnsched_rt_protectprio(thread, prio);
690 
691  thread->wprio = xnsched_calc_wprio(sched_class, thread->cprio);
692 }
693 
694 static inline void xnsched_forget(struct xnthread *thread)
695 {
696  --thread->base_class->nthreads;
697  __xnsched_rt_forget(thread);
698 }
699 
700 static inline void xnsched_kick(struct xnthread *thread)
701 {
702  xnthread_set_info(thread, XNKICKED);
703  xnsched_set_resched(thread->sched);
704 }
705 
706 #endif /* !CONFIG_XENO_OPT_SCHED_CLASSES */
707 
710 #endif /* !_COBALT_KERNEL_SCHED_H */
struct xnthread * curr
Definition: sched.h:64
Snapshot revision tag.
Definition: vfile.h:482
#define XNKICKED
Forced out of primary mode.
Definition: thread.h:69
#define XNRRB
Undergoes a round-robin scheduling.
Definition: thread.h:45
int cpu
Definition: sched.h:67
#define XNROOT
Root thread (that is, Linux/IDLE)
Definition: thread.h:48
volatile unsigned inesting
Definition: sched.h:90
Scheduling information structure.
Definition: sched.h:58
unsigned long lflags
Definition: sched.h:62
unsigned long status
Definition: sched.h:60
static void xnsched_rotate(struct xnsched *sched, struct xnsched_class *sched_class, const union xnsched_policy_param *sched_param)
Rotate a scheduler runqueue.
Definition: sched.h:459
static int xnsched_run(void)
The rescheduling procedure.
Definition: sched.h:318
cpumask_t resched
Definition: sched.h:69