3 * at the start, there's a single process. core_init() is called system
4 * initialisation. it starts a thread, the switcher thread.
6 * the main thread runs the "current" aros task. thats all. if left unchecked,
7 * it would run the same task forever. thats not much fun though, which is
8 * what the switcher thread is for.
10 * the switcher thread receives interrupts from a variety of sources (virtual
11 * hardware) including a timer thread (for normal task switch operation). when
12 * an interrupt occurs, the following happens (high level)
14 * - switcher signals main that its time for a context switch
15 * - main responds by storing the current context and then waiting
16 * - switcher saves the current context into the current aros task
17 * - switcher runs the scheduler with the current interrupt state
18 * - switcher loads the context for the scheduled task as the new current context
19 * - switcher signals main
20 * - main wakes up and jumps to the current context
21 * - switcher loops and waits for the next interrupt
26 #include <aros/system.h>
27 #include <exec/types.h>
34 #include <semaphore.h>
37 #include <exec/lists.h>
38 #include <exec/execbase.h>
40 #include "kernel_intern.h"
42 #include "host_debug.h"
44 struct ExecBase **SysBasePtr;
45 struct KernelBase **KernelBasePtr;
51 void core_intr_disable(void) {
52 D(printf("[kernel] disabling interrupts\n"));
56 void core_intr_enable(void) {
57 D(printf("[kernel] enabling interrupts\n"));
61 int core_is_super(void) {
65 pthread_t main_thread;
66 pthread_t switcher_thread;
67 pthread_t timer_thread;
69 unsigned long timer_period;
71 pthread_mutex_t irq_lock = PTHREAD_MUTEX_INITIALIZER;
72 pthread_cond_t irq_cond = PTHREAD_COND_INITIALIZER;
83 void core_syscall(syscall_id_t type) {
86 pthread_mutex_lock(&irq_lock);
88 pthread_mutex_unlock(&irq_lock);
90 pthread_cond_signal(&irq_cond);
93 static void *timer_entry(void *arg) {
97 clock_gettime(CLOCK_REALTIME, &ts);
98 ts.tv_nsec += 1000000000 / timer_period;
99 if (ts.tv_nsec > 999999999) {
100 ts.tv_nsec -= 1000000000;
103 clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &ts, NULL);
105 pthread_mutex_lock(&irq_lock);
107 pthread_mutex_unlock(&irq_lock);
109 pthread_cond_signal(&irq_cond);
113 static void *switcher_entry(void *arg) {
114 uint32_t irq_bits_current;
118 sem_init(&main_sem, 0, 0);
119 sem_init(&switcher_sem, 0, 0);
122 /* wait for an interrupt */
123 pthread_mutex_lock(&irq_lock);
124 while (irq_bits == 0) pthread_cond_wait(&irq_cond, &irq_lock);
126 /* save the current interrupt bits and allow new interrupts to occur */
127 irq_bits_current = irq_bits;
129 pthread_mutex_unlock(&irq_lock);
131 D(printf("[kernel] interrupt received, irq bits are 0x%x\n", irq_bits_current));
133 /* tell the main task to stop and wait for its signal to proceed */
134 if (sleep_state != ss_SLEEPING) {
136 pthread_kill(main_thread, SIGUSR1);
137 sem_wait(&switcher_sem);
142 if (irq_bits_current & 0x2) {
145 core_Cause(*SysBasePtr);
149 core_Dispatch(&last_ctx, &next_ctx);
153 core_Switch(&last_ctx, &next_ctx);
157 core_Schedule(&last_ctx, &next_ctx);
162 /* if interrupts are enabled, then its time to schedule a new task */
164 core_ExitInterrupt(&last_ctx, &next_ctx);
168 /* if we're sleeping then we don't want to wake the main task just now */
169 if (sleep_state != ss_RUNNING)
170 sleep_state = ss_SLEEPING;
172 /* ready to go, give the main task a kick */
180 static void main_switch_handler(int signo, siginfo_t *si, void *vctx) {
181 /* make sure we were signalled by the switcher thread and not somewhere else */
182 if (sem_trywait(&main_sem) < 0)
185 /* switcher thread is now waiting for us. save the current context somewhere it can get it */
186 memcpy(&last_ctx, vctx, sizeof(ucontext_t));
188 /* tell the switcher to proceed */
189 sem_post(&switcher_sem);
191 /* wait for it to run the scheduler and whatever else */
194 /* switcher has given us the new context, jump to it */
195 setcontext(&next_ctx);
198 int core_init(unsigned long TimerPeriod, struct ExecBase **SysBasePointer, struct KernelBase **KernelBasePointer) {
200 pthread_attr_t thread_attrs;
204 D(printf("[kernel] initialising interrupts and task switching\n"));
206 SysBasePtr = SysBasePointer;
207 KernelBasePtr = KernelBasePointer;
213 timer_period = TimerPeriod;
215 sa.sa_flags = SA_SIGINFO;
216 sa.sa_sigaction = main_switch_handler;
217 sigaction(SIGUSR1, &sa, NULL);
219 main_thread = pthread_self();
221 pthread_attr_init(&thread_attrs);
222 pthread_attr_setdetachstate(&thread_attrs, PTHREAD_CREATE_DETACHED);
223 pthread_create(&switcher_thread, &thread_attrs, switcher_entry, NULL);
224 pthread_create(&timer_thread, &thread_attrs, timer_entry, NULL);
226 D(printf("[kernel] threads started, switcher id %d, timer id %d\n", switcher_thread, timer_thread));