direct-io.hg

view extras/mini-os/sched.c @ 11356:af7c87d42bc6

[XEN][POWERPC] Fix PHDR issues with large .data.percpu sections

This patch tells the link to only create one PHDR and place all sections
in it, also removing an unrequired mapping for the .data.percpu section.

This avoids the "Not enough room for program headers (allocated 2, need 3)"

Booted on a JS20.

Signed-off-by: Tony Breeds <tony@bakeyournoodle.com>
Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>
author Jimi Xenidis <jimix@watson.ibm.com>
date Thu Aug 17 07:10:57 2006 -0400 (2006-08-17)
parents 62c8e97d56cf
children 0839db0aa611
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>
50 #ifdef SCHED_DEBUG
51 #define DEBUG(_f, _a...) \
52 printk("MINI_OS(file=sched.c, line=%d) " _f "\n", __LINE__, ## _a)
53 #else
54 #define DEBUG(_f, _a...) ((void)0)
55 #endif
58 #define RUNNABLE_FLAG 0x00000001
60 #define is_runnable(_thread) (_thread->flags & RUNNABLE_FLAG)
61 #define set_runnable(_thread) (_thread->flags |= RUNNABLE_FLAG)
62 #define clear_runnable(_thread) (_thread->flags &= ~RUNNABLE_FLAG)
65 struct thread *idle_thread = NULL;
66 LIST_HEAD(exited_threads);
68 void idle_thread_fn(void *unused);
70 void dump_stack(struct thread *thread)
71 {
72 unsigned long *bottom = (unsigned long *)(thread->stack + 2*4*1024);
73 unsigned long *pointer = (unsigned long *)thread->sp;
74 int count;
75 if(thread == current)
76 {
77 #ifdef __i386__
78 asm("movl %%esp,%0"
79 : "=r"(pointer));
80 #else
81 asm("movq %%rsp,%0"
82 : "=r"(pointer));
83 #endif
84 }
85 printk("The stack for \"%s\"\n", thread->name);
86 for(count = 0; count < 25 && pointer < bottom; count ++)
87 {
88 printk("[0x%lx] 0x%lx\n", pointer, *pointer);
89 pointer++;
90 }
92 if(pointer < bottom) printk(" ... continues.\n");
93 }
95 #ifdef __i386__
96 #define switch_threads(prev, next) do { \
97 unsigned long esi,edi; \
98 __asm__ __volatile__("pushfl\n\t" \
99 "pushl %%ebp\n\t" \
100 "movl %%esp,%0\n\t" /* save ESP */ \
101 "movl %4,%%esp\n\t" /* restore ESP */ \
102 "movl $1f,%1\n\t" /* save EIP */ \
103 "pushl %5\n\t" /* restore EIP */ \
104 "ret\n\t" \
105 "1:\t" \
106 "popl %%ebp\n\t" \
107 "popfl" \
108 :"=m" (prev->sp),"=m" (prev->ip), \
109 "=S" (esi),"=D" (edi) \
110 :"m" (next->sp),"m" (next->ip), \
111 "2" (prev), "d" (next)); \
112 } while (0)
113 #elif __x86_64__
114 #define switch_threads(prev, next) do { \
115 unsigned long rsi,rdi; \
116 __asm__ __volatile__("pushfq\n\t" \
117 "pushq %%rbp\n\t" \
118 "movq %%rsp,%0\n\t" /* save RSP */ \
119 "movq %4,%%rsp\n\t" /* restore RSP */ \
120 "movq $1f,%1\n\t" /* save RIP */ \
121 "pushq %5\n\t" /* restore RIP */ \
122 "ret\n\t" \
123 "1:\t" \
124 "popq %%rbp\n\t" \
125 "popfq" \
126 :"=m" (prev->sp),"=m" (prev->ip), \
127 "=S" (rsi),"=D" (rdi) \
128 :"m" (next->sp),"m" (next->ip), \
129 "2" (prev), "d" (next)); \
130 } while (0)
131 #endif
133 void inline print_runqueue(void)
134 {
135 struct list_head *it;
136 struct thread *th;
137 list_for_each(it, &idle_thread->thread_list)
138 {
139 th = list_entry(it, struct thread, thread_list);
140 printk(" Thread \"%s\", runnable=%d\n", th->name, is_runnable(th));
141 }
142 printk("\n");
143 }
146 void schedule(void)
147 {
148 struct thread *prev, *next, *thread;
149 struct list_head *iterator;
150 unsigned long flags;
151 prev = current;
152 local_irq_save(flags);
153 list_for_each(iterator, &exited_threads)
154 {
155 thread = list_entry(iterator, struct thread, thread_list);
156 if(thread != prev)
157 {
158 list_del(&thread->thread_list);
159 free_pages(thread->stack, 1);
160 xfree(thread);
161 }
162 }
163 next = idle_thread;
164 /* Thread list needs to be protected */
165 list_for_each(iterator, &idle_thread->thread_list)
166 {
167 thread = list_entry(iterator, struct thread, thread_list);
168 if(is_runnable(thread))
169 {
170 next = thread;
171 /* Put this thread on the end of the list */
172 list_del(&thread->thread_list);
173 list_add_tail(&thread->thread_list, &idle_thread->thread_list);
174 break;
175 }
176 }
177 local_irq_restore(flags);
178 /* Interrupting the switch is equivalent to having the next thread
179 inturrupted at the return instruction. And therefore at safe point. */
180 if(prev != next) switch_threads(prev, next);
181 }
184 /* Gets run when a new thread is scheduled the first time ever,
185 defined in x86_[32/64].S */
186 extern void thread_starter(void);
189 void exit_thread(void)
190 {
191 unsigned long flags;
192 struct thread *thread = current;
193 printk("Thread \"%s\" exited.\n", thread->name);
194 local_irq_save(flags);
195 /* Remove from the thread list */
196 list_del(&thread->thread_list);
197 clear_runnable(thread);
198 /* Put onto exited list */
199 list_add(&thread->thread_list, &exited_threads);
200 local_irq_restore(flags);
201 /* Schedule will free the resources */
202 schedule();
203 }
205 /* Pushes the specified value onto the stack of the specified thread */
206 static void stack_push(struct thread *thread, unsigned long value)
207 {
208 thread->sp -= sizeof(unsigned long);
209 *((unsigned long *)thread->sp) = value;
210 }
212 struct thread* create_thread(char *name, void (*function)(void *), void *data)
213 {
214 struct thread *thread;
215 unsigned long flags;
217 thread = xmalloc(struct thread);
218 /* Allocate 2 pages for stack, stack will be 2pages aligned */
219 thread->stack = (char *)alloc_pages(1);
220 thread->name = name;
221 printk("Thread \"%s\": pointer: 0x%lx, stack: 0x%lx\n", name, thread,
222 thread->stack);
224 thread->sp = (unsigned long)thread->stack + 4096 * 2;
225 /* Save pointer to the thread on the stack, used by current macro */
226 *((unsigned long *)thread->stack) = (unsigned long)thread;
228 stack_push(thread, (unsigned long) function);
229 stack_push(thread, (unsigned long) data);
230 thread->ip = (unsigned long) thread_starter;
232 /* Not runable, not exited */
233 thread->flags = 0;
234 set_runnable(thread);
235 local_irq_save(flags);
236 if(idle_thread != NULL) {
237 list_add_tail(&thread->thread_list, &idle_thread->thread_list);
238 } else if(function != idle_thread_fn)
239 {
240 printk("BUG: Not allowed to create thread before initialising scheduler.\n");
241 BUG();
242 }
243 local_irq_restore(flags);
244 return thread;
245 }
248 void block(struct thread *thread)
249 {
250 clear_runnable(thread);
251 }
253 void wake(struct thread *thread)
254 {
255 set_runnable(thread);
256 }
258 void idle_thread_fn(void *unused)
259 {
260 for(;;)
261 {
262 schedule();
263 block_domain(10000);
264 }
265 }
267 void run_idle_thread(void)
268 {
269 /* Switch stacks and run the thread */
270 #if defined(__i386__)
271 __asm__ __volatile__("mov %0,%%esp\n\t"
272 "push %1\n\t"
273 "ret"
274 :"=m" (idle_thread->sp)
275 :"m" (idle_thread->ip));
276 #elif defined(__x86_64__)
277 __asm__ __volatile__("mov %0,%%rsp\n\t"
278 "push %1\n\t"
279 "ret"
280 :"=m" (idle_thread->sp)
281 :"m" (idle_thread->ip));
282 #endif
283 }
287 DECLARE_MUTEX(mutex);
289 void th_f1(void *data)
290 {
291 struct timeval tv1, tv2;
293 for(;;)
294 {
295 down(&mutex);
296 printk("Thread \"%s\" got semaphore, runnable %d\n", current->name, is_runnable(current));
297 schedule();
298 printk("Thread \"%s\" releases the semaphore\n", current->name);
299 up(&mutex);
302 gettimeofday(&tv1);
303 for(;;)
304 {
305 gettimeofday(&tv2);
306 if(tv2.tv_sec - tv1.tv_sec > 2) break;
307 }
310 schedule();
311 }
312 }
314 void th_f2(void *data)
315 {
316 for(;;)
317 {
318 printk("Thread OTHER executing, data 0x%lx\n", data);
319 schedule();
320 }
321 }
325 void init_sched(void)
326 {
327 printk("Initialising scheduler\n");
329 idle_thread = create_thread("Idle", idle_thread_fn, NULL);
330 INIT_LIST_HEAD(&idle_thread->thread_list);
331 }