]> 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 "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 void
54 Scheduler::operator delete (void *)
55 {
56   printf("WARNING: tried to delete kernel scheduler object.\n"
57          "         The system is now useless\n");
58 }
59
60 PUBLIC inline
61 Scheduler::Scheduler()
62 {
63   initial_kobjects.register_obj(this, 7);
64 }
65
66 PRIVATE static
67 Mword
68 Scheduler::first_online(Cpu_set const *cpus, Mword bm)
69 {
70   unsigned cpu = cpus->offset();
71
72   for (;;)
73     {
74       unsigned b = (cpu - cpus->offset()) >> cpus->granularity();
75       if (cpu >= Config::Max_num_cpus || b >= MWORD_BITS)
76         return ~0UL;
77
78       if (!(bm & (1UL << b)))
79         {
80           cpu += 1UL << cpus->granularity();
81           continue;
82         }
83
84       if (Cpu::online(cpu))
85         return cpu;
86
87       ++cpu;
88     }
89 }
90
91 PRIVATE
92 L4_msg_tag
93 Scheduler::sys_run(unsigned char /*rights*/, Syscall_frame *f, Utcb const *utcb)
94 {
95   L4_msg_tag const tag = f->tag();
96   unsigned const curr_cpu = current_cpu();
97
98   Obj_space *s = current()->space()->obj_space();
99   L4_snd_item_iter snd_items(utcb, tag.words());
100
101   if (EXPECT_FALSE(tag.words() < 5))
102     return commit_result(-L4_err::EInval);
103
104   if (EXPECT_FALSE(!tag.items() || !snd_items.next()))
105     return commit_result(-L4_err::EInval);
106
107   L4_fpage _thread(snd_items.get()->d);
108   if (EXPECT_FALSE(!_thread.is_objpage()))
109     return commit_result(-L4_err::EInval);
110
111   Thread *thread = Kobject::dcast<Thread_object*>(s->lookup_local(_thread.obj_index()));
112   if (!thread)
113     return commit_result(-L4_err::EInval);
114
115   Cpu_set const *cpus = reinterpret_cast<Cpu_set const *>(&utcb->values[1]);
116
117   Thread::Migration_info info;
118
119   unsigned t_cpu = thread->cpu();
120   if (cpus->contains(t_cpu, utcb->values[2]))
121     info.cpu = t_cpu;
122   else if (cpus->contains(curr_cpu, utcb->values[2]))
123     info.cpu = curr_cpu;
124   else
125     info.cpu = first_online(cpus, utcb->values[2]);
126 #if 0
127   if (info.cpu == Invalid_cpu)
128     return commit_result(-L4_err::EInval);
129 #endif
130   info.prio = utcb->values[3];
131   info.quantum = utcb->values[4];
132 #if 0
133   printf("CPU[%lx]: current_cpu=%u run(thread=%lx, prio=%ld, quantum=%ld, cpu=%ld (%lx,%u,%u)\n",
134          dbg_id(), curr_cpu, thread->dbg_id(), info.prio, info.quantum, info.cpu, utcb->values[2], cpus->offset(), cpus->granularity());
135 #endif
136
137   if (info.prio > 255)
138     info.prio = 255;
139   if (!info.quantum)
140     info.quantum = Config::default_time_slice;
141
142
143   thread->migrate(info);
144
145   return commit_result(0);
146 }
147
148 PRIVATE
149 L4_msg_tag
150 Scheduler::sys_idle_time(unsigned char,
151                          Syscall_frame *f, Utcb *utcb)
152 {
153   if (f->tag().words() < 3)
154     return commit_result(-L4_err::EInval);
155
156   Cpu_set const *cpus = reinterpret_cast<Cpu_set const *>(&utcb->values[1]);
157   Mword const cpu = first_online(cpus, utcb->values[2]);
158   if (cpu == ~0UL)
159     return commit_result(-L4_err::EInval);
160
161   reinterpret_cast<Utcb::Time_val *>(utcb->values)->t
162     = Context::kernel_context(cpu)->consumed_time();
163
164   return commit_result(0, Utcb::Time_val::Words);
165 }
166
167 PRIVATE
168 L4_msg_tag
169 Scheduler::sys_info(unsigned char, Syscall_frame *f,
170                       Utcb const *iutcb, Utcb *outcb)
171 {
172   if (f->tag().words() < 2)
173     return commit_result(-L4_err::EInval);
174
175   Cpu_set const *s = reinterpret_cast<Cpu_set const*>(&iutcb->values[1]);
176   Mword rm = 0;
177   Mword max = Config::Max_num_cpus;
178   Mword const offset = s->offset() << s->granularity();
179   if (offset >= max)
180     return commit_result(-L4_err::EInval);
181
182   if (max > offset + ((Mword)MWORD_BITS << s->granularity()))
183     max = offset + ((Mword)MWORD_BITS << s->granularity());
184
185   for (Mword i = 0; i < max - offset; ++i)
186     if (Cpu::online(i + offset))
187       rm |= (1 << (i >> s->granularity()));
188
189   outcb->values[0] = rm;
190   outcb->values[1] = Config::Max_num_cpus;
191   return commit_result(0, 2);
192 }
193
194 PUBLIC
195 L4_msg_tag
196 Scheduler::kinvoke(L4_obj_ref, Mword rights, Syscall_frame *f,
197                    Utcb const *iutcb, Utcb *outcb)
198 {
199   if (EXPECT_FALSE(f->tag().proto() != L4_msg_tag::Label_scheduler))
200     return commit_result(-L4_err::EBadproto);
201
202   switch (iutcb->values[0])
203     {
204     case Info:       return sys_info(rights, f, iutcb, outcb);
205     case Run_thread: return sys_run(rights, f, iutcb);
206     case Idle_time:  return sys_idle_time(rights, f, outcb);
207     default:         return commit_result(-L4_err::ENosys);
208     }
209 }