#include "override_types.h"
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <KernelExport.h>
#include <List.h>
#include <Locker.h>
#include <String.h>
#include <TLS.h>
#include <cpu.h>
#include <kscheduler.h>
#include <timer.h>
const static option kOptions[] = {
{"time", required_argument, NULL, 't'},
{"cpu", required_argument, NULL, 'c'},
};
const bigtime_t kQuantum = 3000;
const uint32 kMaxCPUCount = 64;
class Thread {
public:
Thread(const char* name, int32 priority);
virtual ~Thread();
struct thread* GetThread() { return &fThread; }
virtual void Rescheduled() { fOnCPU[fThread.cpu->cpu_num]++; }
virtual bigtime_t NextQuantum() { return kQuantum; }
virtual bigtime_t NextState() { return B_THREAD_READY; }
virtual bigtime_t NextReady() { return 0; }
protected:
struct thread fThread;
int32 fOnCPU[kMaxCPUCount];
};
class IdleThread : public Thread {
public:
IdleThread();
virtual ~IdleThread();
};
class CPU {
public:
CPU(int32 num);
~CPU();
cpu_ent* GetCPU() { return &fCPU; }
int32 Index() { return fCPU.cpu_num; }
struct thread* CurrentThread()
{ return fCurrentThread->GetThread(); }
void SetCurrentThread(struct thread* thread)
{ fCurrentThread = thread->object; }
void Quit();
private:
void _Run();
static status_t _Run(void* self);
struct cpu_ent fCPU;
thread_id fThread;
Thread* fCurrentThread;
IdleThread fIdleThread;
int32 fRescheduleCount;
bool fQuit;
};
class Timer {
public:
Timer();
~Timer();
void AddTimer(bigtime_t time);
};
thread_queue dead_q;
static BLocker sThreadLock;
static BList sThreads;
static int32 sNextThreadID = 1;
static int32 sCPUIndexSlot;
static CPU* sCPU[kMaxCPUCount];
static size_t sCPUCount;
Thread::Thread(const char* name, int32 priority)
{
memset(&fThread, 0, sizeof(struct thread));
fThread.name = strdup(name);
fThread.id = sNextThreadID++;
fThread.priority = fThread.next_priority = priority;
fThread.state = fThread.next_state = B_THREAD_READY;
fThread.object = this;
fThread.last_time = system_time();
memset(&fOnCPU, 0, sizeof(fOnCPU));
}
Thread::~Thread()
{
printf(" %p %10Ld %s, prio %ld, cpu:", &fThread, fThread.kernel_time,
fThread.name, fThread.priority);
for (uint32 i = 0; i < kMaxCPUCount; i++) {
if (fOnCPU[i])
printf(" [%ld] %ld", i, fOnCPU[i]);
}
putchar('\n');
free(fThread.name);
}
IdleThread::IdleThread()
: Thread("idle thread", B_IDLE_PRIORITY)
{
}
IdleThread::~IdleThread()
{
}
CPU::CPU(int32 num)
:
fRescheduleCount(0),
fQuit(false)
{
memset(&fCPU, 0, sizeof(struct cpu_ent));
fCPU.cpu_num = num;
fCurrentThread = &fIdleThread;
fIdleThread.GetThread()->cpu = &fCPU;
fThread = spawn_thread(&_Run, (BString("cpu ") << num).String(),
B_NORMAL_PRIORITY, this);
resume_thread(fThread);
}
CPU::~CPU()
{
}
void
CPU::Quit()
{
fQuit = true;
status_t status;
wait_for_thread(fThread, &status);
}
void
CPU::_Run()
{
tls_set(sCPUIndexSlot, this);
printf("CPU %d has started.\n", fCPU.cpu_num);
while (!fQuit) {
fRescheduleCount++;
grab_thread_lock();
scheduler_reschedule();
release_thread_lock();
fCurrentThread->Rescheduled();
snooze(fCurrentThread->NextQuantum());
fCurrentThread->GetThread()->next_state = fCurrentThread->NextState();
}
thread_info info;
get_thread_info(find_thread(NULL), &info);
printf("CPU %d has halted, user %lld, %ld rescheduled.\n",
fCPU.cpu_num, info.user_time, fRescheduleCount);
delete this;
}
status_t
CPU::_Run(void* self)
{
CPU* cpu = (CPU*)self;
cpu->_Run();
return B_OK;
}
extern "C" void
kprintf(const char *format,...)
{
va_list args;
va_start(args, format);
printf("\33[35m");
vprintf(format, args);
printf("\33[0m");
fflush(stdout);
va_end(args);
}
void
thread_enqueue(struct thread *t, struct thread_queue *q)
{
}
struct thread *
thread_get_current_thread(void)
{
CPU* cpu = (CPU*)tls_get(sCPUIndexSlot);
return cpu->CurrentThread();
}
void
grab_thread_lock(void)
{
sThreadLock.Lock();
}
void
release_thread_lock(void)
{
sThreadLock.Unlock();
}
void
arch_thread_context_switch(struct thread *t_from, struct thread *t_to)
{
}
void
arch_thread_set_current_thread(struct thread *thread)
{
CPU* cpu = (CPU*)tls_get(sCPUIndexSlot);
return cpu->SetCurrentThread(thread);
}
int
add_debugger_command(char *name, int (*func)(int, char **), char *desc)
{
return B_OK;
}
cpu_status
disable_interrupts()
{
return 0;
}
void
restore_interrupts(cpu_status status)
{
}
extern "C" status_t
_local_timer_cancel_event(int cpu, timer *event)
{
return B_OK;
}
status_t
add_timer(timer *event, timer_hook hook, bigtime_t period, int32 flags)
{
return B_OK;
}
int32
smp_get_current_cpu(void)
{
return thread_get_current_thread()->cpu->cpu_num;
}
static void
start_cpus(uint32 count)
{
sCPUIndexSlot = tls_allocate();
sCPUCount = count;
for (size_t i = 0; i < count; i++) {
sCPU[i] = new CPU(i);
}
}
static void
stop_cpus()
{
for (size_t i = 0; i < sCPUCount; i++) {
sCPU[i]->Quit();
}
}
static void
add_thread(Thread* thread)
{
grab_thread_lock();
sThreads.AddItem(thread);
scheduler_enqueue_in_run_queue(thread->GetThread());
release_thread_lock();
}
static void
delete_threads()
{
for (int32 i = 0; i < sThreads.CountItems(); i++) {
delete (Thread*)sThreads.ItemAt(i);
}
}
int
main(int argc, char** argv)
{
bigtime_t runTime = 1000000;
uint32 cpuCount = 1;
char option;
while ((option = getopt_long(argc, argv, "", kOptions, NULL)) != -1) {
switch (option) {
case 't':
runTime *= strtol(optarg, 0, NULL);
if (runTime <= 0) {
fprintf(stderr, "Invalid run time.\n");
exit(1);
}
break;
case 'c':
cpuCount = strtol(optarg, 0, NULL);
if (cpuCount <= 0 || cpuCount > 64) {
fprintf(stderr, "Invalid CPU count (allowed: 1-64).\n");
exit(1);
}
break;
}
}
start_cpus(cpuCount);
add_thread(new Thread("test 1", 5));
add_thread(new Thread("test 2", 10));
add_thread(new Thread("test 3", 15));
snooze(runTime);
stop_cpus();
delete_threads();
return 0;
}