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 30 31
 */

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

extern rt_list_t rt_thread_defunct;

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

41 42
/**
 * @ingroup Hook
43
 * This function sets a hook function when the system suspend a thread.
44 45 46 47 48 49 50 51 52
 *
 * @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 已提交
53

54 55
/**
 * @ingroup Hook
56
 * This function sets a hook function when the system resume a thread.
57 58 59 60 61 62 63 64 65
 *
 * @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 已提交
66 67 68

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

78 79
#endif

80
void rt_thread_exit(void)
81
{
82 83 84 85
    struct rt_thread *thread;
    register rt_base_t level;

    /* get current thread */
S
shaojinchun 已提交
86
    thread = rt_thread_self();
87 88 89 90 91 92 93 94 95 96

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

    /* remove from schedule */
    rt_schedule_remove_thread(thread);
    /* change stat */
    thread->stat = RT_THREAD_CLOSE;

    /* remove it from timer list */
97
    rt_timer_detach(&thread->thread_timer);
98 99 100 101 102 103 104 105 106 107 108 109 110 111

    if ((rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE) &&
        thread->cleanup == RT_NULL)
    {
        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();
112 113 114

    /* enable interrupt */
    rt_hw_interrupt_enable(level);
115
}
116

D
dzzxzz 已提交
117
static rt_err_t _rt_thread_init(struct rt_thread *thread,
118 119 120 121 122 123 124
                                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)
125
{
126 127 128 129 130 131 132 133
    /* init thread list */
    rt_list_init(&(thread->tlist));

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

    /* stack init */
    thread->stack_addr = stack_start;
W
weety 已提交
134
    thread->stack_size = stack_size;
135 136 137

    /* init thread stack */
    rt_memset(thread->stack_addr, '#', thread->stack_size);
138 139 140 141 142
#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
143
    thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
144
                                          (rt_uint8_t *)((char *)thread->stack_addr + thread->stack_size - sizeof(rt_ubase_t)),
145
                                          (void *)rt_thread_exit);
146
#endif
147 148 149 150 151 152

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

153 154 155
    thread->number_mask = 0;
#if RT_THREAD_PRIORITY_MAX > 32
    thread->number = 0;
B
Bernard Xiong 已提交
156
    thread->high_mask = 0;
157 158
#endif

159 160 161 162 163 164 165 166
    /* tick init */
    thread->init_tick      = tick;
    thread->remaining_tick = tick;

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

S
shaojinchun 已提交
167 168 169 170 171 172 173 174
#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 已提交
175
    thread->critical_lock_nest = 0;
S
shaojinchun 已提交
176 177
#endif /*RT_USING_SMP*/

178 179 180 181
    /* initialize cleanup function and user data */
    thread->cleanup   = 0;
    thread->user_data = 0;

B
Bernard Xiong 已提交
182
    /* initialize thread timer */
183 184 185 186 187 188 189
    rt_timer_init(&(thread->thread_timer),
                  thread->name,
                  rt_thread_timeout,
                  thread,
                  0,
                  RT_TIMER_FLAG_ONE_SHOT);

B
bernard 已提交
190 191 192 193 194
    /* initialize signal */
#ifdef RT_USING_SIGNALS
    thread->sig_mask    = 0x00;
    thread->sig_pending = 0x00;

S
shaojinchun 已提交
195
#ifndef RT_USING_SMP
B
bernard 已提交
196
    thread->sig_ret     = RT_NULL;
S
shaojinchun 已提交
197
#endif
B
bernard 已提交
198 199 200 201
    thread->sig_vectors = RT_NULL;
    thread->si_list     = RT_NULL;
#endif

H
heyuanjie 已提交
202 203 204 205
#ifdef RT_USING_LWP
    thread->lwp = RT_NULL;
#endif

206
    RT_OBJECT_HOOK_CALL(rt_thread_inited_hook, (thread));
B
Bernard Xiong 已提交
207

208
    return RT_EOK;
209 210 211 212 213 214
}

/**
 * @addtogroup Thread
 */

D
dogandog 已提交
215
/**@{*/
216 217

/**
B
bernard.xiong@gmail.com 已提交
218 219
 * This function will initialize a thread, normally it's used to initialize a
 * static thread object.
220 221 222 223 224 225 226 227 228 229
 *
 * @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 已提交
230
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
231
 */
