source: trunk/packages/xen-common/xen-common/extras/mini-os/sched.c @ 77

Last change on this file since 77 was 34, checked in by hartmans, 17 years ago

Add xen and xen-common

File size: 7.5 KB
Line 
1/*
2 ****************************************************************************
3 * (C) 2005 - Grzegorz Milos - Intel Research Cambridge
4 ****************************************************************************
5 *
6 *        File: sched.c
7 *      Author: Grzegorz Milos
8 *     Changes: Robert Kaiser
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 */
37
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>
48
49
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
56
57struct thread *idle_thread = NULL;
58LIST_HEAD(exited_threads);
59
60void inline print_runqueue(void)
61{
62    struct list_head *it;
63    struct thread *th;
64    list_for_each(it, &idle_thread->thread_list)
65    {
66        th = list_entry(it, struct thread, thread_list);
67        printk("   Thread \"%s\", runnable=%d\n", th->name, is_runnable(th));
68    }
69    printk("\n");
70}
71
72/* Find the time when the next timeout expires. If this is more than
73   10 seconds from now, return 10 seconds from now. */
74static s_time_t blocking_time(void)
75{
76    struct thread *thread;
77    struct list_head *iterator;
78    s_time_t min_wakeup_time;
79    unsigned long flags;
80    local_irq_save(flags);
81    /* default-block the domain for 10 seconds: */
82    min_wakeup_time = NOW() + SECONDS(10);
83
84    /* Thread list needs to be protected */
85    list_for_each(iterator, &idle_thread->thread_list)
86    {
87        thread = list_entry(iterator, struct thread, thread_list);
88        if(!is_runnable(thread) && thread->wakeup_time != 0LL)
89        {
90            if(thread->wakeup_time < min_wakeup_time)
91            {
92                min_wakeup_time = thread->wakeup_time;
93            }
94        }
95    }
96    local_irq_restore(flags);
97    return(min_wakeup_time);
98}
99
100/* Wake up all threads with expired timeouts. */
101static void wake_expired(void)
102{
103    struct thread *thread;
104    struct list_head *iterator;
105    s_time_t now = NOW();
106    unsigned long flags;
107    local_irq_save(flags);
108    /* Thread list needs to be protected */
109    list_for_each(iterator, &idle_thread->thread_list)
110    {
111        thread = list_entry(iterator, struct thread, thread_list);
112        if(!is_runnable(thread) && thread->wakeup_time != 0LL)
113        {
114            if(thread->wakeup_time <= now)
115                wake(thread);
116        }
117    }
118    local_irq_restore(flags);
119}
120
121void schedule(void)
122{
123    struct thread *prev, *next, *thread;
124    struct list_head *iterator;
125    unsigned long flags;
126    prev = current;
127    local_irq_save(flags); 
128    list_for_each(iterator, &exited_threads)
129    {
130        thread = list_entry(iterator, struct thread, thread_list);
131        if(thread != prev)
132        {
133            list_del(&thread->thread_list);
134            free_pages(thread->stack, 1);
135            xfree(thread);
136        }
137    }
138    next = idle_thread;   
139    /* Thread list needs to be protected */
140    list_for_each(iterator, &idle_thread->thread_list)
141    {
142        thread = list_entry(iterator, struct thread, thread_list);
143        if(is_runnable(thread)) 
144        {
145            next = thread;
146            /* Put this thread on the end of the list */
147            list_del(&thread->thread_list);
148            list_add_tail(&thread->thread_list, &idle_thread->thread_list);
149            break;
150        }
151    }
152    local_irq_restore(flags);
153    /* Interrupting the switch is equivalent to having the next thread
154       inturrupted at the return instruction. And therefore at safe point. */
155    if(prev != next) switch_threads(prev, next);
156}
157
158struct thread* create_thread(char *name, void (*function)(void *), void *data)
159{
160    struct thread *thread;
161    unsigned long flags;
162    /* Call architecture specific setup. */
163    thread = arch_create_thread(name, function, data);
164    /* Not runable, not exited, not sleeping */
165    thread->flags = 0;
166    thread->wakeup_time = 0LL;
167    set_runnable(thread);
168    local_irq_save(flags);
169    if(idle_thread != NULL) {
170        list_add_tail(&thread->thread_list, &idle_thread->thread_list); 
171    } else if(function != idle_thread_fn)
172    {
173        printk("BUG: Not allowed to create thread before initialising scheduler.\n");
174        BUG();
175    }
176    local_irq_restore(flags);
177    return thread;
178}
179
180void exit_thread(void)
181{
182    unsigned long flags;
183    struct thread *thread = current;
184    printk("Thread \"%s\" exited.\n", thread->name);
185    local_irq_save(flags);
186    /* Remove from the thread list */
187    list_del(&thread->thread_list);
188    clear_runnable(thread);
189    /* Put onto exited list */
190    list_add(&thread->thread_list, &exited_threads);
191    local_irq_restore(flags);
192    /* Schedule will free the resources */
193    schedule();
194}
195
196void block(struct thread *thread)
197{
198    thread->wakeup_time = 0LL;
199    clear_runnable(thread);
200}
201
202void sleep(u32 millisecs)
203{
204    struct thread *thread = get_current();
205    thread->wakeup_time = NOW()  + MILLISECS(millisecs);
206    clear_runnable(thread);
207    schedule();
208}
209
210void wake(struct thread *thread)
211{
212    thread->wakeup_time = 0LL;
213    set_runnable(thread);
214}
215
216void idle_thread_fn(void *unused)
217{
218    s_time_t until;
219    for(;;)
220    {
221        schedule();
222        /* block until the next timeout expires, or for 10 secs, whichever comes first */
223        until = blocking_time();
224        block_domain(until);
225        wake_expired();
226    }
227}
228
229DECLARE_MUTEX(mutex);
230
231void th_f1(void *data)
232{
233    struct timeval tv1, tv2;
234
235    for(;;)
236    {
237        down(&mutex);
238        printk("Thread \"%s\" got semaphore, runnable %d\n", current->name, is_runnable(current));
239        schedule();
240        printk("Thread \"%s\" releases the semaphore\n", current->name);
241        up(&mutex);
242       
243       
244        gettimeofday(&tv1);
245        for(;;)
246        {
247            gettimeofday(&tv2);
248            if(tv2.tv_sec - tv1.tv_sec > 2) break;
249        }
250               
251       
252        schedule(); 
253    }
254}
255
256void th_f2(void *data)
257{
258    for(;;)
259    {
260        printk("Thread OTHER executing, data 0x%lx\n", data);
261        schedule();
262    }
263}
264
265
266
267void init_sched(void)
268{
269    printk("Initialising scheduler\n");
270
271    idle_thread = create_thread("Idle", idle_thread_fn, NULL);
272    INIT_LIST_HEAD(&idle_thread->thread_list);
273}
274
Note: See TracBrowser for help on using the repository browser.