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
19const static option kOptions[] = {
20	{"time", required_argument, NULL, 't'},
21	{"cpu", required_argument, NULL, 'c'},
22};
23
24const bigtime_t kQuantum = 3000;
25const uint32 kMaxCPUCount = 64;
26
27class Thread {
28public:
29	Thread(const char* name, int32 priority);
30	virtual ~Thread();
31
32	struct thread* GetThread() { return &fThread; }
33	virtual void Rescheduled() { fOnCPU[fThread.cpu->cpu_num]++; }
34
35	virtual bigtime_t NextQuantum() { return kQuantum; }
36	virtual bigtime_t NextState() { return B_THREAD_READY; }
37	virtual bigtime_t NextReady() { return 0; }
38
39protected:
40	struct thread	fThread;
41	int32			fOnCPU[kMaxCPUCount];
42};
43
44class IdleThread : public Thread {
45public:
46	IdleThread();
47	virtual ~IdleThread();
48};
49
50class CPU {
51public:
52	CPU(int32 num);
53	~CPU();
54
55	cpu_ent* GetCPU() { return &fCPU; }
56	int32 Index() { return fCPU.cpu_num; }
57
58	struct thread* CurrentThread()
59		{ return fCurrentThread->GetThread(); }
60	void SetCurrentThread(struct thread* thread)
61		{ fCurrentThread = thread->object; }
62
63	void Quit();
64
65private:
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
77class Timer {
78public:
79	Timer();
80	~Timer();
81
82	void AddTimer(bigtime_t time);
83};
84
85thread_queue dead_q;
86
87static BLocker sThreadLock;
88static BList sThreads;
89static int32 sNextThreadID = 1;
90static int32 sCPUIndexSlot;
91static CPU* sCPU[kMaxCPUCount];
92static size_t sCPUCount;
93
94
95//	#pragma mark -
96
97
98Thread::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
112Thread::~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
128IdleThread::IdleThread()
129	: Thread("idle thread", B_IDLE_PRIORITY)
130{
131}
132
133
134IdleThread::~IdleThread()
135{
136}
137
138
139//	#pragma mark -
140
141
142CPU::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
159CPU::~CPU()
160{
161}
162
163
164void
165CPU::Quit()
166{
167	fQuit = true;
168
169	status_t status;
170	wait_for_thread(fThread, &status);
171}
172
173
174void
175CPU::_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
201status_t
202CPU::_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
213extern "C" void
214kprintf(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
226void
227thread_enqueue(struct thread *t, struct thread_queue *q)
228{
229}
230
231
232struct thread *
233thread_get_current_thread(void)
234{
235	CPU* cpu = (CPU*)tls_get(sCPUIndexSlot);
236	return cpu->CurrentThread();
237}
238
239
240void
241grab_thread_lock(void)
242{
243	sThreadLock.Lock();
244}
245
246
247void
248release_thread_lock(void)
249{
250	sThreadLock.Unlock();
251}
252
253
254void
255arch_thread_context_switch(struct thread *t_from, struct thread *t_to)
256{
257}
258
259
260void
261arch_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
269int
270add_debugger_command(char *name, int (*func)(int, char **), char *desc)
271{
272	return B_OK;
273}
274
275
276cpu_status
277disable_interrupts()
278{
279	return 0;
280}
281
282
283void
284restore_interrupts(cpu_status status)
285{
286}
287
288
289extern "C" status_t
290_local_timer_cancel_event(int cpu, timer *event)
291{
292	return B_OK;
293}
294
295
296status_t
297add_timer(timer *event, timer_hook hook, bigtime_t period, int32 flags)
298{
299	return B_OK;
300}
301
302
303int32
304smp_get_current_cpu(void)
305{
306	return thread_get_current_thread()->cpu->cpu_num;
307}
308
309
310//	#pragma mark -
311
312
313static void
314start_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
325static void
326stop_cpus()
327{
328	for (size_t i = 0; i < sCPUCount; i++) {
329		sCPU[i]->Quit();
330	}
331}
332
333
334static void
335add_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
344static void
345delete_threads()
346{
347	for (int32 i = 0; i < sThreads.CountItems(); i++) {
348		delete (Thread*)sThreads.ItemAt(i);
349	}
350}
351
352
353int
354main(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