1 /* 2 * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2010, Axel Dörfler, axeld@pinc-software.de. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 #include <kscheduler.h> 9 #include <listeners.h> 10 #include <smp.h> 11 12 #include "scheduler_affine.h" 13 #include "scheduler_simple.h" 14 #include "scheduler_simple_smp.h" 15 #include "scheduler_tracing.h" 16 17 18 struct scheduler_ops* gScheduler; 19 spinlock gSchedulerLock = B_SPINLOCK_INITIALIZER; 20 SchedulerListenerList gSchedulerListeners; 21 22 static void (*sRescheduleFunction)(void); 23 24 25 static void 26 scheduler_reschedule_no_op(void) 27 { 28 Thread* thread = thread_get_current_thread(); 29 if (thread != NULL && thread->next_state != B_THREAD_READY) 30 panic("scheduler_reschedule_no_op() called in non-ready thread"); 31 } 32 33 34 // #pragma mark - SchedulerListener 35 36 37 SchedulerListener::~SchedulerListener() 38 { 39 } 40 41 42 // #pragma mark - kernel private 43 44 45 /*! Add the given scheduler listener. Thread lock must be held. 46 */ 47 void 48 scheduler_add_listener(struct SchedulerListener* listener) 49 { 50 gSchedulerListeners.Add(listener); 51 } 52 53 54 /*! Remove the given scheduler listener. Thread lock must be held. 55 */ 56 void 57 scheduler_remove_listener(struct SchedulerListener* listener) 58 { 59 gSchedulerListeners.Remove(listener); 60 } 61 62 63 void 64 scheduler_init(void) 65 { 66 int32 cpuCount = smp_get_num_cpus(); 67 dprintf("scheduler_init: found %ld logical cpu%s\n", cpuCount, 68 cpuCount != 1 ? "s" : ""); 69 70 if (cpuCount > 1) { 71 #if 0 72 dprintf("scheduler_init: using affine scheduler\n"); 73 scheduler_affine_init(); 74 #else 75 dprintf("scheduler_init: using simple SMP scheduler\n"); 76 scheduler_simple_smp_init(); 77 #endif 78 } else { 79 dprintf("scheduler_init: using simple scheduler\n"); 80 scheduler_simple_init(); 81 } 82 83 // Disable rescheduling until the basic kernel initialization is done and 84 // CPUs are ready to enable interrupts. 85 sRescheduleFunction = gScheduler->reschedule; 86 gScheduler->reschedule = scheduler_reschedule_no_op; 87 88 #if SCHEDULER_TRACING 89 add_debugger_command_etc("scheduler", &cmd_scheduler, 90 "Analyze scheduler tracing information", 91 "<thread>\n" 92 "Analyzes scheduler tracing information for a given thread.\n" 93 " <thread> - ID of the thread.\n", 0); 94 #endif 95 } 96 97 98 void 99 scheduler_enable_scheduling(void) 100 { 101 gScheduler->reschedule = sRescheduleFunction; 102 } 103 104 105 // #pragma mark - Syscalls 106 107 108 bigtime_t 109 _user_estimate_max_scheduling_latency(thread_id id) 110 { 111 syscall_64_bit_return_value(); 112 113 // get the thread 114 Thread* thread; 115 if (id < 0) { 116 thread = thread_get_current_thread(); 117 thread->AcquireReference(); 118 } else { 119 thread = Thread::Get(id); 120 if (thread == NULL) 121 return 0; 122 } 123 BReference<Thread> threadReference(thread, true); 124 125 // ask the scheduler for the thread's latency 126 InterruptsSpinLocker locker(gSchedulerLock); 127 return gScheduler->estimate_max_scheduling_latency(thread); 128 } 129