thread.c 24.7 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
 *
 * 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
/* must be invoke witch rt_hw_interrupt_disable */
82
static void _rt_thread_cleanup_execute(rt_thread_t thread)
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
{
    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
static 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
    _rt_thread_cleanup_execute(thread);
118

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
#ifdef ARCH_CPU_STACK_GROWS_UPWARD
    thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
                                          (void *)((char *)thread->stack_addr),
168
                                          (void *)_rt_thread_exit);
169
#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
{
T
tangyuxin 已提交
361 362
    rt_base_t lock;

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
    _rt_thread_cleanup_execute(thread);
378

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

T
tangyuxin 已提交
382 383 384
    /* disable interrupt */
    lock = rt_hw_interrupt_disable();

385 386
    /* change stat */
    thread->stat = RT_THREAD_CLOSE;
387

388 389
    /* detach thread object */
    rt_object_detach((rt_object_t)thread);
390

T
tangyuxin 已提交
391 392 393
    /* enable interrupt */
    rt_hw_interrupt_enable(lock);

394
    return RT_EOK;
395
}
396 397
RTM_EXPORT(rt_thread_detach);

398
#ifdef RT_USING_HEAP
399 400 401 402 403 404 405 406 407 408 409 410 411 412
/**
 * 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,
413 414 415 416 417
                             void (*entry)(void *parameter),
                             void       *parameter,
                             rt_uint32_t stack_size,
                             rt_uint8_t  priority,
                             rt_uint32_t tick)
418
{
419 420 421 422 423 424 425 426
    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 已提交
427
    stack_start = (void *)RT_KERNEL_MALLOC(stack_size);
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
    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;
446
}
447
RTM_EXPORT(rt_thread_create);
448

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

461 462
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
463 464
    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);
465

C
cliff-cmc 已提交
466
    if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE)
467 468
        return RT_EOK;

B
bernard 已提交
469
    if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT)
470 471 472 473
    {
        /* remove from schedule */
        rt_schedule_remove_thread(thread);
    }
474

475
    _rt_thread_cleanup_execute(thread);
476

477 478
    /* release thread timer */
    rt_timer_detach(&(thread->thread_timer));
479

480 481
    /* disable interrupt */
    lock = rt_hw_interrupt_disable();
482

483 484 485
    /* change stat */
    thread->stat = RT_THREAD_CLOSE;

486 487
    /* insert to defunct thread list */
    rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));
488

489 490
    /* enable interrupt */
    rt_hw_interrupt_enable(lock);
491

492
    return RT_EOK;
493
}
494
RTM_EXPORT(rt_thread_delete);
495 496 497
#endif

/**
B
bernard.xiong@gmail.com 已提交
498 499 500
 * 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.
501
 *
B
bernard.xiong@gmail.com 已提交
502
 * @return RT_EOK
503
 */
D
dzzxzz 已提交
504
rt_err_t rt_thread_yield(void)
505
{
506 507 508 509 510 511 512
    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 已提交
513
    rt_schedule();
514
    rt_hw_interrupt_enable(lock);
515

516
    return RT_EOK;
517
}
518
RTM_EXPORT(rt_thread_yield);
519 520 521 522 523 524

/**
 * This function will let current thread sleep for some ticks.
 *
 * @param tick the sleep ticks
 *
B
bernard.xiong@gmail.com 已提交
525
 * @return RT_EOK
526
 */
D
dzzxzz 已提交
527
rt_err_t rt_thread_sleep(rt_tick_t tick)
528
{
529 530
    register rt_base_t temp;
    struct rt_thread *thread;
531

532
    /* set to current thread */
S
shaojinchun 已提交
533
    thread = rt_thread_self();
534
    RT_ASSERT(thread != RT_NULL);
535
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
536

S
shaojinchun 已提交
537 538 539
    /* disable interrupt */
    temp = rt_hw_interrupt_disable();

540 541
    /* suspend thread */
    rt_thread_suspend(thread);
542

543 544 545
    /* 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));
546

547 548
    /* enable interrupt */
    rt_hw_interrupt_enable(temp);
549

550
    rt_schedule();
551

552 553 554
    /* clear error number of this thread to RT_EOK */
    if (thread->error == -RT_ETIMEOUT)
        thread->error = RT_EOK;
555

556
    return RT_EOK;
557 558 559 560 561 562 563
}

