]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/scheduler.cpp
7135380d609811df06aba1a96a6357b6e032838f
[l4.git] / kernel / fiasco / src / kern / scheduler.cpp
1 INTERFACE:
2
3 #include "context.h"
4 #include "kobject_helper.h"
5 #include "types.h"
6
7 class Scheduler : public Kobject_h<Scheduler>
8 {
9   FIASCO_DECLARE_KOBJ();
10
11 public:
12   enum Operation
13   {
14     Info       = 0,
15     Run_thread = 1,
16     Idle_time  = 2,
17   };
18
19   class Cpu_set
20   {
21   private:
22     Mword _w;
23
24   public:
25     Mword offset() const { return (_w & 0x00ffffff) & (~0 << granularity()); }
26     Mword granularity() const { return (_w >> 24) & (MWORD_BITS-1) ; }
27     bool contains(unsigned cpu, Mword map) const
28     {
29       if (offset() > cpu)
30         return false;
31
32       cpu -= offset();
33       cpu >>= granularity();
34       if (cpu >= MWORD_BITS)
35         return false;
36
37       return map & (1UL << cpu);
38     }
39   };
40 };
41
42 // ----------------------------------------------------------------------------
43 IMPLEMENTATION:
44
45 #include "thread_object.h"
46 #include "l4_buf_iter.h"
47 #include "entry_frame.h"
48
49 FIASCO_DEFINE_KOBJ(Scheduler);
50
51 static Scheduler scheduler;
52
53 PUBLIC inline
54 Scheduler::Scheduler()
55 {
56   initial_kobjects.register_obj(this, 7);
57 }
58
59 PRIVATE static
60 Mword
61 Scheduler::first_online(Cpu_set const *cpus, Mword bm)
62 {
63   unsigned cpu = cpus->offset();
64
65   for (;;)
66     {
67       unsigned b = (cpu - cpus->offset()) >> cpus->granularity();
68       if (cpu >= Config::Max_num_cpus || b >= MWORD_BITS)
69         return ~0UL;
70
71       if (!(bm & (1UL << b)))
72         {
73           cpu += 1UL << cpus->granularity();
74           continue;
75         }
76
77       if (Cpu::online(cpu))
78         return cpu;
79
80       ++cpu;
81     }
82 }
83
84 PRIVATE
85 L4_msg_tag
86 Scheduler::sys_run(unsigned char /*rights*/, Syscall_frame *f, Utcb const *utcb)
87 {
88   L4_msg_tag const tag = f->tag();
89   unsigned const curr_cpu = current_cpu();
90
91   Obj_space *s = current()->space()->obj_space();
92   L4_snd_item_iter snd_items(utcb, tag.words());
93
94   if (EXPECT_FALSE(tag.words() < 5))
95     return commit_result(-L4_err::EInval);
96
97   if (EXPECT_FALSE(!tag.items() || !snd_items.next()))
98     return commit_result(-L4_err::EInval);
99
100   L4_fpage _thread(snd_items.get()->d);
101   if (EXPECT_FALSE(!_thread.is_objpage()))
102     return commit_result(-L4_err::EInval);
103
104   Thread *thread = Kobject::dcast<Thread_object*>(s->lookup_local(_thread.obj_index()));
105   if (!thread)
106     return commit_result(-L4_err::EInval);
107
108   Cpu_set const *cpus = reinterpret_cast<Cpu_set const *>(&utcb->values[1]);
109
110   Thread::Migration_info info;
111
112   unsigned t_cpu = thread->cpu();
113   if (cpus->contains(t_cpu, utcb->values[2]))
114     info.cpu = t_cpu;
115   else if (cpus->contains(curr_cpu, utcb->values[2]))
116     info.cpu = curr_cpu;
117   else
118     info.cpu = first_online(cpus, utcb->values[2]);
119 #if 0
120   if (info.cpu == Invalid_cpu)
121     return commit_result(-L4_err::EInval);
122 #endif
123   info.prio = utcb->values[3];
124   info.quantum = utcb->values[4];
125 #if 0
126   printf("CPU[%lx]: current_cpu=%u run(thread=%lx, prio=%ld, quantum=%ld, cpu=%ld (%lx,%u,%u)\n",
127          dbg_id(), curr_cpu, thread->dbg_id(), info.prio, info.quantum, info.cpu, utcb->values[2], cpus->offset(), cpus->granularity());
128 #endif
129
130   if (info.prio > 255)
131     info.prio = 255;
132   if (!info.quantum)
133     info.quantum = Config::default_time_slice;
134
135
136   thread->migrate(info);
137
138   return commit_result(0);
139 }
140
141 PRIVATE
142 L4_msg_tag
143 Scheduler::sys_idle_time(unsigned char,
144                          Syscall_frame *f, Utcb *utcb)
145 {
146   if (f->tag().words() < 3)
147     return commit_result(-L4_err::EInval);
148
149   Cpu_set const *cpus = reinterpret_cast<Cpu_set const *>(&utcb->values[1]);
150   Mword const cpu = first_online(cpus, utcb->values[2]);
151   if (cpu == ~0UL)
152     return commit_result(-L4_err::EInval);
153
154   reinterpret_cast<Utcb::Time_val *>(utcb->values)->t
155     = Context::kernel_context(cpu)->consumed_time();
156
157   return commit_result(0, Utcb::Time_val::Words);
158 }
159
160 PRIVATE
161 L4_msg_tag
162 Scheduler::sys_info(unsigned char, Syscall_frame *f,
163                       Utcb const *iutcb, Utcb *outcb)
164 {
165   if (f->tag().words() < 2)
166     return commit_result(-L4_err::EInval);
167
168   Cpu_set const *s = reinterpret_cast<Cpu_set const*>(&iutcb->values[1]);
169   Mword rm = 0;
170   Mword max = Config::Max_num_cpus;
171   Mword const offset = s->offset() << s->granularity();
172   if (offset >= max)
173     return commit_result(-L4_err::EInval);
174
175   if (max > offset + ((Mword)MWORD_BITS << s->granularity()))
176     max = offset + ((Mword)MWORD_BITS << s->granularity());
177
178   for (Mword i = 0; i < max - offset; ++i)
179     if (Cpu::online(i + offset))
180       rm |= (1 << (i >> s->granularity()));
181
182   outcb->values[0] = rm;
183   outcb->values[1] = Config::Max_num_cpus;
184   return commit_result(0, 2);
185 }
186
187 PUBLIC
188 L4_msg_tag
189 Scheduler::kinvoke(L4_obj_ref, Mword rights, Syscall_frame *f,
190                    Utcb const *iutcb, Utcb *outcb)
191 {
192   if (EXPECT_FALSE(f->tag().proto() != L4_msg_tag::Label_cpu))
193     return commit_result(-L4_err::EBadproto);
194
195   switch (iutcb->values[0])
196     {
197     case Info:       return sys_info(rights, f, iutcb, outcb);
198     case Run_thread: return sys_run(rights, f, iutcb);
199     case Idle_time:  return sys_idle_time(rights, f, outcb);
200     default:         return commit_result(-L4_err::ENosys);
201     }
202 }