thread.c 24.5 KB
Newer Older
1
/*
2
 * Copyright (c) 2006-2018, RT-Thread Development Team
B
Bernard Xiong 已提交
3
 *
4
 * SPDX-License-Identifier: Apache-2.0
5 6 7 8 9
 *
 * Change Logs:
 * Date           Author       Notes
 * 2006-03-28     Bernard      first version
 * 2006-04-29     Bernard      implement thread timer
10 11 12 13 14
 * 2006-04-30     Bernard      added THREAD_DEBUG
 * 2006-05-27     Bernard      fixed the rt_thread_yield bug
 * 2006-06-03     Bernard      fixed the thread timer init bug
 * 2006-08-10     Bernard      fixed the timer bug in thread_sleep
 * 2006-09-03     Bernard      changed rt_timer_delete to rt_timer_detach
15
 * 2006-09-03     Bernard      implement rt_thread_detach
16
 * 2008-02-16     Bernard      fixed the rt_thread_timeout bug
17 18
 * 2010-03-21     Bernard      change the errno of rt_thread_delay/sleep to
 *                             RT_EOK.
19
 * 2010-11-10     Bernard      add cleanup callback function in thread exit.
20 21
 * 2011-09-01     Bernard      fixed rt_thread_exit issue when the current
 *                             thread preempted, which reported by Jiaxing Lee.
22
 * 2011-09-08     Bernard      fixed the scheduling issue in rt_thread_startup.
23
 * 2012-12-29     Bernard      fixed compiling warning.
24
 * 2016-08-09     ArdaFu       add thread suspend and resume hook.
25
 * 2017-04-10     armink       fixed the rt_thread_delete and rt_thread_detach
S
shaojinchun 已提交
26 27 28
 *                             bug when thread has not startup.
 * 2018-11-22     Jesven       yield is same to rt_schedule
 *                             add support for tasks bound to cpu
29
 * 2021-02-24     Meco Man     rearrange rt_thread_control() - schedule the thread when close it
30 31 32
 */

#include <rthw.h>
S
shaojinchun 已提交
33
#include <rtthread.h>
34 35 36

extern rt_list_t rt_thread_defunct;

37 38
#ifdef RT_USING_HOOK
static void (*rt_thread_suspend_hook)(rt_thread_t thread);
B
Bernard Xiong 已提交
39 40 41
static void (*rt_thread_resume_hook) (rt_thread_t thread);
static void (*rt_thread_inited_hook) (rt_thread_t thread);

42 43
/**
 * @ingroup Hook
44
 * This function sets a hook function when the system suspend a thread.
45 46 47 48 49 50 51 52 53
 *
 * @param hook the specified hook function
 *
 * @note the hook function must be simple and never be blocked or suspend.
 */
void rt_thread_suspend_sethook(void (*hook)(rt_thread_t thread))
{
    rt_thread_suspend_hook = hook;
}
B
Bernard Xiong 已提交
54

55 56
/**
 * @ingroup Hook
57
 * This function sets a hook function when the system resume a thread.
58 59 60 61 62 63 64 65 66
 *
 * @param hook the specified hook function
 *
 * @note the hook function must be simple and never be blocked or suspend.
 */
void rt_thread_resume_sethook(void (*hook)(rt_thread_t thread))
{
    rt_thread_resume_hook = hook;
}
B
Bernard Xiong 已提交
67 68 69

/**
 * @ingroup Hook
70
 * This function sets a hook function when a thread is initialized.
B
Bernard Xiong 已提交
71 72 73 74 75
 *
 * @param hook the specified hook function
 */
void rt_thread_inited_sethook(void (*hook)(rt_thread_t thread))
{
76
    rt_thread_inited_hook = hook;
B
Bernard Xiong 已提交
77 78
}

79 80
#endif

81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
/* must be invoke witch rt_hw_interrupt_disable */
static void _thread_cleanup_execute(rt_thread_t thread)
{
    register rt_base_t level;
#ifdef RT_USING_MODULE
    struct rt_dlmodule *module = RT_NULL;
#endif
    level = rt_hw_interrupt_disable();
#ifdef RT_USING_MODULE
    module = (struct rt_dlmodule*)thread->module_id;
    if (module)
    {
        dlmodule_destroy(module);
    }
#endif
    /* invoke thread cleanup */
    if (thread->cleanup != RT_NULL)
        thread->cleanup(thread);

#ifdef RT_USING_SIGNALS
    rt_thread_free_sig(thread);
#endif
    rt_hw_interrupt_enable(level);
}

