scheduler.c 29.4 KB
Newer Older
1
/*
mysterywolf's avatar
mysterywolf 已提交
2
 * Copyright (c) 2006-2021, RT-Thread Development Team
B
Bernard Xiong 已提交
3
 *
4
 * SPDX-License-Identifier: Apache-2.0
5 6 7 8 9 10
 *
 * Change Logs:
 * Date           Author       Notes
 * 2006-03-17     Bernard      the first version
 * 2006-04-28     Bernard      fix the scheduler algorthm
 * 2006-04-30     Bernard      add SCHEDULER_DEBUG
11 12
 * 2006-05-27     Bernard      fix the scheduler algorthm for same priority
 *                             thread schedule
13 14 15 16 17
 * 2006-06-04     Bernard      rewrite the scheduler algorithm
 * 2006-08-03     Bernard      add hook support
 * 2006-09-05     Bernard      add 32 priority level support
 * 2006-09-24     Bernard      add rt_system_scheduler_start function
 * 2009-09-16     Bernard      fix _rt_scheduler_stack_check
18
 * 2010-04-11     yi.qiu       add module feature
19
 * 2010-07-13     Bernard      fix the maximal number of rt_scheduler_lock_nest
20
 *                             issue found by kuronca
21
 * 2010-12-13     Bernard      add defunct list initialization even if not use heap.
B
bernard.xiong@gmail.com 已提交
22
 * 2011-05-10     Bernard      clean scheduler debug log.
23
 * 2013-12-21     Grissiom     add rt_critical_level
S
shaojinchun 已提交
24 25 26 27 28 29 30
 * 2018-11-22     Jesven       remove the current task from ready queue
 *                             add per cpu ready queue
 *                             add _get_highest_priority_thread to find highest priority task
 *                             rt_schedule_insert_thread won't insert current task to ready queue
 *                             in smp version, rt_hw_context_switch_interrupt maybe switch to
 *                               new task directly
 *
31 32 33 34 35 36
 */

#include <rtthread.h>
#include <rthw.h>

rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];
S
shaojinchun 已提交
37
rt_uint32_t rt_thread_ready_priority_group;
38
#if RT_THREAD_PRIORITY_MAX > 32
39
/* Maximum priority level, 256 */
40
rt_uint8_t rt_thread_ready_table[32];
41
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
42

S
shaojinchun 已提交
43 44 45
#ifndef RT_USING_SMP
extern volatile rt_uint8_t rt_interrupt_nest;
static rt_int16_t rt_scheduler_lock_nest;
46
struct rt_thread *rt_current_thread = RT_NULL;
S
shaojinchun 已提交
47
rt_uint8_t rt_current_priority;
48
#endif /* RT_USING_SMP */
S
shaojinchun 已提交
49

50
#ifdef RT_USING_HOOK
D
dzzxzz 已提交
51
static void (*rt_scheduler_hook)(struct rt_thread *from, struct rt_thread *to);
52 53 54 55

/**
 * @addtogroup Hook
 */
D
dzzxzz 已提交
56

D
dogandog 已提交
57
/**@{*/
58 59 60 61 62 63 64

/**
 * This function will set a hook function, which will be invoked when thread
 * switch happens.
 *
 * @param hook the hook function
 */
65 66
void
rt_scheduler_sethook(void (*hook)(struct rt_thread *from, struct rt_thread *to))
67
{
68
    rt_scheduler_hook = hook;
69 70
}

D
dogandog 已提交
71
/**@}*/
72
#endif /* RT_USING_HOOK */
73 74

