]> 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(L4_fpage::Rights, Syscall_frame *f, Utcb const *utcb)
54 {
55   L4_msg_tag const tag = f->tag();
56   Cpu_number 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   Cpu_number const 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[%u]: run(thread=%lx, cpu=%u (%lx,%u,%u)\n",
111            cxx::int_value<Cpu_number>(curr_cpu), thread->dbg_id(),
112            cxx::int_value<Cpu_number>(info.cpu),
113            utcb->values[2],
114            cxx::int_value<Cpu_number>(sched_param->cpus.offset()),
115            cxx::int_value<Order>(sched_param->cpus.granularity()));
116
117   thread->migrate(&info);
118
119   return commit_result(0);
120 }
121
122 PRIVATE
123 L4_msg_tag
124 Scheduler::sys_idle_time(L4_fpage::Rights,
125                          Syscall_frame *f, Utcb *utcb)
126 {
127   if (f->tag().words() < 3)
128     return commit_result(-L4_err::EInval);
129
130   L4_cpu_set cpus = access_once(reinterpret_cast<L4_cpu_set const *>(&utcb->values[1]));
131   Cpu_number const cpu = cpus.first(Cpu::online_mask(), Config::max_num_cpus());
132   if (EXPECT_FALSE(cpu == Config::max_num_cpus()))
133     return commit_result(-L4_err::EInval);
134
135   reinterpret_cast<Utcb::Time_val *>(utcb->values)->t
136     = Context::kernel_context(cpu)->consumed_time();
137
138   return commit_result(0, Utcb::Time_val::Words);
139 }
140
141 PRIVATE
142 L4_msg_tag
143 Scheduler::sys_info(L4_fpage::Rights, Syscall_frame *f,
144                     Utcb const *iutcb, Utcb *outcb)
145 {
146   if (f->tag().words() < 2)
147     return commit_result(-L4_err::EInval);
148
149   L4_cpu_set_descr const s = access_once(reinterpret_cast<L4_cpu_set_descr const*>(&iutcb->values[1]));
150   Mword rm = 0;
151   Cpu_number max = Config::max_num_cpus();
152   Cpu_number const offset = s.offset() << s.granularity();
153   if (offset >= max)
154     return commit_result(-L4_err::EInval);
155
156   if (max > offset + Cpu_number(MWORD_BITS) << s.granularity())
157     max = offset + Cpu_number(MWORD_BITS) << s.granularity();
158
159   for (Cpu_number i = Cpu_number::first(); i < max - offset; ++i)
160     if (Cpu::online(i + offset))
161       rm |= (1 << cxx::int_value<Cpu_number>(i >> s.granularity()));
162
163   outcb->values[0] = rm;
164   outcb->values[1] = Config::Max_num_cpus;
165   return commit_result(0, 2);
166 }
167
168 PUBLIC inline
169 Irq_base *
170 Scheduler::icu_get_irq(unsigned irqnum)
171 {
172   if (irqnum > 0)
173     return 0;
174
175   return _irq;
176 }
177
178 PUBLIC inline
179 void
180 Scheduler::icu_get_info(Mword *features, Mword *num_irqs, Mword *num_msis)
181 {
182   *features = 0; // supported features (only normal irqs)
183   *num_irqs = 1;
184   *num_msis = 0;
185 }
186
187 PUBLIC
188 L4_msg_tag
189 Scheduler::icu_bind_irq(Irq *irq_o, unsigned irqnum)
190 {
191   if (irqnum > 0)
192     return commit_result(-L4_err::EInval);
193
194   if (_irq)
195     _irq->unbind();
196
197   Irq_chip_soft::bind(irq_o, irqnum);
198   _irq = irq_o;
199   return commit_result(0);
200 }
201
202 PUBLIC
203 L4_msg_tag
204 Scheduler::icu_set_mode(Mword pin, Irq_chip::Mode)
205 {
206   if (pin != 0)
207     return commit_result(-L4_err::EInval);
208
209   if (_irq)
210     _irq->switch_mode(true);
211   return commit_result(0);
212 }
213
214 PUBLIC inline
215 void
216 Scheduler::trigger_hotplug_event()
217 {
218   if (_irq)
219     _irq->hit(0);
220 }
221
222 PUBLIC
223 L4_msg_tag
224 Scheduler::kinvoke(L4_obj_ref ref, L4_fpage::Rights rights, Syscall_frame *f,
225                    Utcb const *iutcb, Utcb *outcb)
226 {
227   switch (f->tag().proto())
228     {
229     case L4_msg_tag::Label_irq:
230       return Icu::icu_invoke(ref, rights, f, iutcb,outcb);
231     case L4_msg_tag::Label_scheduler:
232       break;
233     default:
234       return commit_result(-L4_err::EBadproto);
235     }
236
237   switch (iutcb->values[0])
238     {
239     case Info:       return sys_info(rights, f, iutcb, outcb);
240     case Run_thread: return sys_run(rights, f, iutcb);
241     case Idle_time:  return sys_idle_time(rights, f, outcb);
242     default:         return commit_result(-L4_err::ENosys);
243     }
244 }