106
void rt_thread_exit(void)
107
{
108 109 110 111
    struct rt_thread *thread;
    register rt_base_t level;

    /* get current thread */
S
shaojinchun 已提交
112
    thread = rt_thread_self();
113 114 115 116

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

117 118
    _thread_cleanup_execute(thread);

119 120 121 122 123 124
    /* remove from schedule */
    rt_schedule_remove_thread(thread);
    /* change stat */
    thread->stat = RT_THREAD_CLOSE;

    /* remove it from timer list */
125
    rt_timer_detach(&thread->thread_timer);
126

127
    if (rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE)
128 129 130 131 132 133 134 135 136 137 138
    {
        rt_object_detach((rt_object_t)thread);
    }
    else
    {
        /* insert to defunct thread list */
        rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));
    }

    /* switch to next task */
    rt_schedule();
139 140 141

    /* enable interrupt */
    rt_hw_interrupt_enable(level);
142
}
143

D
dzzxzz 已提交
144
static rt_err_t _rt_thread_init(struct rt_thread *thread,
145 146 147 148 149 150 151
                                const char       *name,
                                void (*entry)(void *parameter),
                                void             *parameter,
                                void             *stack_start,
                                rt_uint32_t       stack_size,
                                rt_uint8_t        priority,
                                rt_uint32_t       tick)
152
{
153 154 155 156 157 158 159 160
    /* init thread list */
    rt_list_init(&(thread->tlist));

    thread->entry = (void *)entry;
    thread->parameter = parameter;

    /* stack init */
    thread->stack_addr = stack_start;
W
weety 已提交
161
    thread->stack_size = stack_size;
162 163 164

    /* init thread stack */
    rt_memset(thread->stack_addr, '#', thread->stack_size);
165 166 167 168 169
#ifdef ARCH_CPU_STACK_GROWS_UPWARD
    thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
                                          (void *)((char *)thread->stack_addr),
                                          (void *)rt_thread_exit);
#else
170
    thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
171
                                          (rt_uint8_t *)((char *)thread->stack_addr + thread->stack_size - sizeof(rt_ubase_t)),
172
                                          (void *)rt_thread_exit);
173
#endif
174 175 176 177 178 179

    /* priority init */
    RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX);
    thread->init_priority    = priority;
    thread->current_priority = priority;

180 181 182
    thread->number_mask = 0;
#if RT_THREAD_PRIORITY_MAX > 32
    thread->number = 0;
B
Bernard Xiong 已提交
183
    thread->high_mask = 0;
184 185
#endif

186 187 188 189 190 191 192 193
    /* tick init */
    thread->init_tick      = tick;
    thread->remaining_tick = tick;

    /* error and flags */
    thread->error = RT_EOK;
    thread->stat  = RT_THREAD_INIT;

S
shaojinchun 已提交
194 195 196 197 198 199 200 201
#ifdef RT_USING_SMP
    /* not bind on any cpu */
    thread->bind_cpu = RT_CPUS_NR;
    thread->oncpu = RT_CPU_DETACHED;

    /* lock init */
    thread->scheduler_lock_nest = 0;
    thread->cpus_lock_nest = 0;
S
shaojinchun 已提交
202
    thread->critical_lock_nest = 0;
S
shaojinchun 已提交
203 204
#endif /*RT_USING_SMP*/

205 206 207 208
    /* initialize cleanup function and user data */
    thread->cleanup   = 0;
    thread->user_data = 0;

B
Bernard Xiong 已提交
209
    /* initialize thread timer */
210 211 212 213 214 215 216
    rt_timer_init(&(thread->thread_timer),
                  thread->name,
                  rt_thread_timeout,
                  thread,
                  0,
                  RT_TIMER_FLAG_ONE_SHOT);

B
bernard 已提交
217 218 219 220 221
    /* initialize signal */
#ifdef RT_USING_SIGNALS
    thread->sig_mask    = 0x00;
    thread->sig_pending = 0x00;

S
shaojinchun 已提交
222
#ifndef RT_USING_SMP
B
bernard 已提交
223
    thread->sig_ret     = RT_NULL;
S
shaojinchun 已提交
224
#endif
B
bernard 已提交
225 226 227 228
    thread->sig_vectors = RT_NULL;
    thread->si_list     = RT_NULL;