/**
 * This function will let current thread delay for some ticks.
 *
 * @param tick the delay ticks
 *
B
bernard.xiong@gmail.com 已提交
564
 * @return RT_EOK
565 566 567
 */
rt_err_t rt_thread_delay(rt_tick_t tick)
{
568
    return rt_thread_sleep(tick);
569
}
570
RTM_EXPORT(rt_thread_delay);
571

572
/**
B
Bernard Xiong 已提交
573
 * This function will let current thread delay until (*tick + inc_tick).
574 575 576 577 578 579
 *
 * @param tick the tick of last wakeup.
 * @param inc_tick the increment tick
 *
 * @return RT_EOK
 */
B
Bernard Xiong 已提交
580
rt_err_t rt_thread_delay_until(rt_tick_t *tick, rt_tick_t inc_tick)
581 582 583
{
    register rt_base_t level;
    struct rt_thread *thread;
584
    rt_tick_t cur_tick;
585

B
Bernard Xiong 已提交
586 587
    RT_ASSERT(tick != RT_NULL);

588 589 590 591 592 593 594 595
    /* 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();

596
    cur_tick = rt_tick_get();
597
    if (cur_tick - *tick < inc_tick)
598
    {
599 600 601 602
        rt_tick_t left_tick;

        *tick += inc_tick;
        left_tick = *tick - cur_tick;
603 604 605 606 607

        /* suspend thread */
        rt_thread_suspend(thread);

        /* reset the timeout of thread timer and start it */
608
        rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &left_tick);
609 610 611 612 613 614 615 616 617 618 619 620 621 622 623
        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
    {
624
        *tick = cur_tick;
625 626 627 628 629
        rt_hw_interrupt_enable(level);
    }

    return RT_EOK;
}
630
RTM_EXPORT(rt_thread_delay_until);
631

H
heyuanjie 已提交
632 633 634
/**
 * This function will let current thread delay for some milliseconds.
 *
S
suhui 已提交
635
 * @param ms the delay ms time
H
heyuanjie 已提交
636 637 638 639 640 641 642 643 644 645 646 647 648
 *
 * @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 已提交
649 650 651 652 653
/**
 * 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
654
 *  RT_THREAD_CTRL_CHANGE_PRIORITY for changing priority level of thread;
B
bernard.xiong@gmail.com 已提交
655
 *  RT_THREAD_CTRL_STARTUP for starting a thread;
S
shaojinchun 已提交
656 657
 *  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 已提交
658 659 660 661
 * @param arg the argument of control command
 *
 * @return RT_EOK
 */
B
bernard 已提交
662
rt_err_t rt_thread_control(rt_thread_t thread, int cmd, void *arg)
663
{
664
    register rt_base_t temp;
665

666 667
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
668
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
669

670 671
    switch (cmd)
    {
672
        case RT_THREAD_CTRL_CHANGE_PRIORITY:
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 706 707 708 709 710 711 712 713 714
            /* 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;
715
        }
716

717 718 719
        case RT_THREAD_CTRL_STARTUP:
        {
            return rt_thread_startup(thread);
720
        }
721

722
        case RT_THREAD_CTRL_CLOSE:
723
        {
724 725 726 727 728 729 730 731 732 733 734 735 736 737
            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;
738
        }
739 740 741

    #ifdef RT_USING_SMP
        case RT_THREAD_CTRL_BIND_CPU:
742
        {
743
            rt_uint8_t cpu;
744

745 746 747 748 749
            if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT)
            {
                /* we only support bind cpu before started phase. */
                return RT_ERROR;
            }
S
shaojinchun 已提交
750

751 752 753
            cpu = (rt_uint8_t)(size_t)arg;
            thread->bind_cpu = cpu > RT_CPUS_NR? RT_CPUS_NR : cpu;
            break;
S
shaojinchun 已提交
754
        }
755
    #endif /*RT_USING_SMP*/
S
shaojinchun 已提交
756

757 758
        default:
            break;
759
    }
760

761
    return RT_EOK;
762
}
763
RTM_EXPORT(rt_thread_control);
764 765 766 767 768 769

