]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/scheduler.cpp
update
[l4.git] / kernel / fiasco / src / kern / scheduler.cpp
1 INTERFACE:
2
3 #include "context.h"
4 #include "icu_helper.h"
5 #include "types.h"
6
7 class Scheduler : public Icu_h<Scheduler>, public Irq_chip_soft
8 {
9   FIASCO_DECLARE_KOBJ();
10   typedef Icu_h<Scheduler> Icu;
11
12 public:
13   enum Operation
14   {
15     Info       = 0,
16     Run_thread = 1,
17     Idle_time  = 2,
18   };
19
20   static Scheduler scheduler;
21 private:
22   Irq_base *_irq;
23 };
24
25 // ----------------------------------------------------------------------------
26 IMPLEMENTATION:
27
28 #include "thread_object.h"
29 #include "l4_buf_iter.h"
30 #include "l4_types.h"
31 #include "entry_frame.h"
32
33 FIASCO_DEFINE_KOBJ(Scheduler);
34
35 Scheduler Scheduler::scheduler;
36
37 PUBLIC void
38 Scheduler::operator delete (void *)
39 {
40   printf("WARNING: tried to delete kernel scheduler object.\n"
41          "         The system is now useless\n");
42 }
43
44 PUBLIC inline
45 Scheduler::Scheduler() : _irq(0)
46 {
47   initial_kobjects.register_obj(this, 7);
48 }
49
50
51 PRIVATE
52 L4_msg_tag
53 Scheduler::sys_run(unsigned char /*rights*/, Syscall_frame *f, Utcb const *utcb)
54 {
55   L4_msg_tag const tag = f->tag();
56   unsigned const curr_cpu = current_cpu();
57
58   Obj_space *s = current()->space();
59   assert(s);
60
61   L4_snd_item_iter snd_items(utcb, tag.words());
62
63   if (EXPECT_FALSE(tag.words() < 5))
64     return commit_result(-L4_err::EInval);
65
66   unsigned long sz = sizeof (L4_sched_param_legacy);
67
68     {
69       L4_sched_param const *sched_param = reinterpret_cast<L4_sched_param const*>(&utcb->values[1]);
70       if (sched_param->sched_class < 0)
71         sz = sched_param->length;
72
73       sz += sizeof(Mword) - 1;
74       sz /= sizeof(Mword);
75
76       if (sz + 1 > tag.words())
77         return commit_result(-L4_err::EInval);
78     }
79
80   if (EXPECT_FALSE(!tag.items() || !snd_items.next()))
81     return commit_result(-L4_err::EInval);
82
83   L4_fpage _thread(snd_items.get()->d);
84   if (EXPECT_FALSE(!_thread.is_objpage()))
85     return commit_result(-L4_err::EInval);
86
87   Thread *thread = Kobject::dcast<Thread_object*>(s->lookup_local(_thread.obj_index()));
88   if (!thread)
89     return commit_result(-L4_err::EInval);
90
91
92   Mword _store[sz];
93   memcpy(_store, &utcb->values[1], sz * sizeof(Mword));
94
95   L4_sched_param const *sched_param = reinterpret_cast<L4_sched_param const *>(_store);
96
97   Thread::Migration info;
98
99   unsigned t_cpu = thread->cpu();
100
101   if (Cpu::online(t_cpu) && sched_param->cpus.contains(t_cpu))
102     info.cpu = t_cpu;
103   else if (sched_param->cpus.contains(curr_cpu))
104     info.cpu = curr_cpu;
105   else
106     info.cpu = sched_param->cpus.first(Cpu::online_mask(), Config::Max_num_cpus);
107
108   info.sp = sched_param;
109   if (0)
110     printf("CPU[%lx]: current_cpu=%u run(thread=%lx, cpu=%u (%lx,%lu,%lu)\n",
111            dbg_id(), curr_cpu, thread->dbg_id(), info.cpu,
112            utcb->values[2], sched_param->cpus.offset(), sched_param->cpus.granularity());
113
114   thread->migrate(&info);
115
116   return commit_result(0);
117 }
118
119 PRIVATE
120 L4_msg_tag
121 Scheduler::sys_idle_time(unsigned char,
122                          Syscall_frame *f, Utcb *utcb)
123 {
124   if (f->tag().words() < 3)
125     return commit_result(-L4_err::EInval);
126
127   L4_cpu_set cpus = access_once(reinterpret_cast<L4_cpu_set const *>(&utcb->values[1]));
128   Mword const cpu = cpus.first(Cpu::online_mask(), Config::Max_num_cpus);
129   if (EXPECT_FALSE(cpu == Config::Max_num_cpus))
130     return commit_result(-L4_err::EInval);
131
132   reinterpret_cast<Utcb::Time_val *>(utcb->values)->t
133     = Context::kernel_context(cpu)->consumed_time();
134
135   return commit_result(0, Utcb::Time_val::Words);
136 }
137
138 PRIVATE
139 L4_msg_tag
140 Scheduler::sys_info(unsigned char, Syscall_frame *f,
141                     Utcb const *iutcb, Utcb *outcb)
142 {
143   if (f->tag().words() < 2)
144     return commit_result(-L4_err::EInval);
145
146   L4_cpu_set_descr const s = access_once(reinterpret_cast<L4_cpu_set_descr const*>(&iutcb->values[1]));
147   Mword rm = 0;
148   Mword max = Config::Max_num_cpus;
149   Mword const offset = s.offset() << s.granularity();
150   if (offset >= max)
151     return commit_result(-L4_err::EInval);
152
153   if (max > offset + ((Mword)MWORD_BITS << s.granularity()))
154     max = offset + ((Mword)MWORD_BITS << s.granularity());
155
156   for (Mword i = 0; i < max - offset; ++i)
157     if (Cpu::online(i + offset))
158       rm |= (1 << (i >> s.granularity()));
159
160   outcb->values[0] = rm;
161   outcb->values[1] = Config::Max_num_cpus;
162   return commit_result(0, 2);
163 }
164
165 PUBLIC inline
166 Irq_base *
167 Scheduler::icu_get_irq(unsigned irqnum)
168 {
169   if (irqnum > 0)
170     return 0;
171
172   return _irq;
173 }
174
175 PUBLIC inline
176 void
177 Scheduler::icu_get_info(Mword *features, Mword *num_irqs, Mword *num_msis)
178 {
179   *features = 0; // supported features (only normal irqs)
180   *num_irqs = 1;
181   *num_msis = 0;
182 }
183
184 PUBLIC
185 L4_msg_tag
186 Scheduler::icu_bind_irq(Irq *irq_o, unsigned irqnum)
187 {
188   if (irqnum > 0)
189     return commit_result(-L4_err::EInval);
190
191   if (_irq)
192     _irq->unbind();
193
194   Irq_chip_soft::bind(irq_o, irqnum);
195   _irq = irq_o;
196   return commit_result(0);
197 }
198
199 PUBLIC inline
200 void
201 Scheduler::trigger_hotplug_event()
202 {
203   if (_irq)
204     _irq->hit(0);
205 }
206
207 PUBLIC
208 L4_msg_tag
209 Scheduler::kinvoke(L4_obj_ref ref, Mword rights, Syscall_frame *f,
210                    Utcb const *iutcb, Utcb *outcb)
211 {
212   switch (f->tag().proto())
213     {
214     case L4_msg_tag::Label_irq:
215       return Icu::icu_invoke(ref, rights, f, iutcb,outcb);
216     case L4_msg_tag::Label_scheduler:
217       break;
218     default:
219       return commit_result(-L4_err::EBadproto);
220     }
221
222   switch (iutcb->values[0])
223     {
224     case Info:       return sys_info(rights, f, iutcb, outcb);
225     case Run_thread: return sys_run(rights, f, iutcb);
226     case Idle_time:  return sys_idle_time(rights, f, outcb);
227     default:         return commit_result(-L4_err::ENosys);
228     }
229 }