#endif

H
heyuanjie 已提交
229 230 231 232
#ifdef RT_USING_LWP
    thread->lwp = RT_NULL;
#endif

233
    RT_OBJECT_HOOK_CALL(rt_thread_inited_hook, (thread));
B
Bernard Xiong 已提交
234

235
    return RT_EOK;
236 237 238 239 240 241
}

/**
 * @addtogroup Thread
 */

D
dogandog 已提交
242
/**@{*/
243 244

/**
B
bernard.xiong@gmail.com 已提交
245 246
 * This function will initialize a thread, normally it's used to initialize a
 * static thread object.
247 248 249 250 251 252 253 254 255 256
 *
 * @param thread the static thread object
 * @param name the name of thread, which shall be unique
 * @param entry the entry function of thread
 * @param parameter the parameter of thread enter function
 * @param stack_start the start address of thread stack
 * @param stack_size the size of thread stack
 * @param priority the priority of thread
 * @param tick the time slice if there are same priority thread
 *
B
bernard.xiong@gmail.com 已提交
257
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
258
 */
D
dzzxzz 已提交
259
rt_err_t rt_thread_init(struct rt_thread *thread,
260 261 262 263 264 265 266
                        const char       *name,
                        void (*entry)(void *parameter),
                        void             *parameter,
                        void             *stack_start,
                        rt_uint32_t       stack_size,
                        rt_uint8_t        priority,
                        rt_uint32_t       tick)
267
{
268 269 270 271
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
    RT_ASSERT(stack_start != RT_NULL);

B
Bernard Xiong 已提交
272
    /* initialize thread object */
273 274 275 276 277 278 279 280 281 282
    rt_object_init((rt_object_t)thread, RT_Object_Class_Thread, name);

    return _rt_thread_init(thread,
                           name,
                           entry,
                           parameter,
                           stack_start,
                           stack_size,
                           priority,
                           tick);
283
}
284
RTM_EXPORT(rt_thread_init);
285 286 287 288 289 290

/**
 * This function will return self thread object
 *
 * @return the self thread object
 */
D
dzzxzz 已提交
291
rt_thread_t rt_thread_self(void)
292
{
S
shaojinchun 已提交
293 294 295 296 297 298 299 300 301 302 303
#ifdef RT_USING_SMP
    rt_base_t lock;
    rt_thread_t self;

    lock = rt_hw_local_irq_disable();
    self = rt_cpu_self()->current_thread;
    rt_hw_local_irq_enable(lock);
    return self;
#else
    extern rt_thread_t rt_current_thread;

304
    return rt_current_thread;
S
shaojinchun 已提交
305
#endif
306
}
307
RTM_EXPORT(rt_thread_self);
308 309 310 311 312 313

/**
 * This function will start a thread and put it to system ready queue
 *
 * @param thread the thread to be started
 *
B
bernard.xiong@gmail.com 已提交
314
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
315
 */
D
dzzxzz 已提交
316
rt_err_t rt_thread_startup(rt_thread_t thread)
317
{
318 319
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
B
bernard 已提交
320
    RT_ASSERT((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_INIT);
321
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
322

B
Bernard Xiong 已提交
323
    /* set current priority to initialize priority */
324
    thread->current_priority = thread->init_priority;
325

326
    /* calculate priority attribute */
327
#if RT_THREAD_PRIORITY_MAX > 32
328 329 330
    thread->number      = thread->current_priority >> 3;            /* 5bit */
    thread->number_mask = 1L << thread->number;
    thread->high_mask   = 1L << (thread->current_priority & 0x07);  /* 3bit */
331
#else
332
    thread->number_mask = 1L << thread->current_priority;
333 334
#endif

335
    RT_DEBUG_LOG(RT_DEBUG_THREAD, ("startup a thread:%s with priority:%d\n",
336
                                   thread->name, thread->init_priority));
337 338 339 340 341 342 343 344 345 346 347
    /* change thread stat */
    thread->stat = RT_THREAD_SUSPEND;
    /* then resume it */
    rt_thread_resume(thread);
    if (rt_thread_self() != RT_NULL)
    {
        /* do a scheduling */
        rt_schedule();
    }

    return RT_EOK;
348
}
349
RTM_EXPORT(rt_thread_startup);
350 351

/**
B
bernard.xiong@gmail.com 已提交
352 353
 * This function will detach a thread. The thread object will be removed from
 * thread queue and detached/deleted from system object management.
354 355 356
 *
 * @param thread the thread to be deleted
 *
B
bernard.xiong@gmail.com 已提交
357
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
358
 */
D
dzzxzz 已提交
359
rt_err_t rt_thread_detach(rt_thread_t thread)
360
{
361
    rt_base_t lock;
362

363 364
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
365 366
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
    RT_ASSERT(rt_object_is_systemobject((rt_object_t)thread));
367

C
cliff-cmc 已提交
368
    if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE)
369 370
        return RT_EOK;

B
bernard 已提交
371
    if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT)
