1/*
2 * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2005-2010, Axel Dörfler, axeld@pinc-software.de.
4 * Distributed under the terms of the MIT License.
5 */
6#ifndef KERNEL_SCHEDULER_H
7#define KERNEL_SCHEDULER_H
8
9
10#include <cpu.h>
11#include <int.h>
12#include <smp.h>
13#include <thread_types.h>
14
15
16struct scheduling_analysis;
17struct SchedulerListener;
18
19
20struct scheduler_ops {
21	/*!	Enqueues the thread in the ready-to-run queue.
22		The caller must hold the scheduler lock (with disabled interrupts).
23	*/
24	void (*enqueue_in_run_queue)(Thread* thread);
25
26	/*!	Selects a thread from the ready-to-run queue and, if that's not the
27		calling thread, switches the current CPU's context to run the selected
28		thread.
29		If it's the same thread, the thread will just continue to run.
30		In either case, unless the thread is dead or is sleeping/waiting
31		indefinitely, the function will eventually return.
32		The caller must hold the scheduler lock (with disabled interrupts).
33	*/
34	void (*reschedule)(void);
35
36	/*!	Sets the given thread's priority.
37		The thread may be running or may be in the ready-to-run queue.
38		The caller must hold the scheduler lock (with disabled interrupts).
39	*/
40	void (*set_thread_priority)(Thread* thread, int32 priority);
41	bigtime_t (*estimate_max_scheduling_latency)(Thread* thread);
42
43	/*!	Called when the Thread structure is first created.
44		Per-thread housekeeping resources can be allocated.
45		Interrupts must be enabled.
46	*/
47	status_t (*on_thread_create)(Thread* thread, bool idleThread);
48
49	/*!	Called when a Thread structure is initialized and made ready for
50		use.
51		The per-thread housekeeping data structures are reset, if needed.
52		The caller must hold the scheduler lock (with disabled interrupts).
53	*/
54	void (*on_thread_init)(Thread* thread);
55
56	/*!	Called when a Thread structure is freed.
57		Frees up any per-thread resources allocated on the scheduler's part. The
58		function may be called even if on_thread_create() failed.
59		Interrupts must be enabled.
60	*/
61	void (*on_thread_destroy)(Thread* thread);
62
63	/*!	Called in the early boot process to start thread scheduling on the
64		current CPU.
65		The function is called once for each CPU.
66		Interrupts must be disabled, but the caller must not hold the scheduler
67		lock.
68	*/
69	void (*start)(void);
70};
71
72extern struct scheduler_ops* gScheduler;
73extern spinlock gSchedulerLock;
74
75#define scheduler_enqueue_in_run_queue(thread)	\
76				gScheduler->enqueue_in_run_queue(thread)
77#define scheduler_set_thread_priority(thread, priority)	\
78				gScheduler->set_thread_priority(thread, priority)
79#define scheduler_reschedule()	gScheduler->reschedule()
80#define scheduler_start()		gScheduler->start()
81#define scheduler_on_thread_create(thread, idleThread) \
82				gScheduler->on_thread_create(thread, idleThread)
83#define scheduler_on_thread_init(thread) \
84				gScheduler->on_thread_init(thread)
85#define scheduler_on_thread_destroy(thread) \
86				gScheduler->on_thread_destroy(thread)
87
88#ifdef __cplusplus
89extern "C" {
90#endif
91
92void scheduler_add_listener(struct SchedulerListener* listener);
93void scheduler_remove_listener(struct SchedulerListener* listener);
94
95void scheduler_init(void);
96void scheduler_enable_scheduling(void);
97
98bigtime_t _user_estimate_max_scheduling_latency(thread_id thread);
99status_t _user_analyze_scheduling(bigtime_t from, bigtime_t until, void* buffer,
100	size_t size, struct scheduling_analysis* analysis);
101
102#ifdef __cplusplus
103}
104#endif
105
106
107/*!	Reschedules, if necessary.
108	The caller must hold the scheduler lock (with disabled interrupts).
109*/
110static inline void
111scheduler_reschedule_if_necessary_locked()
112{
113	if (gCPU[smp_get_current_cpu()].invoke_scheduler)
114		scheduler_reschedule();
115}
116
117
118/*!	Reschedules, if necessary.
119	Is a no-op, if interrupts are disabled.
120*/
121static inline void
122scheduler_reschedule_if_necessary()
123{
124	if (are_interrupts_enabled()) {
125		cpu_status state = disable_interrupts();
126		acquire_spinlock(&gSchedulerLock);
127
128		scheduler_reschedule_if_necessary_locked();
129
130		release_spinlock(&gSchedulerLock);
131		restore_interrupts(state);
132	}
133}
134
135
136#endif /* KERNEL_SCHEDULER_H */
137