/**
 * This function will suspend the specified thread.
 *
 * @param thread the thread to be suspended
 *
B
bernard.xiong@gmail.com 已提交
770
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
771
 *
B
bernard.xiong@gmail.com 已提交
772 773
 * @note if suspend self thread, after this function call, the
 * rt_schedule() must be invoked.
774
 */
D
dzzxzz 已提交
775
rt_err_t rt_thread_suspend(rt_thread_t thread)
776
{
777
    register rt_base_t stat;
778
    register rt_base_t temp;
779

780 781
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
782
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
783

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

786 787
    stat = thread->stat & RT_THREAD_STAT_MASK;
    if ((stat != RT_THREAD_READY) && (stat != RT_THREAD_RUNNING))
788
    {
789
        RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend: thread disorder, 0x%2x\n",
790
                                       thread->stat));
791 792
        return -RT_ERROR;
    }
793

794 795
    /* disable interrupt */
    temp = rt_hw_interrupt_disable();
796 797 798 799 800
    if (stat == RT_THREAD_RUNNING)
    {
        /* not suspend running status thread on other core */
        RT_ASSERT(thread == rt_thread_self());
    }
801

802 803
    /* change thread stat */
    rt_schedule_remove_thread(thread);
804
    thread->stat = RT_THREAD_SUSPEND | (thread->stat & ~RT_THREAD_STAT_MASK);
805

806 807 808
    /* stop thread timer anyway */
    rt_timer_stop(&(thread->thread_timer));

809 810
    /* enable interrupt */
    rt_hw_interrupt_enable(temp);
811

812
    RT_OBJECT_HOOK_CALL(rt_thread_suspend_hook, (thread));
813
    return RT_EOK;
814
}
815
RTM_EXPORT(rt_thread_suspend);
816 817 818 819 820 821

/**
 * 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 已提交
822
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
823
 */
D
dzzxzz 已提交
824
rt_err_t rt_thread_resume(rt_thread_t thread)
825
{
826
    register rt_base_t temp;
827

828 829
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
830
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
831

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

B
bernard 已提交
834
    if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_SUSPEND)
835 836
    {
        RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume: thread disorder, %d\n",
837
                                       thread->stat));
838

839 840
        return -RT_ERROR;
    }
841

842 843
    /* disable interrupt */
    temp = rt_hw_interrupt_disable();
844

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

848
    rt_timer_stop(&thread->thread_timer);
849

850 851
    /* enable interrupt */
    rt_hw_interrupt_enable(temp);
852

853 854
    /* insert to schedule ready list */
    rt_schedule_insert_thread(thread);
855

856
    RT_OBJECT_HOOK_CALL(rt_thread_resume_hook, (thread));
857
    return RT_EOK;
858
}
859
RTM_EXPORT(rt_thread_resume);
860 861

/**
B
bernard.xiong@gmail.com 已提交
862
 * This function is the timeout function for thread, normally which is invoked
863
 * when thread is timeout to wait some resource.
864 865 866
 *
 * @param parameter the parameter of thread timeout function
 */
D
dzzxzz 已提交
867
void rt_thread_timeout(void *parameter)
868
{
869
    struct rt_thread *thread;
870

871
    thread = (struct rt_thread *)parameter;
872

873 874
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
B
bernard 已提交
875
    RT_ASSERT((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND);
876
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
877

878 879
    /* set error number */
    thread->error = -RT_ETIMEOUT;
880

881 882
    /* remove from suspend list */
    rt_list_remove(&(thread->tlist));
883

884 885
    /* insert to schedule ready list */
    rt_schedule_insert_thread(thread);
886

887 888
    /* do schedule */
    rt_schedule();
889
}
890
RTM_EXPORT(rt_thread_timeout);
891 892 893 894 895 896

/**
 * This function will find the specified thread.
 *
 * @param name the name of thread finding
 *
B
bernard.xiong@gmail.com 已提交
897 898 899
 * @return the found thread
 *
 * @note please don't invoke this function in interrupt status.
900
 */
D
dzzxzz 已提交
901
rt_thread_t rt_thread_find(char *name)
902
{
903
    return (rt_thread_t)rt_object_find(name, RT_Object_Class_Thread);
904
}
905
RTM_EXPORT(rt_thread_find);
906

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