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 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 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 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 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 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 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 128 IdleThread::IdleThread() 129 : Thread("idle thread", B_IDLE_PRIORITY) 130 { 131 } 132 133 134 IdleThread::~IdleThread() 135 { 136 } 137 138 139 // #pragma mark - 140 141 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 159 CPU::~CPU() 160 { 161 } 162 163 164 void 165 CPU::Quit() 166 { 167 fQuit = true; 168 169 status_t status; 170 wait_for_thread(fThread, &status); 171 } 172 173 174 void 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 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 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 227 thread_enqueue(struct thread *t, struct thread_queue *q) 228 { 229 } 230 231 232 struct thread * 233 thread_get_current_thread(void) 234 { 235 CPU* cpu = (CPU*)tls_get(sCPUIndexSlot); 236 return cpu->CurrentThread(); 237 } 238 239 240 void 241 grab_thread_lock(void) 242 { 243 sThreadLock.Lock(); 244 } 245 246 247 void 248 release_thread_lock(void) 249 { 250 sThreadLock.Unlock(); 251 } 252 253 254 void 255 arch_thread_context_switch(struct thread *t_from, struct thread *t_to) 256 { 257 } 258 259 260 void 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 270 add_debugger_command(char *name, int (*func)(int, char **), char *desc) 271 { 272 return B_OK; 273 } 274 275 276 cpu_status 277 disable_interrupts() 278 { 279 return 0; 280 } 281 282 283 void 284 restore_interrupts(cpu_status status) 285 { 286 } 287 288 289 extern "C" status_t 290 _local_timer_cancel_event(int cpu, timer *event) 291 { 292 return B_OK; 293 } 294 295 296 status_t 297 add_timer(timer *event, timer_hook hook, bigtime_t period, int32 flags) 298 { 299 return B_OK; 300 } 301 302 303 int32 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 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 326 stop_cpus() 327 { 328 for (size_t i = 0; i < sCPUCount; i++) { 329 sCPU[i]->Quit(); 330 } 331 } 332 333 334 static void 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 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 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