372 373 374 375
    {
        /* remove from schedule */
        rt_schedule_remove_thread(thread);
    }
376

377 378
    _thread_cleanup_execute(thread);

379 380
    /* release thread timer */
    rt_timer_detach(&(thread->thread_timer));
381

382 383
    /* change stat */
    thread->stat = RT_THREAD_CLOSE;
384

385 386
    /* detach thread object */
    rt_object_detach((rt_object_t)thread);
387

388
    return RT_EOK;
389
}
390 391
RTM_EXPORT(rt_thread_detach);

392
#ifdef RT_USING_HEAP
393 394 395 396 397 398 399 400 401 402 403 404 405 406
/**
 * This function will create a thread object and allocate thread object memory
 * and stack.
 *
 * @param name the name of thread, which shall be unique
 * @param entry the entry function of thread
 * @param parameter the parameter of thread enter function
 * @param stack_size the size of thread stack
 * @param priority the priority of thread
 * @param tick the time slice if there are same priority thread
 *
 * @return the created thread object
 */
rt_thread_t rt_thread_create(const char *name,
407 408 409 410 411
                             void (*entry)(void *parameter),
                             void       *parameter,
                             rt_uint32_t stack_size,
                             rt_uint8_t  priority,
                             rt_uint32_t tick)
412
{
413 414 415 416 417 418 419 420
    struct rt_thread *thread;
    void *stack_start;

    thread = (struct rt_thread *)rt_object_allocate(RT_Object_Class_Thread,
                                                    name);
    if (thread == RT_NULL)
        return RT_NULL;

B
Bernard Xiong 已提交
421
    stack_start = (void *)RT_KERNEL_MALLOC(stack_size);
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
    if (stack_start == RT_NULL)
    {
        /* allocate stack failure */
        rt_object_delete((rt_object_t)thread);

        return RT_NULL;
    }

    _rt_thread_init(thread,
                    name,
                    entry,
                    parameter,
                    stack_start,
                    stack_size,
                    priority,
                    tick);

    return thread;
440
}
441
RTM_EXPORT(rt_thread_create);
442

443
/**
B
bernard.xiong@gmail.com 已提交
444
 * This function will delete a thread. The thread object will be removed from
445
 * thread queue and deleted from system object management in the idle thread.
446 447 448
 *
 * @param thread the thread to be deleted
 *
B
bernard.xiong@gmail.com 已提交
449
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
450
 */
D
dzzxzz 已提交
451
rt_err_t rt_thread_delete(rt_thread_t thread)
452
{
453
    rt_base_t lock;
454

455 456
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
457 458
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
    RT_ASSERT(rt_object_is_systemobject((rt_object_t)thread) == RT_FALSE);
459

C
cliff-cmc 已提交
460
    if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE)
461 462
        return RT_EOK;

B
bernard 已提交
463
    if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT)
464 465 466 467
    {
        /* remove from schedule */
        rt_schedule_remove_thread(thread);
    }
468

469 470
    _thread_cleanup_execute(thread);

471 472
    /* release thread timer */
    rt_timer_detach(&(thread->thread_timer));
473

474 475
    /* disable interrupt */
    lock = rt_hw_interrupt_disable();
476

477 478 479
    /* change stat */
    thread->stat = RT_THREAD_CLOSE;

480 481
    /* insert to defunct thread list */
    rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));
482

483 484
    /* enable interrupt */
    rt_hw_interrupt_enable(lock);
485

486
    return RT_EOK;
487
}
488
RTM_EXPORT(rt_thread_delete);
489 490 491
#endif

/**
B
bernard.xiong@gmail.com 已提交
492 493 494
 * This function will let current thread yield processor, and scheduler will
 * choose a highest thread to run. After yield processor, the current thread
 * is still in READY state.
495
 *
B
bernard.xiong@gmail.com 已提交
496
 * @return RT_EOK
497
 */