D
dzzxzz 已提交
232
rt_err_t rt_thread_init(struct rt_thread *thread,
233 234 235 236 237 238 239
                        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)
240
{
241 242 243 244
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
    RT_ASSERT(stack_start != RT_NULL);

B
Bernard Xiong 已提交
245
    /* initialize thread object */
246 247 248 249 250 251 252 253 254 255
    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);
256
}
257
RTM_EXPORT(rt_thread_init);
258 259 260 261 262 263

/**
 * This function will return self thread object
 *
 * @return the self thread object
 */
D
dzzxzz 已提交
264
rt_thread_t rt_thread_self(void)
265
{
S
shaojinchun 已提交
266 267 268 269 270 271 272 273 274 275 276
#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;

277
    return rt_current_thread;
S
shaojinchun 已提交
278
#endif
279
}
280
RTM_EXPORT(rt_thread_self);
281 282 283 284 285 286

/**
 * 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 已提交
287
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
288
 */
D
dzzxzz 已提交
289
rt_err_t rt_thread_startup(rt_thread_t thread)
290
{
291 292
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
B
bernard 已提交
293
    RT_ASSERT((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_INIT);
294
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
295

B
Bernard Xiong 已提交
296
    /* set current priority to initialize priority */
297
    thread->current_priority = thread->init_priority;
298

299
    /* calculate priority attribute */
300
#if RT_THREAD_PRIORITY_MAX > 32
301 302 303
    thread->number      = thread->current_priority >> 3;            /* 5bit */
    thread->number_mask = 1L << thread->number;
    thread->high_mask   = 1L << (thread->current_priority & 0x07);  /* 3bit */
304
#else
305
    thread->number_mask = 1L << thread->current_priority;
306 307
#endif

308
    RT_DEBUG_LOG(RT_DEBUG_THREAD, ("startup a thread:%s with priority:%d\n",
309
                                   thread->name, thread->init_priority));
310 311 312 313 314 315 316 317 318 319 320
    /* 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;
321
}
322
RTM_EXPORT(rt_thread_startup);
323 324

/**
B
bernard.xiong@gmail.com 已提交
325 326
 * This function will detach a thread. The thread object will be removed from
 * thread queue and detached/deleted from system object management.
327 328 329
 *
 * @param thread the thread to be deleted
 *
B
bernard.xiong@gmail.com 已提交
330
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
331
 */
D
dzzxzz 已提交
332
rt_err_t rt_thread_detach(rt_thread_t thread)
333
{
334
    rt_base_t lock;
335

336 337
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
338 339
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
    RT_ASSERT(rt_object_is_systemobject((rt_object_t)thread));
340

C
cliff-cmc 已提交
341
    if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE)
342 343
        return RT_EOK;

B
bernard 已提交
344
    if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT)
345 346 347 348
    {
        /* remove from schedule */
        rt_schedule_remove_thread(thread);
    }
349

350 351
    /* release thread timer */
    rt_timer_detach(&(thread->thread_timer));
352

353 354
    /* change stat */
    thread->stat = RT_THREAD_CLOSE;
355

B
Bernard Xiong 已提交
356 357 358 359 360 361
    if ((rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE) &&
        thread->cleanup == RT_NULL)
    {
        rt_object_detach((rt_object_t)thread);
    }
    else
362 363 364 365 366 367 368 369
    {
        /* disable interrupt */
        lock = rt_hw_interrupt_disable();
        /* insert to defunct thread list */
        rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));
        /* enable interrupt */
        rt_hw_interrupt_enable(lock);
    }
370

371
    return RT_EOK;
372
}
373 374
RTM_EXPORT(rt_thread_detach);

375
#ifdef RT_USING_HEAP
376 377 378 379 380 381 382 383 384 385 386 387 388 389
/**
 * 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,
390 391 392 393 394
                             void (*entry)(void *parameter),
                             void       *parameter,
                             rt_uint32_t stack_size,
                             rt_uint8_t  priority,
                             rt_uint32_t tick)
395
{
396 397 398 399 400 401 402 403
    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 已提交
404
    stack_start = (void *)RT_KERNEL_MALLOC(stack_size);
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422
    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;
423
}
424
RTM_EXPORT(rt_thread_create);
425

426
/**
B
bernard.xiong@gmail.com 已提交
427
 * This function will delete a thread. The thread object will be removed from
428
 * thread queue and deleted from system object management in the idle thread.
429 430 431
 *
 * @param thread the thread to be deleted
 *
B
bernard.xiong@gmail.com 已提交
432
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
433
 */
