xref: /haiku/src/system/kernel/scheduler/scheduler_common.h (revision fccd8899fcb583bfb73c5c26c9fcd714b963959b)
1 /*
2  * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 #ifndef KERNEL_SCHEDULER_COMMON_H
6 #define KERNEL_SCHEDULER_COMMON_H
7 
8 
9 #include <kscheduler.h>
10 #include <smp.h>
11 #include <user_debugger.h>
12 
13 
14 /*!	Switches the currently running thread.
15 	This is a service function for scheduler implementations.
16 
17 	\param fromThread The currently running thread.
18 	\param toThread The thread to switch to. Must be different from
19 		\a fromThread.
20 */
21 static inline void
22 scheduler_switch_thread(Thread* fromThread, Thread* toThread)
23 {
24 	// notify the user debugger code
25 	if ((fromThread->flags & THREAD_FLAGS_DEBUGGER_INSTALLED) != 0)
26 		user_debug_thread_unscheduled(fromThread);
27 
28 	// stop CPU time based user timers
29 	if (fromThread->HasActiveCPUTimeUserTimers()
30 		|| fromThread->team->HasActiveCPUTimeUserTimers()) {
31 		user_timer_stop_cpu_timers(fromThread, toThread);
32 	}
33 
34 	// update CPU and Thread structures and perform the context switch
35 	cpu_ent* cpu = fromThread->cpu;
36 	toThread->previous_cpu = toThread->cpu = cpu;
37 	fromThread->cpu = NULL;
38 	cpu->running_thread = toThread;
39 	cpu->previous_thread = fromThread;
40 
41 	arch_thread_set_current_thread(toThread);
42 	arch_thread_context_switch(fromThread, toThread);
43 
44 	// The use of fromThread below looks weird, but is correct. fromThread had
45 	// been unscheduled earlier, but is back now. For a thread scheduled the
46 	// first time the same is done in thread.cpp:common_thread_entry().
47 
48 	// continue CPU time based user timers
49 	if (fromThread->HasActiveCPUTimeUserTimers()
50 		|| fromThread->team->HasActiveCPUTimeUserTimers()) {
51 		user_timer_continue_cpu_timers(fromThread, cpu->previous_thread);
52 	}
53 
54 	// notify the user debugger code
55 	if ((fromThread->flags & THREAD_FLAGS_DEBUGGER_INSTALLED) != 0)
56 		user_debug_thread_scheduled(fromThread);
57 }
58 
59 
60 static inline void
61 scheduler_update_thread_times(Thread* oldThread, Thread* nextThread)
62 {
63 	bigtime_t now = system_time();
64 	if (oldThread == nextThread) {
65 		acquire_spinlock(&oldThread->time_lock);
66 		oldThread->kernel_time += now - oldThread->last_time;
67 		oldThread->last_time = now;
68 		release_spinlock(&oldThread->time_lock);
69 	} else {
70 		acquire_spinlock(&oldThread->time_lock);
71 		oldThread->kernel_time += now - oldThread->last_time;
72 		release_spinlock(&oldThread->time_lock);
73 
74 		acquire_spinlock(&nextThread->time_lock);
75 		nextThread->last_time = now;
76 		release_spinlock(&nextThread->time_lock);
77 	}
78 
79 	// If the old thread's team has user time timers, check them now.
80 	Team* team = oldThread->team;
81 	if (team->HasActiveUserTimeUserTimers())
82 		user_timer_check_team_user_timers(team);
83 }
84 
85 
86 #endif	// KERNEL_SCHEDULER_COMMON_H
87