D
dzzxzz 已提交
498
rt_err_t rt_thread_yield(void)
499
{
500 501 502 503 504 505 506
    struct rt_thread *thread;
    rt_base_t lock;

    thread = rt_thread_self();
    lock = rt_hw_interrupt_disable();
    thread->remaining_tick = thread->init_tick;
    thread->stat |= RT_THREAD_STAT_YIELD;
S
shaojinchun 已提交
507
    rt_schedule();
508
    rt_hw_interrupt_enable(lock);
509

510
    return RT_EOK;
511
}
512
RTM_EXPORT(rt_thread_yield);
513 514 515 516 517 518

/**
 * This function will let current thread sleep for some ticks.
 *
 * @param tick the sleep ticks
 *
B
bernard.xiong@gmail.com 已提交
519
 * @return RT_EOK
520
 */
D
dzzxzz 已提交
521
rt_err_t rt_thread_sleep(rt_tick_t tick)
522
{
523 524
    register rt_base_t temp;
    struct rt_thread *thread;
525

526
    /* set to current thread */
S
shaojinchun 已提交
527
    thread = rt_thread_self();
528
    RT_ASSERT(thread != RT_NULL);
529
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
530

S
shaojinchun 已提交
531 532 533
    /* disable interrupt */
    temp = rt_hw_interrupt_disable();

534 535
    /* suspend thread */
    rt_thread_suspend(thread);
536

537 538 539
    /* reset the timeout of thread timer and start it */
    rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &tick);
    rt_timer_start(&(thread->thread_timer));
540

541 542
    /* enable interrupt */
    rt_hw_interrupt_enable(temp);
543

544
    rt_schedule();
545

546 547 548
    /* clear error number of this thread to RT_EOK */
    if (thread->error == -RT_ETIMEOUT)
        thread->error = RT_EOK;
549

550
    return RT_EOK;
551 552 553 554 555 556 557
}

/**
 * This function will let current thread delay for some ticks.
 *
 * @param tick the delay ticks
 *
B
bernard.xiong@gmail.com 已提交
558
 * @return RT_EOK
559 560 561
 */
rt_err_t rt_thread_delay(rt_tick_t tick)
{
562
    return rt_thread_sleep(tick);
563
}
564
RTM_EXPORT(rt_thread_delay);
565

566
/**
B
Bernard Xiong 已提交
567
 * This function will let current thread delay until (*tick + inc_tick).
568 569 570 571 572 573
 *
 * @param tick the tick of last wakeup.
 * @param inc_tick the increment tick
 *
 * @return RT_EOK
 */
B
Bernard Xiong 已提交
574
rt_err_t rt_thread_delay_until(rt_tick_t *tick, rt_tick_t inc_tick)
575 576 577 578
{
    register rt_base_t level;
    struct rt_thread *thread;

B
Bernard Xiong 已提交
579 580
    RT_ASSERT(tick != RT_NULL);

581 582 583 584 585 586 587 588 589 590
    /* set to current thread */
    thread = rt_thread_self();
    RT_ASSERT(thread != RT_NULL);
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);

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

    if (rt_tick_get() - *tick < inc_tick)
    {
B
Bernard Xiong 已提交
591
        *tick = *tick + inc_tick - rt_tick_get();
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615

        /* suspend thread */
        rt_thread_suspend(thread);

        /* reset the timeout of thread timer and start it */
        rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, tick);
        rt_timer_start(&(thread->thread_timer));

        /* enable interrupt */
        rt_hw_interrupt_enable(level);

        rt_schedule();

        /* clear error number of this thread to RT_EOK */
        if (thread->error == -RT_ETIMEOUT)
        {
            thread->error = RT_EOK;
        }
    }
    else
    {
        rt_hw_interrupt_enable(level);
    }

B
Bernard Xiong 已提交
616 617 618
    /* get the wakeup tick */
    *tick = rt_tick_get();

619 620
    return RT_EOK;
}
621
RTM_EXPORT(rt_thread_delay_until);
622

H
heyuanjie 已提交
623 624 625
/**
 * This function will let current thread delay for some milliseconds.
 *
S
suhui 已提交
626
 * @param ms the delay ms time
H
heyuanjie 已提交
627 628 629 630 631 632 633 634 635 636 637 638 639
 *
 * @return RT_EOK
 */