#ifdef RT_USING_OVERFLOW_CHECK
D
dzzxzz 已提交
75
static void _rt_scheduler_stack_check(struct rt_thread *thread)
76
{
77 78
    RT_ASSERT(thread != RT_NULL);

79
#ifdef ARCH_CPU_STACK_GROWS_UPWARD
80
    if (*((rt_uint8_t *)((rt_ubase_t)thread->stack_addr + thread->stack_size - 1)) != '#' ||
Z
zhaohengbo 已提交
81
#else
A
Aubr.Cool 已提交
82
    if (*((rt_uint8_t *)thread->stack_addr) != '#' ||
83
#endif /* ARCH_CPU_STACK_GROWS_UPWARD */
B
Bernard Xiong 已提交
84 85 86
        (rt_ubase_t)thread->sp <= (rt_ubase_t)thread->stack_addr ||
        (rt_ubase_t)thread->sp >
        (rt_ubase_t)thread->stack_addr + (rt_ubase_t)thread->stack_size)
87
    {
B
Bernard Xiong 已提交
88
        rt_ubase_t level;
89 90

        rt_kprintf("thread:%s stack overflow\n", thread->name);
91

92 93 94
        level = rt_hw_interrupt_disable();
        while (level);
    }
95
#ifdef ARCH_CPU_STACK_GROWS_UPWARD
96 97 98 99 100 101
    else if ((rt_ubase_t)thread->sp > ((rt_ubase_t)thread->stack_addr + thread->stack_size))
    {
        rt_kprintf("warning: %s stack is close to the top of stack address.\n",
                   thread->name);
    }
#else
S
shaojinchun 已提交
102
    else if ((rt_ubase_t)thread->sp <= ((rt_ubase_t)thread->stack_addr + 32))
103
    {
S
shaojinchun 已提交
104
        rt_kprintf("warning: %s stack is close to end of stack address.\n",
105 106
                   thread->name);
    }
107
#endif /* ARCH_CPU_STACK_GROWS_UPWARD */
S
shaojinchun 已提交
108
}
109
#endif /* RT_USING_OVERFLOW_CHECK */
S
shaojinchun 已提交
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126

/*
 * get the highest priority thread in ready queue
 */
#ifdef RT_USING_SMP
static struct rt_thread* _get_highest_priority_thread(rt_ubase_t *highest_prio)
{
    register struct rt_thread *highest_priority_thread;
    register rt_ubase_t highest_ready_priority, local_highest_ready_priority;
    struct rt_cpu* pcpu = rt_cpu_self();
#if RT_THREAD_PRIORITY_MAX > 32
    register rt_ubase_t number;

    number = __rt_ffs(rt_thread_ready_priority_group) - 1;
    highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1;
    number = __rt_ffs(pcpu->priority_group) - 1;
    local_highest_ready_priority = (number << 3) + __rt_ffs(pcpu->ready_table[number]) - 1;
127
#else
S
shaojinchun 已提交
128 129
    highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;
    local_highest_ready_priority = __rt_ffs(pcpu->priority_group) - 1;
130
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
S
shaojinchun 已提交
131 132 133

    /* get highest ready priority thread */
    if (highest_ready_priority < local_highest_ready_priority)
134
    {
S
shaojinchun 已提交
135 136 137 138 139 140 141 142 143 144 145
        *highest_prio = highest_ready_priority;
        highest_priority_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
                                  struct rt_thread,
                                  tlist);
    }
    else
    {
        *highest_prio = local_highest_ready_priority;
        highest_priority_thread = rt_list_entry(pcpu->priority_table[local_highest_ready_priority].next,
                                  struct rt_thread,
                                  tlist);
146
    }
S
shaojinchun 已提交
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162

    return highest_priority_thread;
}
#else
static struct rt_thread* _get_highest_priority_thread(rt_ubase_t *highest_prio)
{
    register struct rt_thread *highest_priority_thread;
    register rt_ubase_t highest_ready_priority;

#if RT_THREAD_PRIORITY_MAX > 32
    register rt_ubase_t number;

    number = __rt_ffs(rt_thread_ready_priority_group) - 1;
    highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1;
#else
    highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;
163
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
S
shaojinchun 已提交
164 165 166 167 168 169 170 171 172

    /* get highest ready priority thread */
    highest_priority_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
                              struct rt_thread,
                              tlist);

    *highest_prio = highest_ready_priority;

    return highest_priority_thread;
173
}
174
#endif /* RT_USING_SMP */
175 176 177

/**
 * @ingroup SystemInit
B
bernard.xiong@gmail.com 已提交
178
 * This function will initialize the system scheduler
179 180 181
 */
void rt_system_scheduler_init(void)
{
S
shaojinchun 已提交
182 183
#ifdef RT_USING_SMP
    int cpu;
184
#endif /* RT_USING_SMP */
185
    register rt_base_t offset;
186

S
shaojinchun 已提交
187
#ifndef RT_USING_SMP
188
    rt_scheduler_lock_nest = 0;
189
#endif /* RT_USING_SMP */
190

191
    RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("start scheduler: max priority 0x%02x\n",
192
                                      RT_THREAD_PRIORITY_MAX));
B
bernard.xiong@gmail.com 已提交
193

194 195 196 197
    for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset ++)
    {
        rt_list_init(&rt_thread_priority_table[offset]);
    }
S
shaojinchun 已提交
198 199 200 201 202 203 204 205
#ifdef RT_USING_SMP
    for (cpu = 0; cpu < RT_CPUS_NR; cpu++)
    {
        struct rt_cpu *pcpu =  rt_cpu_index(cpu);
        for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset ++)
        {
            rt_list_init(&pcpu->priority_table[offset]);
        }
206

S
shaojinchun 已提交
207 208 209 210 211 212 213
        pcpu->irq_switch_flag = 0;
        pcpu->current_priority = RT_THREAD_PRIORITY_MAX - 1;
        pcpu->current_thread = RT_NULL;
        pcpu->priority_group = 0;

#if RT_THREAD_PRIORITY_MAX > 32
        rt_memset(pcpu->ready_table, 0, sizeof(pcpu->ready_table));
214
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
S
shaojinchun 已提交
215
    }
216
#endif /* RT_USING_SMP */
217

218 219
    /* initialize ready priority group */
    rt_thread_ready_priority_group = 0;
220 221

#if RT_THREAD_PRIORITY_MAX > 32
222 223
    /* initialize ready table */
    rt_memset(rt_thread_ready_table, 0, sizeof(rt_thread_ready_table));
224
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
225 226 227
}

