ia64/xen-unstable

view extras/mini-os/sched.c @ 7238:971e7c7411b3

Raise an exception if an error appears on the pipes to our children, and make
sure that the child's pipes are closed even under that exception. Move the
handling of POLLHUP to the end of the loop, so that we guarantee to read any
remaining data from the child if POLLHUP and POLLIN appear at the same time.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@ewan
date Thu Oct 06 10:13:11 2005 +0100 (2005-10-06)
parents 06d84bf87159
children 1569bc48b0b8
line source
1 /*
2 ****************************************************************************
3 * (C) 2005 - Grzegorz Milos - Intel Research Cambridge
4 ****************************************************************************
5 *
6 * File: sched.c
7 * Author: Grzegorz Milos
8 * Changes:
9 *
10 * Date: Aug 2005
11 *
12 * Environment: Xen Minimal OS
13 * Description: simple scheduler for Mini-Os
14 *
15 * The scheduler is non-preemptive (cooperative), and schedules according
16 * to Round Robin algorithm.
17 *
18 ****************************************************************************
19 * Permission is hereby granted, free of charge, to any person obtaining a copy
20 * of this software and associated documentation files (the "Software"), to
21 * deal in the Software without restriction, including without limitation the
22 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
23 * sell copies of the Software, and to permit persons to whom the Software is
24 * furnished to do so, subject to the following conditions:
25 *
26 * The above copyright notice and this permission notice shall be included in
27 * all copies or substantial portions of the Software.
28 *
29 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
34 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
35 * DEALINGS IN THE SOFTWARE.
36 */
38 #include <os.h>
39 #include <hypervisor.h>
40 #include <time.h>
41 #include <mm.h>
42 #include <types.h>
43 #include <lib.h>
44 #include <xmalloc.h>
45 #include <list.h>
46 #include <sched.h>
47 #include <semaphore.h>
49 #ifdef SCHED_DEBUG
50 #define DEBUG(_f, _a...) \
51 printk("MINI_OS(file=sched.c, line=%d) " _f "\n", __LINE__, ## _a)
52 #else
53 #define DEBUG(_f, _a...) ((void)0)
54 #endif
57 #define RUNNABLE_FLAG 0x00000001
59 #define is_runnable(_thread) (_thread->flags & RUNNABLE_FLAG)
60 #define set_runnable(_thread) (_thread->flags |= RUNNABLE_FLAG)
61 #define clear_runnable(_thread) (_thread->flags &= ~RUNNABLE_FLAG)
64 struct thread *idle_thread;
65 LIST_HEAD(exited_threads);
67 void dump_stack(struct thread *thread)
68 {
69 unsigned long *bottom = (unsigned long *)thread->stack + 2048;
70 unsigned long *pointer = (unsigned long *)thread->eps;
71 int count;
72 printk("The stack for \"%s\"\n", thread->name);
73 for(count = 0; count < 15 && pointer < bottom; count ++)
74 {
75 printk("[0x%lx] 0x%lx\n", pointer, *pointer);
76 pointer++;
77 }
79 if(pointer < bottom) printk("Not the whole stack printed\n");
80 }
82 #ifdef __i386__
83 #define switch_threads(prev, next) do { \
84 unsigned long esi,edi; \
85 __asm__ __volatile__("pushfl\n\t" \
86 "pushl %%ebp\n\t" \
87 "movl %%esp,%0\n\t" /* save ESP */ \
88 "movl %4,%%esp\n\t" /* restore ESP */ \
89 "movl $1f,%1\n\t" /* save EIP */ \
90 "pushl %5\n\t" /* restore EIP */ \
91 "ret\n\t" \
92 "1:\t" \
93 "popl %%ebp\n\t" \
94 "popfl" \
95 :"=m" (prev->eps),"=m" (prev->eip), \
96 "=S" (esi),"=D" (edi) \
97 :"m" (next->eps),"m" (next->eip), \
98 "2" (prev), "d" (next)); \
99 } while (0)
100 #elif __x86_64__
101 /* FIXME */
102 #endif
104 void inline print_runqueue(void)
105 {
106 struct list_head *it;
107 struct thread *th;
108 list_for_each(it, &idle_thread->thread_list)
109 {
110 th = list_entry(it, struct thread, thread_list);
111 printk(" Thread \"%s\", runnable=%d\n", th->name, is_runnable(th));
112 }
113 printk("\n");
114 }
117 void schedule(void)
118 {
119 struct thread *prev, *next, *thread;
120 struct list_head *iterator;
121 unsigned long flags;
122 prev = current;
123 local_irq_save(flags);
124 list_for_each(iterator, &exited_threads)
125 {
126 thread = list_entry(iterator, struct thread, thread_list);
127 if(thread != prev)
128 {
129 list_del(&thread->thread_list);
130 free_pages(thread->stack, 1);
131 xfree(thread);
132 }
133 }
134 next = idle_thread;
135 /* Thread list needs to be protected */
136 list_for_each(iterator, &idle_thread->thread_list)
137 {
138 thread = list_entry(iterator, struct thread, thread_list);
139 if(is_runnable(thread))
140 {
141 next = thread;
142 /* Put this thread on the end of the list */
143 list_del(&thread->thread_list);
144 list_add_tail(&thread->thread_list, &idle_thread->thread_list);
145 break;
146 }
147 }
148 local_irq_restore(flags);
149 /* Interrupting the switch is equivalent to having the next thread
150 inturrupted at the return instruction. And therefore at safe point. */
151 /* The thread switching only works for i386 at the moment */
152 #ifdef __i386__
153 if(prev != next) switch_threads(prev, next);
154 #endif
155 }
159 void exit_thread(struct thread *thread)
160 {
161 unsigned long flags;
162 printk("Thread \"%s\" exited.\n", thread->name);
163 local_irq_save(flags);
164 /* Remove from the thread list */
165 list_del(&thread->thread_list);
166 clear_runnable(thread);
167 /* Put onto exited list */
168 list_add(&thread->thread_list, &exited_threads);
169 local_irq_restore(flags);
170 /* Schedule will free the resources */
171 schedule();
172 }
175 struct thread* create_thread(char *name, void (*function)(void *), void *data)
176 {
177 struct thread *thread;
178 unsigned long flags;
180 thread = xmalloc(struct thread);
181 /* Allocate 2 pages for stack, stack will be 2pages aligned */
182 thread->stack = (char *)alloc_pages(1);
183 thread->name = name;
184 printk("Thread \"%s\": pointer: 0x%lx, stack: 0x%lx\n", name, thread,
185 thread->stack);
187 thread->eps = (unsigned long)thread->stack + 4096 * 2 - 4;
188 /* Save pointer to the thread on the stack, used by current macro */
189 *((unsigned long *)thread->stack) = (unsigned long)thread;
190 *((unsigned long *)thread->eps) = (unsigned long)thread;
191 thread->eps -= 4;
192 *((unsigned long *)thread->eps) = (unsigned long)data;
194 /* No return address */
195 thread->eps -= 4;
196 *((unsigned long *)thread->eps) = (unsigned long)exit_thread;
198 thread->eip = (unsigned long)function;
200 /* Not runable, not exited */
201 thread->flags = 0;
202 set_runnable(thread);
204 local_irq_save(flags);
205 if(idle_thread != NULL)
206 list_add_tail(&thread->thread_list, &idle_thread->thread_list);
207 local_irq_restore(flags);
209 return thread;
210 }
213 void block(struct thread *thread)
214 {
215 clear_runnable(thread);
216 }
218 void wake(struct thread *thread)
219 {
220 set_runnable(thread);
221 }
223 void idle_thread_fn(void *unused)
224 {
225 for(;;)
226 {
227 schedule();
228 printk("Blocking the domain\n");
229 block_domain(10000);
230 }
231 }
233 void run_idle_thread(void)
234 {
235 /* Switch stacks and run the thread */
236 __asm__ __volatile__("mov %0,%%esp\n\t"
237 "push %1\n\t"
238 "ret"
239 :"=m" (idle_thread->eps)
240 :"m" (idle_thread->eip));
241 }
245 DECLARE_MUTEX(mutex);
247 void th_f1(void *data)
248 {
249 struct timeval tv1, tv2;
251 for(;;)
252 {
253 down(&mutex);
254 printk("Thread \"%s\" got semaphore, runnable %d\n", current->name, is_runnable(current));
255 schedule();
256 printk("Thread \"%s\" releases the semaphore\n", current->name);
257 up(&mutex);
260 gettimeofday(&tv1);
261 for(;;)
262 {
263 gettimeofday(&tv2);
264 if(tv2.tv_sec - tv1.tv_sec > 2) break;
265 }
268 schedule();
269 }
270 }
272 void th_f2(void *data)
273 {
274 for(;;)
275 {
276 printk("Thread OTHER executing, data 0x%lx\n", data);
277 schedule();
278 }
279 }
283 void init_sched(void)
284 {
285 printk("Initialising scheduler\n");
287 idle_thread = create_thread("Idle", idle_thread_fn, NULL);
288 INIT_LIST_HEAD(&idle_thread->thread_list);
291 /* create_thread("1", th_f1, (void *)0x1234);
292 create_thread("2", th_f1, (void *)0x1234);
293 create_thread("3", th_f1, (void *)0x1234);
294 create_thread("4", th_f1, (void *)0x1234);
295 create_thread("5", th_f1, (void *)0x1234);
296 create_thread("6", th_f1, (void *)0x1234);
297 create_thread("second", th_f2, NULL);
298 */
299 }