xref: /haiku/src/system/kernel/scheduler/scheduler.cpp (revision 7a74a5df454197933bc6e80a542102362ee98703)
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