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
18struct scheduler_ops* gScheduler;
19spinlock gSchedulerLock = B_SPINLOCK_INITIALIZER;
20SchedulerListenerList gSchedulerListeners;
21
22static void (*sRescheduleFunction)(void);
23
24
25static void
26scheduler_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
37SchedulerListener::~SchedulerListener()
38{
39}
40
41
42// #pragma mark - kernel private
43
44
45/*!	Add the given scheduler listener. Thread lock must be held.
46*/
47void
48scheduler_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*/
56void
57scheduler_remove_listener(struct SchedulerListener* listener)
58{
59	gSchedulerListeners.Remove(listener);
60}
61
62
63void
64scheduler_init(void)
65{
66	int32 cpuCount = smp_get_num_cpus();
67	dprintf("scheduler_init: found %" B_PRId32 " 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
98void
99scheduler_enable_scheduling(void)
100{
101	gScheduler->reschedule = sRescheduleFunction;
102}
103
104
105// #pragma mark - Syscalls
106
107
108bigtime_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