/**
228
 * @ingroup SystemInit
229 230 231
 * This function will startup scheduler. It will select one thread
 * with the highest priority level, then switch to it.
 */
D
dzzxzz 已提交
232
void rt_system_scheduler_start(void)
233
{
234
    register struct rt_thread *to_thread;
S
shaojinchun 已提交
235
    rt_ubase_t highest_ready_priority;
236

S
shaojinchun 已提交
237
    to_thread = _get_highest_priority_thread(&highest_ready_priority);
238

S
shaojinchun 已提交
239 240
#ifdef RT_USING_SMP
    to_thread->oncpu = rt_hw_cpu_id();
241
#else
242
    rt_current_thread = to_thread;
243
#endif /* RT_USING_SMP */
S
shaojinchun 已提交
244 245

    rt_schedule_remove_thread(to_thread);
246
    to_thread->stat = RT_THREAD_RUNNING;
247

248
    /* switch to new thread */
S
shaojinchun 已提交
249
#ifdef RT_USING_SMP
250
    rt_hw_context_switch_to((rt_ubase_t)&to_thread->sp, to_thread);
S
shaojinchun 已提交
251
#else
252
    rt_hw_context_switch_to((rt_ubase_t)&to_thread->sp);
253
#endif /* RT_USING_SMP */
254

255
    /* never come back */
256 257 258 259 260
}

/**
 * @addtogroup Thread
 */
D
dzzxzz 已提交
261

D
dogandog 已提交
262
/**@{*/
263

S
shaojinchun 已提交
264 265 266 267

#ifdef RT_USING_SMP
/**
 * This function will handle IPI interrupt and do a scheduling in system;
mysterywolf's avatar
mysterywolf 已提交
268
 *
S
shaojinchun 已提交
269 270
 * @param vector, the number of IPI interrupt for system scheduling
 * @param param, use RT_NULL
mysterywolf's avatar
mysterywolf 已提交
271
 *
S
shaojinchun 已提交
272 273 274 275 276 277 278 279 280
 * NOTE: this function should be invoke or register as ISR in BSP.
 */
void rt_scheduler_ipi_handler(int vector, void *param)
{
    rt_schedule();
}

/**
 * This function will perform one scheduling. It will select one thread
mysterywolf's avatar
mysterywolf 已提交
281
 * with the highest priority level in global ready queue or local ready queue,
S
shaojinchun 已提交
282 283 284 285 286 287 288 289 290 291 292
 * then switch to it.
 */