D
dzzxzz 已提交
434
rt_err_t rt_thread_delete(rt_thread_t thread)
435
{
436
    rt_base_t lock;
437

438 439
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
440 441
    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);
442

C
cliff-cmc 已提交
443
    if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE)
444 445
        return RT_EOK;

B
bernard 已提交
446
    if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT)
447 448 449 450
    {
        /* remove from schedule */
        rt_schedule_remove_thread(thread);
    }
451

452 453
    /* release thread timer */
    rt_timer_detach(&(thread->thread_timer));
454

455 456
    /* disable interrupt */
    lock = rt_hw_interrupt_disable();
457

458 459 460
    /* change stat */
    thread->stat = RT_THREAD_CLOSE;

461 462
    /* insert to defunct thread list */
    rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));
463

464 465
    /* enable interrupt */
    rt_hw_interrupt_enable(lock);
466

467
    return RT_EOK;
468
}
469
RTM_EXPORT(rt_thread_delete);
470 471 472
#endif

/**
B
bernard.xiong@gmail.com 已提交
473 474 475
 * 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.
476
 *
B
bernard.xiong@gmail.com 已提交
477
 * @return RT_EOK
478
 */
D
dzzxzz 已提交
479
rt_err_t rt_thread_yield(void)
480
{
481 482 483 484 485 486 487
    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 已提交
488
    rt_schedule();
489
    rt_hw_interrupt_enable(lock);
490

491
    return RT_EOK;
492
}
493
RTM_EXPORT(rt_thread_yield);
494 495 496 497 498 499

/**
 * This function will let current thread sleep for some ticks.
 *
 * @param tick the sleep ticks
 *
B
bernard.xiong@gmail.com 已提交
500
 * @return RT_EOK
501
 */
D
dzzxzz 已提交
502
rt_err_t rt_thread_sleep(rt_tick_t tick)
503
{
504 505
    register rt_base_t temp;
    struct rt_thread *thread;
506

507
    /* set to current thread */
S
shaojinchun 已提交
508
    thread = rt_thread_self();
509
    RT_ASSERT(thread != RT_NULL);
510
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
511

S
shaojinchun 已提交
512 513 514
    /* disable interrupt */
    temp = rt_hw_interrupt_disable();

515 516
    /* suspend thread */
    rt_thread_suspend(thread);
517

518 519 520
    /* 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));
521

522 523
    /* enable interrupt */
    rt_hw_interrupt_enable(temp);
524

525
    rt_schedule();
526

527 528 529
    /* clear error number of this thread to RT_EOK */
    if (thread->error == -RT_ETIMEOUT)
        thread->error = RT_EOK;
530

531
    return RT_EOK;
532 533 534 535 536 537 538
}

/**
 * This function will let current thread delay for some ticks.
 *
 * @param tick the delay ticks
 *
B
bernard.xiong@gmail.com 已提交
539
 * @return RT_EOK
540 541 542
 */
rt_err_t rt_thread_delay(rt_tick_t tick)
{
543
    return rt_thread_sleep(tick);
544
}
545
RTM_EXPORT(rt_thread_delay);
546

547
/**
B
Bernard Xiong 已提交
548
 * This function will let current thread delay until (*tick + inc_tick).
549 550 551 552 553 554
 *
 * @param tick the tick of last wakeup.
 * @param inc_tick the increment tick
 *
 * @return RT_EOK
 */
B
Bernard Xiong 已提交
555
rt_err_t rt_thread_delay_until(rt_tick_t *tick, rt_tick_t inc_tick)
556 557 558 559
{
    register rt_base_t level;
    struct rt_thread *thread;

B
Bernard Xiong 已提交
560 561
    RT_ASSERT(tick != RT_NULL);

562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596
    /* 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)
    {
        *tick = rt_tick_get() - *tick + inc_tick;

        /* 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 已提交
597 598 599
    /* get the wakeup tick */
    *tick = rt_tick_get();

600 601
    return RT_EOK;
}
602
RTM_EXPORT(rt_thread_delay_until);
603