rt_err_t rt_thread_mdelay(rt_int32_t ms)
{
    rt_tick_t tick;

    tick = rt_tick_from_millisecond(ms);

    return rt_thread_sleep(tick);
}
RTM_EXPORT(rt_thread_mdelay);

B
bernard.xiong@gmail.com 已提交
640 641 642 643 644
/**
 * This function will control thread behaviors according to control command.
 *
 * @param thread the specified thread to be controlled
 * @param cmd the control command, which includes
645
 *  RT_THREAD_CTRL_CHANGE_PRIORITY for changing priority level of thread;
B
bernard.xiong@gmail.com 已提交
646
 *  RT_THREAD_CTRL_STARTUP for starting a thread;
S
shaojinchun 已提交
647 648
 *  RT_THREAD_CTRL_CLOSE for delete a thread;
 *  RT_THREAD_CTRL_BIND_CPU for bind the thread to a CPU.
B
bernard.xiong@gmail.com 已提交
649 650 651 652
 * @param arg the argument of control command
 *
 * @return RT_EOK
 */
B
bernard 已提交
653
rt_err_t rt_thread_control(rt_thread_t thread, int cmd, void *arg)
654
{
655
    register rt_base_t temp;
656

657 658
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
659
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
660

661 662
    switch (cmd)
    {
663
        case RT_THREAD_CTRL_CHANGE_PRIORITY:
664
        {
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705
            /* disable interrupt */
            temp = rt_hw_interrupt_disable();

            /* for ready thread, change queue */
            if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY)
            {
                /* remove thread from schedule queue first */
                rt_schedule_remove_thread(thread);

                /* change thread priority */
                thread->current_priority = *(rt_uint8_t *)arg;

                /* recalculate priority attribute */
    #if RT_THREAD_PRIORITY_MAX > 32
                thread->number      = thread->current_priority >> 3;            /* 5bit */
                thread->number_mask = 1 << thread->number;
                thread->high_mask   = 1 << (thread->current_priority & 0x07);   /* 3bit */
    #else
                thread->number_mask = 1 << thread->current_priority;
    #endif

                /* insert thread to schedule queue again */
                rt_schedule_insert_thread(thread);
            }
            else
            {
                thread->current_priority = *(rt_uint8_t *)arg;

                /* recalculate priority attribute */
    #if RT_THREAD_PRIORITY_MAX > 32
                thread->number      = thread->current_priority >> 3;            /* 5bit */
                thread->number_mask = 1 << thread->number;
                thread->high_mask   = 1 << (thread->current_priority & 0x07);   /* 3bit */
    #else
                thread->number_mask = 1 << thread->current_priority;
    #endif
            }

            /* enable interrupt */
            rt_hw_interrupt_enable(temp);
            break;
706
        }
707

708 709 710
        case RT_THREAD_CTRL_STARTUP:
        {
            return rt_thread_startup(thread);
711
        }
712

713
        case RT_THREAD_CTRL_CLOSE:
714
        {
715 716 717 718 719 720 721 722 723 724 725 726 727 728
            rt_err_t rt_err;

            if (rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE)
            {
                rt_err = rt_thread_detach(thread);
            }
    #ifdef RT_USING_HEAP
            else
            {
                rt_err = rt_thread_delete(thread);
            }
    #endif
            rt_schedule();
            return rt_err;
729
        }
730 731 732

    #ifdef RT_USING_SMP
        case RT_THREAD_CTRL_BIND_CPU:
733
        {
734
            rt_uint8_t cpu;
735

736 737 738 739 740
            if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT)
            {
                /* we only support bind cpu before started phase. */
                return RT_ERROR;
            }
S
shaojinchun 已提交
741

742 743 744
            cpu = (rt_uint8_t)(size_t)arg;
            thread->bind_cpu = cpu > RT_CPUS_NR? RT_CPUS_NR : cpu;
            break;
S
shaojinchun 已提交
745
        }
746
    #endif /*RT_USING_SMP*/
S
shaojinchun 已提交
747

748 749
        default:
            break;
750
    }
751

752
    return RT_EOK;
753
}
754
RTM_EXPORT(rt_thread_control);
755 756 757 758 759 760

/**
 * This function will suspend the specified thread.
 *
 * @param thread the thread to be suspended
 *
B
bernard.xiong@gmail.com 已提交
761
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
762
 *
B
bernard.xiong@gmail.com 已提交
763 764
 * @note if suspend self thread, after this function call, the
 * rt_schedule() must be invoked.
765
 */