void rt_schedule(void)
{
    rt_base_t level;
    struct rt_thread *to_thread;
    struct rt_thread *current_thread;
    struct rt_cpu    *pcpu;
    int cpu_id;

    /* disable interrupt */
293
    level  = rt_hw_interrupt_disable();
S
shaojinchun 已提交
294 295 296 297 298 299 300 301 302

    cpu_id = rt_hw_cpu_id();
    pcpu   = rt_cpu_index(cpu_id);
    current_thread = pcpu->current_thread;

    /* whether do switch in interrupt */
    if (pcpu->irq_nest)
    {
        pcpu->irq_switch_flag = 1;
S
shaojinchun 已提交
303 304 305 306 307 308 309 310 311 312 313 314 315
        rt_hw_interrupt_enable(level);
        goto __exit;
    }

#ifdef RT_USING_SIGNALS
    if ((current_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND)
    {
        /* if current_thread signal is in pending */

        if ((current_thread->stat & RT_THREAD_STAT_SIGNAL_MASK) & RT_THREAD_STAT_SIGNAL_PENDING)
        {
            rt_thread_resume(current_thread);
        }
S
shaojinchun 已提交
316
    }
317
#endif /* RT_USING_SIGNALS */
S
shaojinchun 已提交
318 319

    if (current_thread->scheduler_lock_nest == 1) /* whether lock scheduler */
S
shaojinchun 已提交
320 321 322 323 324 325 326
    {
        rt_ubase_t highest_ready_priority;

        if (rt_thread_ready_priority_group != 0 || pcpu->priority_group != 0)
        {
            to_thread = _get_highest_priority_thread(&highest_ready_priority);
            current_thread->oncpu = RT_CPU_DETACHED;
327
            if ((current_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_RUNNING)
S
shaojinchun 已提交
328 329 330 331 332
            {
                if (current_thread->current_priority < highest_ready_priority)
                {
                    to_thread = current_thread;
                }
333
                else if (current_thread->current_priority == highest_ready_priority && (current_thread->stat & RT_THREAD_STAT_YIELD_MASK) == 0)
334 335 336
                {
                    to_thread = current_thread;
                }
S
shaojinchun 已提交
337 338 339 340
                else
                {
                    rt_schedule_insert_thread(current_thread);
                }
341
                current_thread->stat &= ~RT_THREAD_STAT_YIELD_MASK;
S
shaojinchun 已提交
342 343 344 345 346 347 348 349 350 351
            }
            to_thread->oncpu = cpu_id;
            if (to_thread != current_thread)
            {
                /* if the destination thread is not the same as current thread */
                pcpu->current_priority = (rt_uint8_t)highest_ready_priority;

                RT_OBJECT_HOOK_CALL(rt_scheduler_hook, (current_thread, to_thread));

                rt_schedule_remove_thread(to_thread);
352
                to_thread->stat = RT_THREAD_RUNNING | (to_thread->stat & ~RT_THREAD_STAT_MASK);
S
shaojinchun 已提交
353 354 355 356 357 358 359 360 361 362 363 364

                /* switch to new thread */
                RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,
                        ("[%d]switch to priority#%d "
                         "thread:%.*s(sp:0x%08x), "
                         "from thread:%.*s(sp: 0x%08x)\n",
                         pcpu->irq_nest, highest_ready_priority,
                         RT_NAME_MAX, to_thread->name, to_thread->sp,
                         RT_NAME_MAX, current_thread->name, current_thread->sp));

#ifdef RT_USING_OVERFLOW_CHECK
                _rt_scheduler_stack_check(to_thread);
365
#endif /* RT_USING_OVERFLOW_CHECK */
S
shaojinchun 已提交
366

S
shaojinchun 已提交
367 368
                rt_hw_context_switch((rt_ubase_t)&current_thread->sp,
                        (rt_ubase_t)&to_thread->sp, to_thread);
S
shaojinchun 已提交
369 370 371 372
            }
        }
    }

373 374 375
    /* enable interrupt */
    rt_hw_interrupt_enable(level);

S
shaojinchun 已提交
376
#ifdef RT_USING_SIGNALS
377 378
    /* check stat of thread for signal */
    level = rt_hw_interrupt_disable();
S
shaojinchun 已提交
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
    if (current_thread->stat & RT_THREAD_STAT_SIGNAL_PENDING)
    {
        extern void rt_thread_handle_sig(rt_bool_t clean_state);

        current_thread->stat &= ~RT_THREAD_STAT_SIGNAL_PENDING;

        rt_hw_interrupt_enable(level);

        /* check signal status */
        rt_thread_handle_sig(RT_TRUE);
    }
    else
    {
        rt_hw_interrupt_enable(level);
    }
394
#endif /* RT_USING_SIGNALS */
S
shaojinchun 已提交
395 396 397 398 399

__exit:
    return ;
}
#else
400 401
/**
 * This function will perform one schedule. It will select one thread
402
 * with the highest priority level, and switch to it immediately.
403
 */
D
dzzxzz 已提交
404
void rt_schedule(void)
405
{
406 407 408
    rt_base_t level;
    struct rt_thread *to_thread;
    struct rt_thread *from_thread;
409

410 411
    /* disable interrupt */
    level = rt_hw_interrupt_disable();
412

413 414 415
    /* check the scheduler is enabled or not */
    if (rt_scheduler_lock_nest == 0)
    {
S
shaojinchun 已提交
416
        rt_ubase_t highest_ready_priority;
417

S
shaojinchun 已提交
418 419
        if (rt_thread_ready_priority_group != 0)
        {
420
            /* need_insert_from_thread: need to insert from_thread to ready queue */
S
shaojinchun 已提交
421
            int need_insert_from_thread = 0;
422

S
shaojinchun 已提交
423
            to_thread = _get_highest_priority_thread(&highest_ready_priority);
424

425
            if ((rt_current_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_RUNNING)
S
shaojinchun 已提交
426 427 428 429 430
            {
                if (rt_current_thread->current_priority < highest_ready_priority)
                {
                    to_thread = rt_current_thread;
                }
431
                else if (rt_current_thread->current_priority == highest_ready_priority && (rt_current_thread->stat & RT_THREAD_STAT_YIELD_MASK) == 0)
432
                {
433
                    to_thread = rt_current_thread;
434
                }
S
shaojinchun 已提交
435 436 437 438
                else
                {
                    need_insert_from_thread = 1;
                }
439
                rt_current_thread->stat &= ~RT_THREAD_STAT_YIELD_MASK;
S
shaojinchun 已提交
440
            }
441

S
shaojinchun 已提交
442 443 444 445 446 447 448 449
            if (to_thread != rt_current_thread)
            {
                /* if the destination thread is not the same as current thread */
                rt_current_priority = (rt_uint8_t)highest_ready_priority;
                from_thread         = rt_current_thread;
                rt_current_thread   = to_thread;

                RT_OBJECT_HOOK_CALL(rt_scheduler_hook, (from_thread, to_thread));
450

S
shaojinchun 已提交
451 452 453 454
                if (need_insert_from_thread)
                {
                    rt_schedule_insert_thread(from_thread);
                }
455

S
shaojinchun 已提交
456
                rt_schedule_remove_thread(to_thread);
457
                to_thread->stat = RT_THREAD_RUNNING | (to_thread->stat & ~RT_THREAD_STAT_MASK);
S
shaojinchun 已提交
458 459 460 461

                /* switch to new thread */
                RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,
                        ("[%d]switch to priority#%d "
B
Bernard Xiong 已提交
462 463
                         "thread:%.*s(sp:0x%08x), "
                         "from thread:%.*s(sp: 0x%08x)\n",
S
shaojinchun 已提交
464 465 466
                         rt_interrupt_nest, highest_ready_priority,
                         RT_NAME_MAX, to_thread->name, to_thread->sp,
                         RT_NAME_MAX, from_thread->name, from_thread->sp));
467

468
#ifdef RT_USING_OVERFLOW_CHECK
S
shaojinchun 已提交
469
                _rt_scheduler_stack_check(to_thread);
470
#endif /* RT_USING_OVERFLOW_CHECK */
471

S
shaojinchun 已提交
472 473 474
                if (rt_interrupt_nest == 0)
                {
                    extern void rt_thread_handle_sig(rt_bool_t clean_state);
B
bernard 已提交
475

S
shaojinchun 已提交
476 477
                    rt_hw_context_switch((rt_ubase_t)&from_thread->sp,
                            (rt_ubase_t)&to_thread->sp);
478 479 480 481

                    /* enable interrupt */
                    rt_hw_interrupt_enable(level);

S
shaojinchun 已提交
482
#ifdef RT_USING_SIGNALS
483 484
                    /* check stat of thread for signal */
                    level = rt_hw_interrupt_disable();
S
shaojinchun 已提交
485 486 487 488 489
                    if (rt_current_thread->stat & RT_THREAD_STAT_SIGNAL_PENDING)
                    {
                        extern void rt_thread_handle_sig(rt_bool_t clean_state);

                        rt_current_thread->stat &= ~RT_THREAD_STAT_SIGNAL_PENDING;
B
bernard 已提交
490

S
shaojinchun 已提交
491 492 493 494 495 496 497 498 499
                        rt_hw_interrupt_enable(level);

                        /* check signal status */
                        rt_thread_handle_sig(RT_TRUE);
                    }
                    else
                    {
                        rt_hw_interrupt_enable(level);
                    }
500
#endif /* RT_USING_SIGNALS */
S
shaojinchun 已提交
501 502 503 504 505 506 507 508 509
                    goto __exit;
                }
                else
                {
                    RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("switch in interrupt\n"));

                    rt_hw_context_switch_interrupt((rt_ubase_t)&from_thread->sp,
                            (rt_ubase_t)&to_thread->sp);
                }
510 511 512
            }
            else
            {
S
shaojinchun 已提交
513
                rt_schedule_remove_thread(rt_current_thread);
514
                rt_current_thread->stat = RT_THREAD_RUNNING | (rt_current_thread->stat & ~RT_THREAD_STAT_MASK);
515 516 517
            }
        }
    }
S
shaojinchun 已提交
518 519 520 521 522 523 524

    /* enable interrupt */
    rt_hw_interrupt_enable(level);

__exit:
    return;
}
525
#endif /* RT_USING_SMP */
S
shaojinchun 已提交
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546

