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
));