D
dzzxzz 已提交
766
rt_err_t rt_thread_suspend(rt_thread_t thread)
767
{
768
    register rt_base_t stat;
769
    register rt_base_t temp;
770

771 772
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
773
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
774

775
    RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend:  %s\n", thread->name));
776

777 778
    stat = thread->stat & RT_THREAD_STAT_MASK;
    if ((stat != RT_THREAD_READY) && (stat != RT_THREAD_RUNNING))
779
    {
780
        RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend: thread disorder, 0x%2x\n",
781
                                       thread->stat));
782 783
        return -RT_ERROR;
    }
784

785 786
    /* disable interrupt */
    temp = rt_hw_interrupt_disable();
787 788 789 790 791
    if (stat == RT_THREAD_RUNNING)
    {
        /* not suspend running status thread on other core */
        RT_ASSERT(thread == rt_thread_self());
    }
792

793 794
    /* change thread stat */
    rt_schedule_remove_thread(thread);
795
    thread->stat = RT_THREAD_SUSPEND | (thread->stat & ~RT_THREAD_STAT_MASK);
796

797 798 799
    /* stop thread timer anyway */
    rt_timer_stop(&(thread->thread_timer));

800 801
    /* enable interrupt */
    rt_hw_interrupt_enable(temp);
802

803
    RT_OBJECT_HOOK_CALL(rt_thread_suspend_hook, (thread));
804
    return RT_EOK;
805
}
806
RTM_EXPORT(rt_thread_suspend);
807 808 809 810 811 812

/**
 * This function will resume a thread and put it to system ready queue.
 *
 * @param thread the thread to be resumed
 *
B
bernard.xiong@gmail.com 已提交
813
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
814
 */
D
dzzxzz 已提交
815
rt_err_t rt_thread_resume(rt_thread_t thread)
816
{
817
    register rt_base_t temp;
818

819 820
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
821
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
822

823
    RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume:  %s\n", thread->name));
824

B
bernard 已提交
825
    if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_SUSPEND)
826 827
    {
        RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume: thread disorder, %d\n",
828
                                       thread->stat));
829

830 831
        return -RT_ERROR;
    }
832

833 834
    /* disable interrupt */
    temp = rt_hw_interrupt_disable();
835

836 837
    /* remove from suspend list */
    rt_list_remove(&(thread->tlist));
838

839
    rt_timer_stop(&thread->thread_timer);
840

841 842
    /* enable interrupt */
    rt_hw_interrupt_enable(temp);
843

844 845
    /* insert to schedule ready list */
    rt_schedule_insert_thread(thread);
846

847
    RT_OBJECT_HOOK_CALL(rt_thread_resume_hook, (thread));
848
    return RT_EOK;
849
}
850
RTM_EXPORT(rt_thread_resume);
851 852

/**
B
bernard.xiong@gmail.com 已提交
853
 * This function is the timeout function for thread, normally which is invoked
854
 * when thread is timeout to wait some resource.
855 856 857
 *
 * @param parameter the parameter of thread timeout function
 */
D
dzzxzz 已提交
858
void rt_thread_timeout(void *parameter)
859
{
860
    struct rt_thread *thread;
861

862
    thread = (struct rt_thread *)parameter;
863

864 865
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
B
bernard 已提交
866
    RT_ASSERT((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND);
867
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
868

869 870
    /* set error number */
    thread->error = -RT_ETIMEOUT;
871

872 873
    /* remove from suspend list */
    rt_list_remove(&(thread->tlist));
874

875 876
    /* insert to schedule ready list */
    rt_schedule_insert_thread(thread);
877

878 879
    /* do schedule */
    rt_schedule();
880
}
881
RTM_EXPORT(rt_thread_timeout);
882 883 884 885 886 887

/**
 * This function will find the specified thread.
 *
 * @param name the name of thread finding
 *
B
bernard.xiong@gmail.com 已提交
888 889 890
 * @return the found thread
 *
 * @note please don't invoke this function in interrupt status.
891
 */
D
dzzxzz 已提交
892
rt_thread_t rt_thread_find(char *name)
893
{
894
    return (rt_thread_t)rt_object_find(name, RT_Object_Class_Thread);
895
}
896
RTM_EXPORT(rt_thread_find);
897

D
dogandog 已提交
898
/**@}*/