/**
 * This function checks if a scheduling is needed after IRQ context. If yes,
 * it will select one thread with the highest priority level, and then switch
 * to it.
 */
#ifdef RT_USING_SMP
void rt_scheduler_do_irq_switch(void *context)
{
    int cpu_id;
    rt_base_t level;
    struct rt_cpu* pcpu;
    struct rt_thread *to_thread;
    struct rt_thread *current_thread;

    level = rt_hw_interrupt_disable();

    cpu_id = rt_hw_cpu_id();
    pcpu   = rt_cpu_index(cpu_id);
    current_thread = pcpu->current_thread;

S
shaojinchun 已提交
547 548 549 550 551 552 553 554 555 556
#ifdef RT_USING_SIGNALS
    if ((current_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND)
    {
        /* if current_thread signal is in pending */

        if ((current_thread->stat & RT_THREAD_STAT_SIGNAL_MASK) & RT_THREAD_STAT_SIGNAL_PENDING)
        {
            rt_thread_resume(current_thread);
        }
    }
557
#endif /* RT_USING_SIGNALS */
S
shaojinchun 已提交
558

S
shaojinchun 已提交
559
    if (pcpu->irq_switch_flag == 0)
armink_ztl's avatar
armink_ztl 已提交
560 561
    {
        rt_hw_interrupt_enable(level);
S
shaojinchun 已提交
562 563 564 565 566 567 568 569 570 571 572 573 574 575
        return;
    }

    if (current_thread->scheduler_lock_nest == 1 && pcpu->irq_nest == 0)
    {
        rt_ubase_t highest_ready_priority;

        /* clear irq switch flag */
        pcpu->irq_switch_flag = 0;

        if (rt_thread_ready_priority_group != 0 || pcpu->priority_group != 0)
        {
            to_thread = _get_highest_priority_thread(&highest_ready_priority);
            current_thread->oncpu = RT_CPU_DETACHED;
576
            if ((current_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_RUNNING)
S
shaojinchun 已提交
577 578 579 580 581
            {
                if (current_thread->current_priority < highest_ready_priority)
                {
                    to_thread = current_thread;
                }
582
                else if (current_thread->current_priority == highest_ready_priority && (current_thread->stat & RT_THREAD_STAT_YIELD_MASK) == 0)
583 584 585
                {
                    to_thread = current_thread;
                }
S
shaojinchun 已提交
586 587 588 589
                else
                {
                    rt_schedule_insert_thread(current_thread);
                }
590
                current_thread->stat &= ~RT_THREAD_STAT_YIELD_MASK;
S
shaojinchun 已提交
591 592 593 594 595 596 597 598 599 600 601
            }
            to_thread->oncpu = cpu_id;
            if (to_thread != current_thread)
            {
                /* if the destination thread is not the same as current thread */

                pcpu->current_priority = (rt_uint8_t)highest_ready_priority;

                RT_OBJECT_HOOK_CALL(rt_scheduler_hook, (current_thread, to_thread));

                rt_schedule_remove_thread(to_thread);
602
                to_thread->stat = RT_THREAD_RUNNING | (to_thread->stat & ~RT_THREAD_STAT_MASK);
S
shaojinchun 已提交
603 604 605

#ifdef RT_USING_OVERFLOW_CHECK
                _rt_scheduler_stack_check(to_thread);
606
#endif /* RT_USING_OVERFLOW_CHECK */
S
shaojinchun 已提交
607 608 609 610 611 612 613 614 615
                RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("switch in interrupt\n"));

                current_thread->cpus_lock_nest--;
                current_thread->scheduler_lock_nest--;

                rt_hw_context_switch_interrupt(context, (rt_ubase_t)&current_thread->sp,
                        (rt_ubase_t)&to_thread->sp, to_thread);
            }
        }
armink_ztl's avatar
armink_ztl 已提交
616
    }
S
shaojinchun 已提交
617
    rt_hw_interrupt_enable(level);
618
}
619
#endif /* RT_USING_SMP */
620

B
bernard.xiong@gmail.com 已提交
621
/*
622 623 624 625 626 627
 * This function will insert a thread to system ready queue. The state of
 * thread will be set as READY and remove from suspend queue.
 *
 * @param thread the thread to be inserted
 * @note Please do not invoke this function in user application.
 */
S
shaojinchun 已提交
628 629 630 631 632 633 634 635 636 637 638 639 640
#ifdef RT_USING_SMP
void rt_schedule_insert_thread(struct rt_thread *thread)
{
    int cpu_id;
    int bind_cpu;
    rt_uint32_t cpu_mask;
    register rt_base_t level;

    RT_ASSERT(thread != RT_NULL);

    /* disable interrupt */
    level = rt_hw_interrupt_disable();

641
    /* it should be RUNNING thread */
S
shaojinchun 已提交
642 643
    if (thread->oncpu != RT_CPU_DETACHED)
    {
644
        thread->stat = RT_THREAD_RUNNING | (thread->stat & ~RT_THREAD_STAT_MASK);
S
shaojinchun 已提交
645 646 647
        goto __exit;
    }

648 649 650
    /* READY thread, insert to ready queue */
    thread->stat = RT_THREAD_READY | (thread->stat & ~RT_THREAD_STAT_MASK);

S
shaojinchun 已提交
651 652 653 654 655 656 657 658
    cpu_id   = rt_hw_cpu_id();
    bind_cpu = thread->bind_cpu ;

    /* insert thread to ready list */
    if (bind_cpu == RT_CPUS_NR)
    {
#if RT_THREAD_PRIORITY_MAX > 32
        rt_thread_ready_table[thread->number] |= thread->high_mask;
659
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
S
shaojinchun 已提交
660 661 662 663 664
        rt_thread_ready_priority_group |= thread->number_mask;

        rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
                              &(thread->tlist));
        cpu_mask = RT_CPU_MASK ^ (1 << cpu_id);
S
shaojinchun 已提交
665
        rt_hw_ipi_send(RT_SCHEDULE_IPI, cpu_mask);
S
shaojinchun 已提交
666 667 668 669 670 671 672
    }
    else
    {
        struct rt_cpu *pcpu = rt_cpu_index(bind_cpu);

#if RT_THREAD_PRIORITY_MAX > 32
        pcpu->ready_table[thread->number] |= thread->high_mask;
673
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
S
shaojinchun 已提交
674 675 676 677 678 679 680 681
        pcpu->priority_group |= thread->number_mask;

        rt_list_insert_before(&(rt_cpu_index(bind_cpu)->priority_table[thread->current_priority]),
                              &(thread->tlist));

        if (cpu_id != bind_cpu)
        {
            cpu_mask = 1 << bind_cpu;
S
shaojinchun 已提交
682
            rt_hw_ipi_send(RT_SCHEDULE_IPI, cpu_mask);
S
shaojinchun 已提交
683 684 685 686 687 688 689 690 691 692 693
        }
    }

    RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("insert thread[%.*s], the priority: %d\n",
                                      RT_NAME_MAX, thread->name, thread->current_priority));

