source: trunk/kernel/kern/scheduler.c @ 54

Last change on this file since 54 was 14, checked in by alain, 7 years ago

Bugs fix.

File size: 10.0 KB
Line 
1/*
2 * scheduler.c - Core scheduler implementation.
3 *
4 * Author    Alain Greiner (2016)
5 *
6 * Copyright (c)  UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH.
9 *
10 * ALMOS-MKH. is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH. is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-MKH.; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24#include <kernel_config.h>
25#include <hal_types.h>
26#include <hal_irqmask.h>
27#include <hal_context.h>
28#include <printk.h>
29#include <list.h>
30#include <core.h>
31#include <thread.h>
32#include <scheduler.h>
33
34
35////////////////////////////////
36void sched_init( core_t * core )
37{
38    scheduler_t * sched = &core->scheduler;
39
40    sched->u_threads_nr   = 0;
41    sched->k_threads_nr   = 0;
42
43    sched->current        = NULL;
44    sched->idle           = NULL;
45    sched->u_last         = NULL;
46    sched->k_last         = NULL;
47
48    // initialise threads lists
49    list_root_init( &sched->u_root );
50    list_root_init( &sched->k_root );
51
52}  // end sched_init()
53
54////////////////////////////////////////////
55void sched_register_thread( core_t   * core,
56                            thread_t * thread )
57{
58    scheduler_t * sched = &core->scheduler;
59    thread_type_t type  = thread->type;
60
61    // take lock protecting sheduler lists
62    spinlock_lock( &sched->lock );
63
64    // register thread
65    if( type == THREAD_USER )
66    {
67        list_add_last( &sched->u_root , &thread->sched_list );
68        sched->u_threads_nr++;
69    }
70    else // kernel thread
71    {
72        list_add_last( &sched->k_root , &thread->sched_list );
73        sched->k_threads_nr++;
74    }
75
76    // release lock
77    spinlock_unlock( &sched->lock );
78
79}  // end sched_register()
80
81/////////////////////////////////////////////
82void sched_remove_thread( thread_t * thread )
83{
84    core_t       * core  = thread->core;
85    scheduler_t  * sched = &core->scheduler;
86    thread_type_t  type  = thread->type;
87
88    // take lock protecting sheduler lists
89    spinlock_lock( &sched->lock );
90
91    // remove thread
92    if( type == THREAD_USER )
93    {
94        list_unlink( &thread->sched_list );
95        sched->u_threads_nr--;
96    }
97    else // kernel thread
98    {
99        list_unlink( &thread->sched_list );
100        sched->k_threads_nr--;
101    }
102
103    // release lock
104    spinlock_unlock( &sched->lock );
105
106}  // end sched_remove()
107
108///////////////////////////////////////////
109void sched_kill_thread( thread_t * thread )
110{
111    // check thread locks
112    if( thread_can_yield() == false )
113    {
114        printk("\n[PANIC] in %s : thread %x in process %x on core[%x][%d]"
115               " did not released all locks\n",
116               __FUNCTION__ , thread->trdid , thread->process->pid, 
117               local_cxy , thread->core->lid ); 
118        hal_core_sleep();
119    }
120
121    // remove thread from scheduler
122    sched_remove_thread( thread );
123
124    // reset the THREAD_SIG_KILL signal
125    thread_reset_signal( thread , THREAD_SIG_KILL );
126
127}  // end sched_kill_thread()
128
129////////////////////////////////////////
130thread_t * sched_select( core_t * core )
131{
132    thread_t * thread;
133
134    scheduler_t * sched = &core->scheduler;
135
136    // take lock protecting sheduler lists
137    spinlock_lock( &sched->lock );
138
139    list_entry_t * current;
140    list_entry_t * last;
141
142    // first scan the kernel threads
143    last    = sched->k_last;
144    current = sched->k_last;
145    do
146    {
147        // get next entry in kernel list
148        current = list_next( &sched->k_root , current );
149
150        // skip the list root that does not contain a thread
151        if( current == NULL ) continue;
152
153        // get thread pointer
154        thread = LIST_ELEMENT( current , thread_t , sched_list );
155
156        // return thread if not blocked
157        if( thread->blocked == 0 ) 
158        {
159            // release lock
160            spinlock_unlock( &sched->lock );
161            return thread;
162        }
163    }
164    while( current != last );
165
166    // second scan the user threads
167    last    = sched->u_last;
168    current = sched->u_last;
169    do
170    {
171        // get next entry in user list
172        current = list_next( &sched->u_root , current );
173
174        // skip the list root that does not contain a thread
175        if( current == NULL ) continue;
176
177        // get thread pointer
178        thread = LIST_ELEMENT( current , thread_t , sched_list );
179
180        // return thread if not blocked
181        if( thread->blocked == 0 )
182        {
183            // release lock
184            spinlock_unlock( &sched->lock );
185            return thread;
186        }
187    }
188    while( current != last );
189
190    // release lock
191    spinlock_unlock( &sched->lock );
192
193    // third, return idle thread if no runnable thread
194    return sched->idle;
195
196}  // end sched_elect()
197
198//////////////////////////////////////////
199void sched_handle_signals( core_t * core )
200{
201    list_entry_t * iter;
202    thread_t     * thread;
203
204    scheduler_t  * sched = &core->scheduler;
205
206    // take lock protecting threads lists
207    spinlock_lock( &sched->lock );
208
209    // handle user threads
210    LIST_FOREACH( &sched->u_root , iter )
211    {
212        thread = LIST_ELEMENT( iter , thread_t , sched_list );
213        if( thread->signals & THREAD_SIG_KILL )  sched_kill_thread( thread );
214    }
215
216    // handle kernel threads
217    LIST_FOREACH( &sched->k_root , iter )
218    {
219        thread = LIST_ELEMENT( iter , thread_t , sched_list );
220        if( thread->signals & THREAD_SIG_KILL )  sched_kill_thread( thread );
221    }
222
223    // release lock
224    spinlock_unlock( &sched->lock );
225
226} // end sched_handle_signals()
227
228//////////////////
229void sched_yield()
230{
231    uint32_t      sr_save;
232    thread_t    * next;
233
234    thread_t    * current = CURRENT_THREAD;
235    core_t      * core    = current->core;
236
237    if( thread_can_yield() == false )
238    {
239        printk("\n[PANIC] in %s : thread %x for process %x on core_gid %x"
240               " has not released all locks at cycle %d\n",
241               __FUNCTION__, current->trdid, current->process->pid, 
242               local_cxy , core->lid , hal_time_stamp() );
243        hal_core_sleep();
244    }
245
246    // desactivate IRQs
247    hal_disable_irq( &sr_save );
248
249    // first loop on all threads to handle pending signals
250    sched_handle_signals( core );
251
252    // second loop on threads to select next thread
253    next = sched_select( core );
254
255    // check stack overflow for selected thread
256    if( next->signature != THREAD_SIGNATURE )
257    {
258        printk("\n[PANIC] in %s : detected stack overflow for thread %x of process %x"
259               " on core [%x][%d]\n",
260               __FUNCTION__, next->trdid, next->process->pid, local_cxy , core->lid );
261        hal_core_sleep();
262        }
263       
264        sched_dmsg("\n[INFO] %s on core %d in cluster %x / old thread = %x / new thread = %x\n",
265               __FUNCTION__, core->lid, local_cxy, current->trdid, next->trdid );
266
267    // switch contexts if new thread
268        if( next != current ) 
269        {
270        hal_cpu_context_save( current );
271        hal_cpu_context_restore( next );
272        }
273
274    // restore IRQs
275    hal_restore_irq( sr_save );
276
277        if( current->type != THREAD_USER ) return;
278
279        if( current == core->fpu_owner )  hal_fpu_enable();
280        else                              hal_fpu_disable();
281
282}  // end sched_yield()
283
284//////////////////////////////////////
285void sched_switch_to( thread_t * new )
286{
287    uint32_t      sr_save;
288
289    thread_t    * current = CURRENT_THREAD;
290    core_t      * core    = current->core;
291    process_t   * process = current->process;
292
293    // check calling thread released all locks
294    if( thread_can_yield() == false )
295    {
296        printk("\n[PANIC] in %s : thread %x for process %x on core %d in cluster %x"
297               " has not released all locks\n",
298               __FUNCTION__, current->trdid, process->pid, core->lid, local_cxy );
299        hal_core_sleep();
300    }
301
302    // check new thread attached to same core as the calling thread
303    if( new->core != current->core )
304    {
305        printk("\n[PANIC] in %s : new thread %x is attached to core %d"
306               " different from core %d of current thread\n",
307               __FUNCTION__, new->trdid, new->core->lid, core->lid , current->trdid );
308        hal_core_sleep();
309    }
310
311    // check new thread not blocked
312    if( new->blocked == 0 )
313    {
314        printk("\n[PANIC] in %s for thread %x of process %x on core %d in cluster %x"
315               " : new thread %x is blocked\n",
316               __FUNCTION__, current->trdid, process->pid , core->lid, local_cxy , new->trdid );
317        hal_core_sleep();
318    }
319
320    // check stack overflow for new thread
321    if( new->signature != THREAD_SIGNATURE )
322    {
323        printk("\n[PANIC] in %s : stack overflow for new thread %x of process %x"
324               " on core %d in cluster %x\n",
325               __FUNCTION__, new->trdid, process->pid , core->lid , local_cxy );
326        hal_core_sleep();
327        }
328
329    // desactivate IRQs
330    hal_disable_irq( &sr_save );
331
332    // loop on all threads to handle pending signals
333    sched_handle_signals( core );
334
335    // check stack overflow for new thread
336    if( new->signature != THREAD_SIGNATURE )
337    {
338        printk("PANIC %s detected stack overflow for thread %x of process %x"
339               " on core %d in cluster %x\n",
340               __FUNCTION__, new->trdid, new->process->pid, core->lid, local_cxy);
341        hal_core_sleep();
342        }
343       
344        sched_dmsg("INFO : %s on core %d in cluster %x / old thread = %x / new thread = %x\n",
345               __FUNCTION__, core->lid, local_cxy, current->trdid, new->trdid );
346
347    // switch contexts if new thread
348    hal_cpu_context_save( current );
349    hal_cpu_context_restore( new );
350
351    // restore IRQs
352    hal_restore_irq( sr_save );
353
354        if( current->type != THREAD_USER ) return;
355
356        if( current == core->fpu_owner )  hal_fpu_enable();
357        else                              hal_fpu_disable();
358
359}  // end sched_switch_to()
360
Note: See TracBrowser for help on using the repository browser.