H
heyuanjie 已提交
604 605 606
/**
 * This function will let current thread delay for some milliseconds.
 *
S
suhui 已提交
607
 * @param ms the delay ms time
H
heyuanjie 已提交
608 609 610 611 612 613 614 615 616 617 618 619 620
 *
 * @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 已提交
621 622 623 624 625
/**
 * 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
626
 *  RT_THREAD_CTRL_CHANGE_PRIORITY for changing priority level of thread;
B
bernard.xiong@gmail.com 已提交
627
 *  RT_THREAD_CTRL_STARTUP for starting a thread;
S
shaojinchun 已提交
628 629
 *  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 已提交
630 631 632 633
 * @param arg the argument of control command
 *
 * @return RT_EOK
 */
B
bernard 已提交
634
rt_err_t rt_thread_control(rt_thread_t thread, int cmd, void *arg)
635
{
636
    register rt_base_t temp;
637

638 639
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
640
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
641

642 643 644 645 646
    switch (cmd)
    {
    case RT_THREAD_CTRL_CHANGE_PRIORITY:
        /* disable interrupt */
        temp = rt_hw_interrupt_disable();
647

648
        /* for ready thread, change queue */
B
bernard 已提交
649
        if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY)
650 651 652
        {
            /* remove thread from schedule queue first */
            rt_schedule_remove_thread(thread);
653

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

657
            /* recalculate priority attribute */
658
#if RT_THREAD_PRIORITY_MAX > 32
659 660 661
            thread->number      = thread->current_priority >> 3;            /* 5bit */
            thread->number_mask = 1 << thread->number;
            thread->high_mask   = 1 << (thread->current_priority & 0x07);   /* 3bit */
662
#else
663
            thread->number_mask = 1 << thread->current_priority;
664 665
#endif

666 667 668 669 670 671
            /* insert thread to schedule queue again */
            rt_schedule_insert_thread(thread);
        }
        else
        {
            thread->current_priority = *(rt_uint8_t *)arg;
672

673
            /* recalculate priority attribute */
674
#if RT_THREAD_PRIORITY_MAX > 32
675 676 677
            thread->number      = thread->current_priority >> 3;            /* 5bit */
            thread->number_mask = 1 << thread->number;
            thread->high_mask   = 1 << (thread->current_priority & 0x07);   /* 3bit */
678
#else
679
            thread->number_mask = 1 << thread->current_priority;
680
#endif
681
        }
682

683 684 685
        /* enable interrupt */
        rt_hw_interrupt_enable(temp);
        break;
686

687 688
    case RT_THREAD_CTRL_STARTUP:
        return rt_thread_startup(thread);
689

690
    case RT_THREAD_CTRL_CLOSE:
691 692 693 694 695 696 697 698 699 700

        if (rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE)
        {
            return rt_thread_detach(thread);
        }
#ifdef RT_USING_HEAP
        else
        {
            return rt_thread_delete(thread);
        }
701 702
#endif

S
shaojinchun 已提交
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
#ifdef RT_USING_SMP
    case RT_THREAD_CTRL_BIND_CPU:
    {
        rt_uint8_t cpu;

        if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT)
        {
            /* we only support bind cpu before started phase. */
            return RT_ERROR;
        }

        cpu = (rt_uint8_t)(size_t)arg;
        thread->bind_cpu = cpu > RT_CPUS_NR? RT_CPUS_NR : cpu;
        break;
    }
#endif /*RT_USING_SMP*/
719 720 721
    default:
        break;
    }
722

723
    return RT_EOK;
724
}
725
RTM_EXPORT(rt_thread_control);
726 727 728 729 730 731

/**
 * This function will suspend the specified thread.
 *
 * @param thread the thread to be suspended
 *
B
bernard.xiong@gmail.com 已提交
732
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
733
 *
B
bernard.xiong@gmail.com 已提交
734 735
 * @note if suspend self thread, after this function call, the
 * rt_schedule() must be invoked.
736
 */
D
dzzxzz 已提交
737
rt_err_t rt_thread_suspend(rt_thread_t thread)
738
{
739
    register rt_base_t stat;
740
    register rt_base_t temp;
741

742 743
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
744
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
745

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

748 749
    stat = thread->stat & RT_THREAD_STAT_MASK;
    if ((stat != RT_THREAD_READY) && (stat != RT_THREAD_RUNNING))
750
    {
751
        RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend: thread disorder, 0x%2x\n",
752
                                       thread->stat));