__exit:
    /* enable interrupt */
    rt_hw_interrupt_enable(level);
}
#else
D
dzzxzz 已提交
694
void rt_schedule_insert_thread(struct rt_thread *thread)
695
{
696
    register rt_base_t temp;
697

698
    RT_ASSERT(thread != RT_NULL);
699

700 701
    /* disable interrupt */
    temp = rt_hw_interrupt_disable();
702

703
    /* it's current thread, it should be RUNNING thread */
S
shaojinchun 已提交
704 705
    if (thread == rt_current_thread)
    {
706
        thread->stat = RT_THREAD_RUNNING | (thread->stat & ~RT_THREAD_STAT_MASK);
S
shaojinchun 已提交
707 708 709
        goto __exit;
    }

710 711
    /* READY thread, insert to ready queue */
    thread->stat = RT_THREAD_READY | (thread->stat & ~RT_THREAD_STAT_MASK);
712 713 714
    /* insert thread to ready list */
    rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
                          &(thread->tlist));
715

G
Grissiom 已提交
716 717
    RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("insert thread[%.*s], the priority: %d\n",
                                      RT_NAME_MAX, thread->name, thread->current_priority));
718

S
shaojinchun 已提交
719
    /* set priority mask */
720
#if RT_THREAD_PRIORITY_MAX > 32
721
    rt_thread_ready_table[thread->number] |= thread->high_mask;
