1 #include "override_types.h"
2
3 #include <getopt.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include <KernelExport.h>
9 #include <List.h>
10 #include <Locker.h>
11 #include <String.h>
12 #include <TLS.h>
13
14 #include <cpu.h>
15 #include <kscheduler.h>
16 #include <timer.h>
17
18
19 const static option kOptions[] = {
20 {"time", required_argument, NULL, 't'},
21 {"cpu", required_argument, NULL, 'c'},
22 };
23
24 const bigtime_t kQuantum = 3000;
25 const uint32 kMaxCPUCount = 64;
26
27 class Thread {
28 public:
29 Thread(const char* name, int32 priority);
30 virtual ~Thread();
31
GetThread()32 struct thread* GetThread() { return &fThread; }
Rescheduled()33 virtual void Rescheduled() { fOnCPU[fThread.cpu->cpu_num]++; }
34
NextQuantum()35 virtual bigtime_t NextQuantum() { return kQuantum; }
NextState()36 virtual bigtime_t NextState() { return B_THREAD_READY; }
NextReady()37 virtual bigtime_t NextReady() { return 0; }
38
39 protected:
40 struct thread fThread;
41 int32 fOnCPU[kMaxCPUCount];
42 };
43
44 class IdleThread : public Thread {
45 public:
46 IdleThread();
47 virtual ~IdleThread();
48 };
49
50 class CPU {
51 public:
52 CPU(int32 num);
53 ~CPU();
54
GetCPU()55 cpu_ent* GetCPU() { return &fCPU; }
Index()56 int32 Index() { return fCPU.cpu_num; }
57
CurrentThread()58 struct thread* CurrentThread()
59 { return fCurrentThread->GetThread(); }
SetCurrentThread(struct thread * thread)60 void SetCurrentThread(struct thread* thread)
61 { fCurrentThread = thread->object; }
62
63 void Quit();
64
65 private:
66 void _Run();
67 static status_t _Run(void* self);
68
69 struct cpu_ent fCPU;
70 thread_id fThread;
71 Thread* fCurrentThread;
72 IdleThread fIdleThread;
73 int32 fRescheduleCount;
74 bool fQuit;
75 };
76
77 class Timer {
78 public:
79 Timer();
80 ~Timer();
81
82 void AddTimer(bigtime_t time);
83 };
84
85 thread_queue dead_q;
86
87 static BLocker sThreadLock;
88 static BList sThreads;
89 static int32 sNextThreadID = 1;
90 static int32 sCPUIndexSlot;
91 static CPU* sCPU[kMaxCPUCount];
92 static size_t sCPUCount;
93
94
95 // #pragma mark -
96
97
Thread(const char * name,int32 priority)98 Thread::Thread(const char* name, int32 priority)
99 {
100 memset(&fThread, 0, sizeof(struct thread));
101 fThread.name = strdup(name);
102 fThread.id = sNextThreadID++;
103 fThread.priority = fThread.next_priority = priority;
104 fThread.state = fThread.next_state = B_THREAD_READY;
105 fThread.object = this;
106 fThread.last_time = system_time();
107
108 memset(&fOnCPU, 0, sizeof(fOnCPU));
109 }
110
111
~Thread()112 Thread::~Thread()
113 {
114 printf(" %p %10Ld %s, prio %ld, cpu:", &fThread, fThread.kernel_time,
115 fThread.name, fThread.priority);
116 for (uint32 i = 0; i < kMaxCPUCount; i++) {
117 if (fOnCPU[i])
118 printf(" [%ld] %ld", i, fOnCPU[i]);
119 }
120 putchar('\n');
121 free(fThread.name);
122 }
123
124
125 // #pragma mark -
126
127
IdleThread()128 IdleThread::IdleThread()
129 : Thread("idle thread", B_IDLE_PRIORITY)
130 {
131 }
132
133
~IdleThread()134 IdleThread::~IdleThread()
135 {
136 }
137
138
139 // #pragma mark -
140
141
CPU(int32 num)142 CPU::CPU(int32 num)
143 :
144 fRescheduleCount(0),
145 fQuit(false)
146 {
147 memset(&fCPU, 0, sizeof(struct cpu_ent));
148 fCPU.cpu_num = num;
149
150 fCurrentThread = &fIdleThread;
151 fIdleThread.GetThread()->cpu = &fCPU;
152
153 fThread = spawn_thread(&_Run, (BString("cpu ") << num).String(),
154 B_NORMAL_PRIORITY, this);
155 resume_thread(fThread);
156 }
157
158
~CPU()159 CPU::~CPU()
160 {
161 }
162
163
164 void
Quit()165 CPU::Quit()
166 {
167 fQuit = true;
168
169 status_t status;
170 wait_for_thread(fThread, &status);
171 }
172
173
174 void
_Run()175 CPU::_Run()
176 {
177 tls_set(sCPUIndexSlot, this);
178 printf("CPU %d has started.\n", fCPU.cpu_num);
179
180 while (!fQuit) {
181 fRescheduleCount++;
182
183 grab_thread_lock();
184 scheduler_reschedule();
185 release_thread_lock();
186
187 fCurrentThread->Rescheduled();
188 snooze(fCurrentThread->NextQuantum());
189 fCurrentThread->GetThread()->next_state = fCurrentThread->NextState();
190 }
191
192 thread_info info;
193 get_thread_info(find_thread(NULL), &info);
194
195 printf("CPU %d has halted, user %lld, %ld rescheduled.\n",
196 fCPU.cpu_num, info.user_time, fRescheduleCount);
197 delete this;
198 }
199
200
201 status_t
_Run(void * self)202 CPU::_Run(void* self)
203 {
204 CPU* cpu = (CPU*)self;
205 cpu->_Run();
206 return B_OK;
207 }
208
209
210 // #pragma mark - Emulation
211
212
213 extern "C" void
kprintf(const char * format,...)214 kprintf(const char *format,...)
215 {
216 va_list args;
217 va_start(args, format);
218 printf("\33[35m");
219 vprintf(format, args);
220 printf("\33[0m");
221 fflush(stdout);
222 va_end(args);
223 }
224
225
226 void
thread_enqueue(struct thread * t,struct thread_queue * q)227 thread_enqueue(struct thread *t, struct thread_queue *q)
228 {
229 }
230
231
232 struct thread *
thread_get_current_thread(void)233 thread_get_current_thread(void)
234 {
235 CPU* cpu = (CPU*)tls_get(sCPUIndexSlot);
236 return cpu->CurrentThread();
237 }
238
239
240 void
grab_thread_lock(void)241 grab_thread_lock(void)
242 {
243 sThreadLock.Lock();
244 }
245
246
247 void
release_thread_lock(void)248 release_thread_lock(void)
249 {
250 sThreadLock.Unlock();
251 }
252
253
254 void
arch_thread_context_switch(struct thread * t_from,struct thread * t_to)255 arch_thread_context_switch(struct thread *t_from, struct thread *t_to)
256 {
257 }
258
259
260 void
arch_thread_set_current_thread(struct thread * thread)261 arch_thread_set_current_thread(struct thread *thread)
262 {
263 CPU* cpu = (CPU*)tls_get(sCPUIndexSlot);
264 //printf("[%ld] %p %s\n", cpu->Index(), thread, thread->name);
265 return cpu->SetCurrentThread(thread);
266 }
267
268
269 int
add_debugger_command(char * name,int (* func)(int,char **),char * desc)270 add_debugger_command(char *name, int (*func)(int, char **), char *desc)
271 {
272 return B_OK;
273 }
274
275
276 cpu_status
disable_interrupts()277 disable_interrupts()
278 {
279 return 0;
280 }
281
282
283 void
restore_interrupts(cpu_status status)284 restore_interrupts(cpu_status status)
285 {
286 }
287
288
289 extern "C" status_t
_local_timer_cancel_event(int cpu,timer * event)290 _local_timer_cancel_event(int cpu, timer *event)
291 {
292 return B_OK;
293 }
294
295
296 status_t
add_timer(timer * event,timer_hook hook,bigtime_t period,int32 flags)297 add_timer(timer *event, timer_hook hook, bigtime_t period, int32 flags)
298 {
299 return B_OK;
300 }
301
302
303 int32
smp_get_current_cpu(void)304 smp_get_current_cpu(void)
305 {
306 return thread_get_current_thread()->cpu->cpu_num;
307 }
308
309
310 // #pragma mark -
311
312
313 static void
start_cpus(uint32 count)314 start_cpus(uint32 count)
315 {
316 sCPUIndexSlot = tls_allocate();
317 sCPUCount = count;
318
319 for (size_t i = 0; i < count; i++) {
320 sCPU[i] = new CPU(i);
321 }
322 }
323
324
325 static void
stop_cpus()326 stop_cpus()
327 {
328 for (size_t i = 0; i < sCPUCount; i++) {
329 sCPU[i]->Quit();
330 }
331 }
332
333
334 static void
add_thread(Thread * thread)335 add_thread(Thread* thread)
336 {
337 grab_thread_lock();
338 sThreads.AddItem(thread);
339 scheduler_enqueue_in_run_queue(thread->GetThread());
340 release_thread_lock();
341 }
342
343
344 static void
delete_threads()345 delete_threads()
346 {
347 for (int32 i = 0; i < sThreads.CountItems(); i++) {
348 delete (Thread*)sThreads.ItemAt(i);
349 }
350 }
351
352
353 int
main(int argc,char ** argv)354 main(int argc, char** argv)
355 {
356 bigtime_t runTime = 1000000;
357 uint32 cpuCount = 1;
358
359 char option;
360 while ((option = getopt_long(argc, argv, "", kOptions, NULL)) != -1) {
361 switch (option) {
362 case 't':
363 runTime *= strtol(optarg, 0, NULL);
364 if (runTime <= 0) {
365 fprintf(stderr, "Invalid run time.\n");
366 exit(1);
367 }
368 break;
369 case 'c':
370 cpuCount = strtol(optarg, 0, NULL);
371 if (cpuCount <= 0 || cpuCount > 64) {
372 fprintf(stderr, "Invalid CPU count (allowed: 1-64).\n");
373 exit(1);
374 }
375 break;
376 }
377 }
378
379 start_cpus(cpuCount);
380
381 add_thread(new Thread("test 1", 5));
382 add_thread(new Thread("test 2", 10));
383 add_thread(new Thread("test 3", 15));
384
385 snooze(runTime);
386
387 stop_cpus();
388 delete_threads();
389 return 0;
390 }
391