753 754
        return -RT_ERROR;
    }
755

756 757
    /* disable interrupt */
    temp = rt_hw_interrupt_disable();
758 759 760 761 762
    if (stat == RT_THREAD_RUNNING)
    {
        /* not suspend running status thread on other core */
        RT_ASSERT(thread == rt_thread_self());
    }
763

764 765
    /* change thread stat */
    rt_schedule_remove_thread(thread);
766
    thread->stat = RT_THREAD_SUSPEND | (thread->stat & ~RT_THREAD_STAT_MASK);
767

768 769 770
    /* stop thread timer anyway */
    rt_timer_stop(&(thread->thread_timer));

771 772
    /* enable interrupt */
    rt_hw_interrupt_enable(temp);
773

774
    RT_OBJECT_HOOK_CALL(rt_thread_suspend_hook, (thread));
775
    return RT_EOK;
776
}
777
RTM_EXPORT(rt_thread_suspend);
778 779 780 781 782 783

/**
 * 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 已提交
784
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
785
 */
D
dzzxzz 已提交
786
rt_err_t rt_thread_resume(rt_thread_t thread)
787
{
788
    register rt_base_t temp;
789

790 791
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
792
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
793

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

B
bernard 已提交
796
    if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_SUSPEND)
797 798
    {
        RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume: thread disorder, %d\n",
799
                                       thread->stat));
800

801 802
        return -RT_ERROR;
    }
803

804 805
    /* disable interrupt */
    temp = rt_hw_interrupt_disable();
806

807 808
    /* remove from suspend list */
    rt_list_remove(&(thread->tlist));
809

810
    rt_timer_stop(&thread->thread_timer);
811

812 813
    /* enable interrupt */
    rt_hw_interrupt_enable(temp);
814

815 816
    /* insert to schedule ready list */
    rt_schedule_insert_thread(thread);
817

818
    RT_OBJECT_HOOK_CALL(rt_thread_resume_hook, (thread));
819
    return RT_EOK;
820
}
821
RTM_EXPORT(rt_thread_resume);
822 823

/**
B
bernard.xiong@gmail.com 已提交
824
 * This function is the timeout function for thread, normally which is invoked
825
 * when thread is timeout to wait some resource.
826 827 828
 *
 * @param parameter the parameter of thread timeout function
 */
D
dzzxzz 已提交
829
void rt_thread_timeout(void *parameter)
830
{
831
    struct rt_thread *thread;
832

833
    thread = (struct rt_thread *)parameter;
834

835 836
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
B
bernard 已提交
837
    RT_ASSERT((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND);
838
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
839

840 841
    /* set error number */
    thread->error = -RT_ETIMEOUT;
842

843 844
    /* remove from suspend list */
    rt_list_remove(&(thread->tlist));
845

846 847
    /* insert to schedule ready list */
    rt_schedule_insert_thread(thread);
848

849 850
    /* do schedule */
    rt_schedule();
851
}
852
RTM_EXPORT(rt_thread_timeout);
853 854 855 856 857 858

/**
 * This function will find the specified thread.
 *
 * @param name the name of thread finding
 *
B
bernard.xiong@gmail.com 已提交
859 860 861
 * @return the found thread
 *
 * @note please don't invoke this function in interrupt status.
862
 */
D
dzzxzz 已提交
863
rt_thread_t rt_thread_find(char *name)
864
{
865 866 867 868 869 870 871 872 873
    struct rt_object_information *information;
    struct rt_object *object;
    struct rt_list_node *node;

    /* enter critical */
    if (rt_thread_self() != RT_NULL)
        rt_enter_critical();

    /* try to find device object */
874 875
    information = rt_object_get_information(RT_Object_Class_Thread);
    RT_ASSERT(information != RT_NULL);
876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896
    for (node  = information->object_list.next;
         node != &(information->object_list);
         node  = node->next)
    {
        object = rt_list_entry(node, struct rt_object, list);
        if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0)
        {
            /* leave critical */
            if (rt_thread_self() != RT_NULL)
                rt_exit_critical();

            return (rt_thread_t)object;
        }
    }

    /* leave critical */
    if (rt_thread_self() != RT_NULL)
        rt_exit_critical();

    /* not found */
    return RT_NULL;
897
}
898
RTM_EXPORT(rt_thread_find);
899

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