#include "override_types.h" #include #include #include #include #include #include #include #include #include #include #include #include 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; // #pragma mark - 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); } // #pragma mark - IdleThread::IdleThread() : Thread("idle thread", B_IDLE_PRIORITY) { } IdleThread::~IdleThread() { } // #pragma mark - 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; } // #pragma mark - Emulation 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); //printf("[%ld] %p %s\n", cpu->Index(), thread, thread->name); 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; } // #pragma mark - 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; }