722
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
723
    rt_thread_ready_priority_group |= thread->number_mask;
724

S
shaojinchun 已提交
725
__exit:
726 727
    /* enable interrupt */
    rt_hw_interrupt_enable(temp);
728
}
729
#endif /* RT_USING_SMP */
730

B
bernard.xiong@gmail.com 已提交
731
/*
732 733 734 735 736 737
 * This function will remove a thread from system ready queue.
 *
 * @param thread the thread to be removed
 *
 * @note Please do not invoke this function in user application.
 */
S
shaojinchun 已提交
738
#ifdef RT_USING_SMP
D
dzzxzz 已提交
739
void rt_schedule_remove_thread(struct rt_thread *thread)
740
{
S
shaojinchun 已提交
741
    register rt_base_t level;
742

743
    RT_ASSERT(thread != RT_NULL);
744

745
    /* disable interrupt */
S
shaojinchun 已提交
746
    level = rt_hw_interrupt_disable();
747

G
Grissiom 已提交
748 749 750
    RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("remove thread[%.*s], the priority: %d\n",
                                      RT_NAME_MAX, thread->name,
                                      thread->current_priority));
S
shaojinchun 已提交
751 752 753 754 755 756 757 758 759 760 761 762 763 764 765

    /* remove thread from ready list */
    rt_list_remove(&(thread->tlist));
    if (thread->bind_cpu == RT_CPUS_NR)
    {
        if (rt_list_isempty(&(rt_thread_priority_table[thread->current_priority])))
        {
#if RT_THREAD_PRIORITY_MAX > 32
            rt_thread_ready_table[thread->number] &= ~thread->high_mask;
            if (rt_thread_ready_table[thread->number] == 0)
            {
                rt_thread_ready_priority_group &= ~thread->number_mask;
            }
#else
            rt_thread_ready_priority_group &= ~thread->number_mask;
766
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
S
shaojinchun 已提交
767 768 769 770 771 772 773 774 775 776
        }
    }
    else
    {
        struct rt_cpu *pcpu = rt_cpu_index(thread->bind_cpu);

        if (rt_list_isempty(&(pcpu->priority_table[thread->current_priority])))
        {
#if RT_THREAD_PRIORITY_MAX > 32
            pcpu->ready_table[thread->number] &= ~thread->high_mask;
777
            if (pcpu->ready_table[thread->number] == 0)
S
shaojinchun 已提交
778 779 780
            {
                pcpu->priority_group &= ~thread->number_mask;
            }
781
#else
S
shaojinchun 已提交
782
            pcpu->priority_group &= ~thread->number_mask;
783
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
S
shaojinchun 已提交
784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
        }
    }

    /* enable interrupt */
    rt_hw_interrupt_enable(level);
}
#else
void rt_schedule_remove_thread(struct rt_thread *thread)
{
    register rt_base_t level;

    RT_ASSERT(thread != RT_NULL);

    /* disable interrupt */
    level = rt_hw_interrupt_disable();

    RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("remove thread[%.*s], the priority: %d\n",
                                      RT_NAME_MAX, thread->name,
                                      thread->current_priority));
803

804 805 806 807
    /* remove thread from ready list */
    rt_list_remove(&(thread->tlist));
    if (rt_list_isempty(&(rt_thread_priority_table[thread->current_priority])))
    {
808
#if RT_THREAD_PRIORITY_MAX > 32
809 810 811 812 813
        rt_thread_ready_table[thread->number] &= ~thread->high_mask;
        if (rt_thread_ready_table[thread->number] == 0)
        {
            rt_thread_ready_priority_group &= ~thread->number_mask;
        }
814
#else
815
        rt_thread_ready_priority_group &= ~thread->number_mask;
816
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
817
    }
818

819
    /* enable interrupt */
S
shaojinchun 已提交
820
    rt_hw_interrupt_enable(level);
821
}
822
#endif /* RT_USING_SMP */
823 824 825 826

