Added context-switching and a yield() function.
[marionette.git] / kernel / thread.c
blob0f77f4a59c1b79c54201f9845608bed9dd55624e
1 /*
2 * Copyright (c) 2008 Joshua Phillips. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
15 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
16 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #define USE_TRACE
30 #include "thread.h"
31 #include "stdlib.h"
32 #include "string.h"
33 #include "console.h"
35 static struct thread *thread_first = NULL;
36 static struct thread *thread_last = NULL;
37 static struct thread *thread_current = NULL;
39 // defined in thread-asm.S
40 void context_switch(struct pusha_struct *regs, uint32_t eip, uint32_t eflags);
41 void store_call(void (* func_ptr)(void));
43 void thread_save_call_state(uint32_t ebx, uint32_t esp, uint32_t ebp, uint32_t esi, uint32_t edi, uint32_t eip, uint32_t eflags)
45 if (!thread_current){
46 return;
48 thread_current->regs.eax = 0;
49 thread_current->regs.ecx = 0;
50 thread_current->regs.edx = 0;
51 thread_current->regs.ebx = ebx;
52 thread_current->regs.esp = esp;
53 thread_current->regs.ebp = ebp;
54 thread_current->regs.esi = esi;
55 thread_current->regs.edi = edi;
56 thread_current->eip = eip;
57 thread_current->eflags = eflags;
60 static struct thread *get_next_thread(void)
62 struct thread *t;
63 if (!thread_current){
64 t = thread_last;
65 } else {
66 t = thread_current;
68 if (!t){
69 return NULL;
71 for (;;){
72 if (t->next){
73 t = t->next;
74 } else {
75 t = thread_first;
77 if (t->suspend_count == 0){
78 return t;
83 static void switch_to_thread(struct thread *thread)
85 thread_current = thread;
86 if (thread->aspace){
87 addr_space_switch(thread->aspace);
89 trace("eip=0x%.8X, eflags=0x%.8X\n", thread->eip, thread->eflags);
90 trace("esp=0x%.8x\n", thread->regs.esp);
91 context_switch(&thread->regs, thread->eip, thread->eflags);
94 // initialize the threading system
95 void thread_sys_init(void)
100 // start the threading system
101 void thread_sys_start(void)
103 struct thread *next_thread;
104 next_thread = get_next_thread();
105 if (next_thread){
106 switch_to_thread(next_thread);
107 } else {
108 trace("thread_sys_start: no threads\n");
112 struct thread *thread_new(void)
114 struct thread *new_thread;
115 new_thread = malloc(sizeof *new_thread);
116 if (!new_thread){
117 return NULL;
120 // set thread as suspended
121 new_thread->suspend_count = 1;
123 // linked-list insert
124 new_thread->prev = thread_last;
125 if (thread_last){
126 thread_last->next = new_thread;
127 } else {
128 thread_first = new_thread;
130 new_thread->next = NULL;
131 thread_last = new_thread;
133 memset(&new_thread->regs, 0, sizeof new_thread->regs);
134 new_thread->eip = 0;
135 new_thread->eflags = 0x0202;
136 new_thread->aspace = NULL;
138 return new_thread;
141 void thread_set_aspace(struct thread *t, struct addr_space *aspace)
143 t->aspace = aspace;
146 void thread_set_eip(struct thread *t, uint32_t eip)
148 t->eip = eip;
151 void thread_set_esp(struct thread *t, uint32_t esp)
153 t->regs.esp = esp;
156 void thread_resume(struct thread *t)
158 if (t->suspend_count > 0){
159 t->suspend_count--;
163 void thread_suspend(struct thread *t)
165 t->suspend_count++;
166 // TODO: if this is the current thread,
167 // need to switch away from it.
170 void thread_delete(struct thread *t)
172 // TODO: if this is the current thread,
173 // need to switch away from it
174 // TODO; more cleanup
175 if (t->prev){
176 t->prev->next = t->next;
177 } else {
178 thread_first = t->next;
180 if (t->next){
181 t->next->prev = t->prev;
182 } else {
183 thread_last = t->prev;
185 free(t);
188 void yield_internal(void)
190 struct thread *next_thread;
191 next_thread = get_next_thread();
192 if (next_thread){
193 switch_to_thread(next_thread);
194 } else {
195 trace("yield_internal: no threads\n");
199 void yield(void)
201 store_call(yield_internal);