/**
 * This function will lock the thread scheduler.
 */
S
shaojinchun 已提交
827 828 829 830 831 832 833 834 835 836
#ifdef RT_USING_SMP
void rt_enter_critical(void)
{
    register rt_base_t level;
    struct rt_thread *current_thread;

    /* disable interrupt */
    level = rt_hw_local_irq_disable();

    current_thread = rt_cpu_self()->current_thread;
837 838 839
    if (!current_thread)
    {
        rt_hw_local_irq_enable(level);
840
        return;
841 842
    }

S
shaojinchun 已提交
843 844 845 846 847 848
    /*
     * the maximal number of nest is RT_UINT16_MAX, which is big
     * enough and does not check here
     */

    {
849 850 851 852 853 854 855
        register rt_uint16_t lock_nest = current_thread->cpus_lock_nest;
        current_thread->cpus_lock_nest++;
        if (lock_nest == 0)
        {
            current_thread->scheduler_lock_nest ++;
            rt_hw_spin_lock(&_cpus_lock);
        }
S
shaojinchun 已提交
856
    }
S
shaojinchun 已提交
857 858 859
    /* critical for local cpu */
    current_thread->critical_lock_nest ++;

S
shaojinchun 已提交
860 861 862 863 864 865 866
    /* lock scheduler for local cpu */
    current_thread->scheduler_lock_nest ++;

    /* enable interrupt */
    rt_hw_local_irq_enable(level);
}
#else
D
dzzxzz 已提交
867
void rt_enter_critical(void)
868
{
869
    register rt_base_t level;
870

871 872
    /* disable interrupt */
    level = rt_hw_interrupt_disable();
873

874 875 876 877 878
    /*
     * the maximal number of nest is RT_UINT16_MAX, which is big
     * enough and does not check here
     */
    rt_scheduler_lock_nest ++;
879

880 881
    /* enable interrupt */
    rt_hw_interrupt_enable(level);
882
}
883
#endif /* RT_USING_SMP */
B
Bernard Xiong 已提交
884
RTM_EXPORT(rt_enter_critical);
885 886 887 888

/**
 * This function will unlock the thread scheduler.
 */
S
shaojinchun 已提交
889 890 891 892 893 894 895 896 897 898
#ifdef RT_USING_SMP
void rt_exit_critical(void)
{
    register rt_base_t level;
    struct rt_thread *current_thread;

    /* disable interrupt */
    level = rt_hw_local_irq_disable();

    current_thread = rt_cpu_self()->current_thread;
899 900 901
    if (!current_thread)
    {
        rt_hw_local_irq_enable(level);
902
        return;
903
    }
S
shaojinchun 已提交
904 905 906

    current_thread->scheduler_lock_nest --;

S
shaojinchun 已提交
907 908
    current_thread->critical_lock_nest --;

909 910
    current_thread->cpus_lock_nest--;
    if (current_thread->cpus_lock_nest == 0)
S
shaojinchun 已提交
911
    {
912 913
        current_thread->scheduler_lock_nest --;
        rt_hw_spin_unlock(&_cpus_lock);
S
shaojinchun 已提交
914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930
    }

    if (current_thread->scheduler_lock_nest <= 0)
    {
        current_thread->scheduler_lock_nest = 0;
        /* enable interrupt */
        rt_hw_local_irq_enable(level);

        rt_schedule();
    }
    else
    {
        /* enable interrupt */
        rt_hw_local_irq_enable(level);
    }
}
#else
D
dzzxzz 已提交
931
void rt_exit_critical(void)
932
{
933 934 935 936 937 938 939 940 941 942 943 944
    register rt_base_t level;

    /* disable interrupt */
    level = rt_hw_interrupt_disable();

    rt_scheduler_lock_nest --;
    if (rt_scheduler_lock_nest <= 0)
    {
        rt_scheduler_lock_nest = 0;
        /* enable interrupt */
        rt_hw_interrupt_enable(level);

945 946 947 948 949
        if (rt_current_thread)
        {
            /* if scheduler is started, do a schedule */
            rt_schedule();
        }
950 951 952 953 954 955
    }
    else
    {
        /* enable interrupt */
        rt_hw_interrupt_enable(level);
    }
956
}
957
#endif /* RT_USING_SMP */
B
Bernard Xiong 已提交
958
RTM_EXPORT(rt_exit_critical);
959

960 961 962 963 964 965 966
/**
 * Get the scheduler lock level
 *
 * @return the level of the scheduler lock. 0 means unlocked.
 */
rt_uint16_t rt_critical_level(void)
{
S
shaojinchun 已提交
967 968 969
#ifdef RT_USING_SMP
    struct rt_thread *current_thread = rt_cpu_self()->current_thread;

S
shaojinchun 已提交
970
    return current_thread->critical_lock_nest;
S
shaojinchun 已提交
971
#else
972
    return rt_scheduler_lock_nest;
973
#endif /* RT_USING_SMP */
974
}
B
Bernard Xiong 已提交
975
RTM_EXPORT(rt_critical_level);
976

S
shaojinchun 已提交
977
/**@}*/