thread.c 27.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
#ifdef RT_USING_HOOK
static void (*rt_thread_suspend_hook)(rt_thread_t thread);
B
Bernard Xiong 已提交
37 38 39
static void (*rt_thread_resume_hook) (rt_thread_t thread);
static void (*rt_thread_inited_hook) (rt_thread_t thread);

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

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

/**
65
 * @brief   This function sets a hook function when a thread is initialized.
B
Bernard Xiong 已提交
66
 *
67
 * @param   hook the specified hook function.
B
Bernard Xiong 已提交
68 69 70
 */
void rt_thread_inited_sethook(void (*hook)(rt_thread_t thread))
{
71
    rt_thread_inited_hook = hook;
B
Bernard Xiong 已提交
72 73
}

74
#endif /* RT_USING_HOOK */
75

mysterywolf's avatar
mysterywolf 已提交
76
static void _thread_cleanup_execute(rt_thread_t thread)
77 78 79 80
{
    register rt_base_t level;
#ifdef RT_USING_MODULE
    struct rt_dlmodule *module = RT_NULL;
81
#endif /* RT_USING_MODULE */
82 83 84 85 86 87 88
    level = rt_hw_interrupt_disable();
#ifdef RT_USING_MODULE
    module = (struct rt_dlmodule*)thread->module_id;
    if (module)
    {
        dlmodule_destroy(module);
    }
89
#endif /* RT_USING_MODULE */
90 91 92 93 94 95
    /* invoke thread cleanup */
    if (thread->cleanup != RT_NULL)
        thread->cleanup(thread);

#ifdef RT_USING_SIGNALS
    rt_thread_free_sig(thread);
96
#endif /* RT_USING_SIGNALS */
97 98 99
    rt_hw_interrupt_enable(level);
}

mysterywolf's avatar
mysterywolf 已提交
100
static void _thread_exit(void)
101
{
102 103 104 105
    struct rt_thread *thread;
    register rt_base_t level;

    /* get current thread */
S
shaojinchun 已提交
106
    thread = rt_thread_self();
107 108 109 110

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

mysterywolf's avatar
mysterywolf 已提交
111
    _thread_cleanup_execute(thread);
112

113 114 115 116 117 118
    /* remove from schedule */
    rt_schedule_remove_thread(thread);
    /* change stat */
    thread->stat = RT_THREAD_CLOSE;

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

121
    if (rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE)
122 123 124 125 126 127
    {
        rt_object_detach((rt_object_t)thread);
    }
    else
    {
        /* insert to defunct thread list */
F
fenghuijie 已提交
128
        rt_thread_defunct_enqueue(thread);
129 130 131 132
    }

    /* switch to next task */
    rt_schedule();
133 134 135

    /* enable interrupt */
    rt_hw_interrupt_enable(level);
136
}
137

mysterywolf's avatar
mysterywolf 已提交
138 139 140 141 142 143 144 145
static rt_err_t _thread_init(struct rt_thread *thread,
                             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)
146
{
147 148 149 150 151 152 153 154
    /* init thread list */
    rt_list_init(&(thread->tlist));

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

    /* stack init */
    thread->stack_addr = stack_start;
W
weety 已提交
155
    thread->stack_size = stack_size;
156 157 158

    /* init thread stack */
    rt_memset(thread->stack_addr, '#', thread->stack_size);
159 160 161
#ifdef ARCH_CPU_STACK_GROWS_UPWARD
    thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
                                          (void *)((char *)thread->stack_addr),
mysterywolf's avatar
mysterywolf 已提交
162
                                          (void *)_thread_exit);
163
#else
164
    thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
165
                                          (rt_uint8_t *)((char *)thread->stack_addr + thread->stack_size - sizeof(rt_ubase_t)),
mysterywolf's avatar
mysterywolf 已提交
166
                                          (void *)_thread_exit);
167
#endif /* ARCH_CPU_STACK_GROWS_UPWARD */
168 169 170 171 172 173

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

174 175 176
    thread->number_mask = 0;
#if RT_THREAD_PRIORITY_MAX > 32
    thread->number = 0;
B
Bernard Xiong 已提交
177
    thread->high_mask = 0;
178
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
179

180 181 182 183 184 185 186 187
    /* tick init */
    thread->init_tick      = tick;
    thread->remaining_tick = tick;

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

S
shaojinchun 已提交
188 189 190 191 192 193 194 195
#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 已提交
196
    thread->critical_lock_nest = 0;
197
#endif /* RT_USING_SMP */
S
shaojinchun 已提交
198

199 200 201 202
    /* initialize cleanup function and user data */
    thread->cleanup   = 0;
    thread->user_data = 0;

B
Bernard Xiong 已提交
203
    /* initialize thread timer */
204 205 206 207 208 209 210
    rt_timer_init(&(thread->thread_timer),
                  thread->name,
                  rt_thread_timeout,
                  thread,
                  0,
                  RT_TIMER_FLAG_ONE_SHOT);

B
bernard 已提交
211 212 213 214 215
    /* initialize signal */
#ifdef RT_USING_SIGNALS
    thread->sig_mask    = 0x00;
    thread->sig_pending = 0x00;

S
shaojinchun 已提交
216
#ifndef RT_USING_SMP
B
bernard 已提交
217
    thread->sig_ret     = RT_NULL;
218
#endif /* RT_USING_SMP */
B
bernard 已提交
219 220
    thread->sig_vectors = RT_NULL;
    thread->si_list     = RT_NULL;
221
#endif /* RT_USING_SIGNALS */
B
bernard 已提交
222

H
heyuanjie 已提交
223 224
#ifdef RT_USING_LWP
    thread->lwp = RT_NULL;
225
#endif /* RT_USING_LWP */
H
heyuanjie 已提交
226

F
fenghuijie 已提交
227 228 229 230
#ifdef RT_USING_CPU_USAGE
    thread->duration_tick = 0;
#endif

231
    RT_OBJECT_HOOK_CALL(rt_thread_inited_hook, (thread));
B
Bernard Xiong 已提交
232

233
    return RT_EOK;
234 235 236 237 238 239
}

/**
 * @addtogroup Thread
 */

D
dogandog 已提交
240
/**@{*/
241 242

/**
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
 * @brief   This function will initialize a thread, normally it's used to initialize a
 *          static thread object.
 *
 * @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.
 *
 * @return  Return the operation status. When the return value is RT_EOK, the function is successfully executed.
 *          When the return value is any other values, it means this operation failed.
264
 */
D
dzzxzz 已提交
265
rt_err_t rt_thread_init(struct rt_thread *thread,
266 267 268 269 270 271 272
                        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)
273
{
274 275 276 277
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
    RT_ASSERT(stack_start != RT_NULL);

B
Bernard Xiong 已提交
278
    /* initialize thread object */
279 280
    rt_object_init((rt_object_t)thread, RT_Object_Class_Thread, name);

mysterywolf's avatar
mysterywolf 已提交
281 282 283 284 285 286 287 288
    return _thread_init(thread,
                        name,
                        entry,
                        parameter,
                        stack_start,
                        stack_size,
                        priority,
                        tick);
289
}
290
RTM_EXPORT(rt_thread_init);
291 292

/**
293
 * @brief   This function will return self thread object.
294
 *
295
 * @return  the self thread object.
296
 */
D
dzzxzz 已提交
297
rt_thread_t rt_thread_self(void)
298
{
S
shaojinchun 已提交
299 300 301 302 303 304 305 306 307 308 309
#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;

310
    return rt_current_thread;
311
#endif /* RT_USING_SMP */
312
}
313
RTM_EXPORT(rt_thread_self);
314 315

/**
316
 * @brief   This function will start a thread and put it to system ready queue.
317
 *
318
 * @param   thread the thread to be started.
319
 *
320 321
 * @return  Return the operation status. When the return value is RT_EOK, the function is successfully executed.
 *          When the return value is any other values, it means this operation failed.
322
 */
D
dzzxzz 已提交
323
rt_err_t rt_thread_startup(rt_thread_t thread)
324
{
325 326
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
B
bernard 已提交
327
    RT_ASSERT((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_INIT);
328
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
329

B
Bernard Xiong 已提交
330
    /* set current priority to initialize priority */
331
    thread->current_priority = thread->init_priority;
332

333
    /* calculate priority attribute */
334
#if RT_THREAD_PRIORITY_MAX > 32
335 336 337
    thread->number      = thread->current_priority >> 3;            /* 5bit */
    thread->number_mask = 1L << thread->number;
    thread->high_mask   = 1L << (thread->current_priority & 0x07);  /* 3bit */
338
#else
339
    thread->number_mask = 1L << thread->current_priority;
340
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
341

342
    RT_DEBUG_LOG(RT_DEBUG_THREAD, ("startup a thread:%s with priority:%d\n",
343
                                   thread->name, thread->init_priority));
344 345 346 347 348 349 350 351 352 353 354
    /* 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;
355
}
356
RTM_EXPORT(rt_thread_startup);
357 358

/**
359 360
 * @brief   This function will detach a thread. The thread object will be removed from
 *          thread queue and detached/deleted from system object management.
361
 *
362
 * @param   thread the thread to be deleted.
363
 *
364 365
 * @return  Return the operation status. When the return value is RT_EOK, the function is successfully executed.
 *          When the return value is any other values, it means this operation failed.
366
 */
D
dzzxzz 已提交
367
rt_err_t rt_thread_detach(rt_thread_t thread)
368
{
T
tangyuxin 已提交
369 370
    rt_base_t lock;

371 372
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
373 374
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
    RT_ASSERT(rt_object_is_systemobject((rt_object_t)thread));
375

C
cliff-cmc 已提交
376
    if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE)
377 378
        return RT_EOK;

B
bernard 已提交
379
    if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT)
380 381 382 383
    {
        /* remove from schedule */
        rt_schedule_remove_thread(thread);
    }
384

mysterywolf's avatar
mysterywolf 已提交
385
    _thread_cleanup_execute(thread);
386

387 388
    /* release thread timer */
    rt_timer_detach(&(thread->thread_timer));
389

390 391
    /* change stat */
    thread->stat = RT_THREAD_CLOSE;
392

F
fenghuijie 已提交
393 394 395 396 397 398 399 400 401 402 403 404 405
    if (rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE)
    {
        rt_object_detach((rt_object_t)thread);
    }
    else
    {
        /* disable interrupt */
        lock = rt_hw_interrupt_disable();
        /* insert to defunct thread list */
        rt_thread_defunct_enqueue(thread);
        /* enable interrupt */
        rt_hw_interrupt_enable(lock);
    }
T
tangyuxin 已提交
406

407
    return RT_EOK;
408
}
409 410
RTM_EXPORT(rt_thread_detach);

411
#ifdef RT_USING_HEAP
412
/**
413 414 415 416 417 418
 * @brief   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.
419
 *
420
 * @param   parameter the parameter of thread enter function.
421
 *
422 423 424 425 426 427 428
 * @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.
429 430
 */
rt_thread_t rt_thread_create(const char *name,
431 432 433 434 435
                             void (*entry)(void *parameter),
                             void       *parameter,
                             rt_uint32_t stack_size,
                             rt_uint8_t  priority,
                             rt_uint32_t tick)
436
{
437 438 439 440 441 442 443 444
    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 已提交
445
    stack_start = (void *)RT_KERNEL_MALLOC(stack_size);
446 447 448 449 450 451 452 453
    if (stack_start == RT_NULL)
    {
        /* allocate stack failure */
        rt_object_delete((rt_object_t)thread);

        return RT_NULL;
    }

mysterywolf's avatar
mysterywolf 已提交
454
    _thread_init(thread,
455 456 457 458 459 460 461 462 463
                    name,
                    entry,
                    parameter,
                    stack_start,
                    stack_size,
                    priority,
                    tick);

    return thread;
464
}
465
RTM_EXPORT(rt_thread_create);
466

467
/**
468 469
 * @brief   This function will delete a thread. The thread object will be removed from
 *          thread queue and deleted from system object management in the idle thread.
470
 *
471
 * @param   thread the thread to be deleted.
472
 *
473 474
 * @return  Return the operation status. When the return value is RT_EOK, the function is successfully executed.
 *          When the return value is any other values, it means this operation failed.
475
 */
D
dzzxzz 已提交
476
rt_err_t rt_thread_delete(rt_thread_t thread)
477
{
478
    rt_base_t lock;
479

480 481
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
482 483
    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);
484

C
cliff-cmc 已提交
485
    if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE)
486 487
        return RT_EOK;

B
bernard 已提交
488
    if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT)
489 490 491 492
    {
        /* remove from schedule */
        rt_schedule_remove_thread(thread);
    }
493

mysterywolf's avatar
mysterywolf 已提交
494
    _thread_cleanup_execute(thread);
495

496 497
    /* release thread timer */
    rt_timer_detach(&(thread->thread_timer));
498

499 500
    /* disable interrupt */
    lock = rt_hw_interrupt_disable();
501

502 503 504
    /* change stat */
    thread->stat = RT_THREAD_CLOSE;

505
    /* insert to defunct thread list */
F
fenghuijie 已提交
506
    rt_thread_defunct_enqueue(thread);
507

508 509
    /* enable interrupt */
    rt_hw_interrupt_enable(lock);
510

511
    return RT_EOK;
512
}
513
RTM_EXPORT(rt_thread_delete);
514
#endif /* RT_USING_HEAP */
515 516

/**
517 518 519
 * @brief 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.
520
 *
521 522
 * @return  Return the operation status. When the return value is RT_EOK, the function is successfully executed.
 *          When the return value is any other values, it means this operation failed.
523
 */
D
dzzxzz 已提交
524
rt_err_t rt_thread_yield(void)
525
{
526 527 528 529 530 531 532
    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 已提交
533
    rt_schedule();
534
    rt_hw_interrupt_enable(lock);
535

536
    return RT_EOK;
537
}
538
RTM_EXPORT(rt_thread_yield);
539 540

/**
541 542
 * @brief   This function will let current thread sleep for some ticks. Change current thread state to suspend,
 *          when the thread timer reaches the tick value, scheduler will awaken this thread.
543
 *
544
 * @param   tick the sleep ticks.
545
 *
546 547
 * @return  Return the operation status. When the return value is RT_EOK, the function is successfully executed.
 *          When the return value is any other values, it means this operation failed.
548
 */
D
dzzxzz 已提交
549
rt_err_t rt_thread_sleep(rt_tick_t tick)
550
{
551 552
    register rt_base_t temp;
    struct rt_thread *thread;
553

554
    /* set to current thread */
S
shaojinchun 已提交
555
    thread = rt_thread_self();
556
    RT_ASSERT(thread != RT_NULL);
557
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
558

S
shaojinchun 已提交
559 560 561
    /* disable interrupt */
    temp = rt_hw_interrupt_disable();

562 563
    /* suspend thread */
    rt_thread_suspend(thread);
564

565 566 567
    /* 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));
568

569 570
    /* enable interrupt */
    rt_hw_interrupt_enable(temp);
571

572
    rt_schedule();
573

574 575 576
    /* clear error number of this thread to RT_EOK */
    if (thread->error == -RT_ETIMEOUT)
        thread->error = RT_EOK;
577

578
    return RT_EOK;
579 580 581
}

/**
582
 * @brief   This function will let current thread delay for some ticks.
583
 *
584
 * @param   tick the delay ticks.
585
 *
586 587
 * @return  Return the operation status. When the return value is RT_EOK, the function is successfully executed.
 *          When the return value is any other values, it means this operation failed.
588 589 590
 */
rt_err_t rt_thread_delay(rt_tick_t tick)
{
591
    return rt_thread_sleep(tick);
592
}
593
RTM_EXPORT(rt_thread_delay);
594

595
/**
596
 * @brief   This function will let current thread delay until (*tick + inc_tick).
597
 *
598
 * @param   tick the tick of last wakeup.
599
 *
600 601 602 603
 * @param   inc_tick the increment tick.
 *
 * @return  Return the operation status. When the return value is RT_EOK, the function is successfully executed.
 *          When the return value is any other values, it means this operation failed.
604
 */
B
Bernard Xiong 已提交
605
rt_err_t rt_thread_delay_until(rt_tick_t *tick, rt_tick_t inc_tick)
606 607 608
{
    register rt_base_t level;
    struct rt_thread *thread;
609
    rt_tick_t cur_tick;
610

B
Bernard Xiong 已提交
611 612
    RT_ASSERT(tick != RT_NULL);

613 614 615 616 617 618 619 620
    /* 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();

621
    cur_tick = rt_tick_get();
622
    if (cur_tick - *tick < inc_tick)
623
    {
624 625 626 627
        rt_tick_t left_tick;

        *tick += inc_tick;
        left_tick = *tick - cur_tick;
628 629 630 631 632

        /* suspend thread */
        rt_thread_suspend(thread);

        /* reset the timeout of thread timer and start it */
633
        rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &left_tick);
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648
        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
    {
649
        *tick = cur_tick;
650 651 652 653 654
        rt_hw_interrupt_enable(level);
    }

    return RT_EOK;
}
655
RTM_EXPORT(rt_thread_delay_until);
656

H
heyuanjie 已提交
657
/**
658
 * @brief   This function will let current thread delay for some milliseconds.
H
heyuanjie 已提交
659
 *
660
 * @param   ms the delay ms time.
H
heyuanjie 已提交
661
 *
662 663
 * @return  Return the operation status. When the return value is RT_EOK, the function is successfully executed.
 *          When the return value is any other values, it means this operation failed.
H
heyuanjie 已提交
664 665 666 667 668 669 670 671 672 673 674
 */
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 已提交
675
/**
676 677 678 679 680
 * @brief   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.
B
bernard.xiong@gmail.com 已提交
681
 *
682
 *              RT_THREAD_CTRL_CHANGE_PRIORITY for changing priority level of thread.
B
bernard.xiong@gmail.com 已提交
683
 *
684 685 686 687 688 689 690 691 692 693
 *              RT_THREAD_CTRL_STARTUP for starting a thread.
 *
 *              RT_THREAD_CTRL_CLOSE for delete a thread.
 *
 *              RT_THREAD_CTRL_BIND_CPU for bind the thread to a CPU.
 *
 * @param   arg the argument of control command.
 *
 * @return  Return the operation status. When the return value is RT_EOK, the function is successfully executed.
 *          When the return value is any other values, it means this operation failed.
B
bernard.xiong@gmail.com 已提交
694
 */
B
bernard 已提交
695
rt_err_t rt_thread_control(rt_thread_t thread, int cmd, void *arg)
696
{
697
    register rt_base_t temp;
698

699 700
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
701
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
702

703 704
    switch (cmd)
    {
705
        case RT_THREAD_CTRL_CHANGE_PRIORITY:
706
        {
707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725
            /* 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;
726
    #endif /* RT_THREAD_PRIORITY_MAX > 32 */
727 728 729 730 731 732 733 734 735 736 737 738 739 740 741

                /* 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;
742
    #endif /* RT_THREAD_PRIORITY_MAX > 32 */
743 744 745 746 747
            }

            /* enable interrupt */
            rt_hw_interrupt_enable(temp);
            break;
748
        }
749

750 751 752
        case RT_THREAD_CTRL_STARTUP:
        {
            return rt_thread_startup(thread);
753
        }
754

755
        case RT_THREAD_CTRL_CLOSE:
756
        {
757 758 759 760 761 762 763 764 765 766 767
            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);
            }
768
    #endif /* RT_USING_HEAP */
769 770
            rt_schedule();
            return rt_err;
771
        }
772 773 774

    #ifdef RT_USING_SMP
        case RT_THREAD_CTRL_BIND_CPU:
775
        {
776
            rt_uint8_t cpu;
777

778 779 780 781 782
            if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT)
            {
                /* we only support bind cpu before started phase. */
                return RT_ERROR;
            }
S
shaojinchun 已提交
783

784 785 786
            cpu = (rt_uint8_t)(size_t)arg;
            thread->bind_cpu = cpu > RT_CPUS_NR? RT_CPUS_NR : cpu;
            break;
S
shaojinchun 已提交
787
        }
788
    #endif /* RT_USING_SMP */
S
shaojinchun 已提交
789

790 791
        default:
            break;
792
    }
793

794
    return RT_EOK;
795
}
796
RTM_EXPORT(rt_thread_control);
797 798

/**
799
 * @brief   This function will suspend the specified thread and change it to suspend state.
800
 *
801 802
 * @note    if suspend self thread, after this function call, the
 *          rt_schedule() must be invoked.
803
 *
804
 * @param   thread the thread to be suspended.
805
 *
806 807
 * @return  Return the operation status. When the return value is RT_EOK, the function is successfully executed.
 *          When the return value is any other values, it means this operation failed.
808
 */
D
dzzxzz 已提交
809
rt_err_t rt_thread_suspend(rt_thread_t thread)
810
{
811
    register rt_base_t stat;
812
    register rt_base_t temp;
813

814 815
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
816
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
817

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

820 821
    stat = thread->stat & RT_THREAD_STAT_MASK;
    if ((stat != RT_THREAD_READY) && (stat != RT_THREAD_RUNNING))
822
    {
823
        RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend: thread disorder, 0x%2x\n",
824
                                       thread->stat));
825 826
        return -RT_ERROR;
    }
827

828 829
    /* disable interrupt */
    temp = rt_hw_interrupt_disable();
830 831 832 833 834
    if (stat == RT_THREAD_RUNNING)
    {
        /* not suspend running status thread on other core */
        RT_ASSERT(thread == rt_thread_self());
    }
835

836 837
    /* change thread stat */
    rt_schedule_remove_thread(thread);
838
    thread->stat = RT_THREAD_SUSPEND | (thread->stat & ~RT_THREAD_STAT_MASK);
839

840 841 842
    /* stop thread timer anyway */
    rt_timer_stop(&(thread->thread_timer));

843 844
    /* enable interrupt */
    rt_hw_interrupt_enable(temp);
845

846
    RT_OBJECT_HOOK_CALL(rt_thread_suspend_hook, (thread));
847
    return RT_EOK;
848
}
849
RTM_EXPORT(rt_thread_suspend);
850 851

/**
852
 * @brief   This function will resume a thread and put it to system ready queue.
853
 *
854
 * @param   thread the thread to be resumed.
855
 *
856 857
 * @return  Return the operation status. When the return value is RT_EOK, the function is successfully executed.
 *          When the return value is any other values, it means this operation failed.
858
 */
D
dzzxzz 已提交
859
rt_err_t rt_thread_resume(rt_thread_t thread)
860
{
861
    register rt_base_t temp;
862

863 864
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
865
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
866

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

B
bernard 已提交
869
    if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_SUSPEND)
870 871
    {
        RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume: thread disorder, %d\n",
872
                                       thread->stat));
873

874 875
        return -RT_ERROR;
    }
876

877 878
    /* disable interrupt */
    temp = rt_hw_interrupt_disable();
879

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

883
    rt_timer_stop(&thread->thread_timer);
884

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

F
fenghuijie 已提交
888 889 890
    /* enable interrupt */
    rt_hw_interrupt_enable(temp);

891
    RT_OBJECT_HOOK_CALL(rt_thread_resume_hook, (thread));
892
    return RT_EOK;
893
}
894
RTM_EXPORT(rt_thread_resume);
895 896

/**
897 898
 * @brief   This function is the timeout function for thread, normally which is invoked
 *          when thread is timeout to wait some resource.
899
 *
900
 * @param   parameter the parameter of thread timeout function
901
 */
D
dzzxzz 已提交
902
void rt_thread_timeout(void *parameter)
903
{
904
    struct rt_thread *thread;
F
fenghuijie 已提交
905
    register rt_base_t temp;
906

907
    thread = (struct rt_thread *)parameter;
908

909 910
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
B
bernard 已提交
911
    RT_ASSERT((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND);
912
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
913

F
fenghuijie 已提交
914 915 916
    /* disable interrupt */
    temp = rt_hw_interrupt_disable();

917 918
    /* set error number */
    thread->error = -RT_ETIMEOUT;
919

920 921
    /* remove from suspend list */
    rt_list_remove(&(thread->tlist));
922

923 924
    /* insert to schedule ready list */
    rt_schedule_insert_thread(thread);
925

F
fenghuijie 已提交
926 927 928
    /* enable interrupt */
    rt_hw_interrupt_enable(temp);

929 930
    /* do schedule */
    rt_schedule();
931
}
932
RTM_EXPORT(rt_thread_timeout);
933 934

/**
935
 * @brief   This function will find the specified thread.
936
 *
937
 * @note    please don't invoke this function in interrupt status.
938
 *
939
 * @param   name the name of thread finding.
B
bernard.xiong@gmail.com 已提交
940
 *
941
 * @return  the found thread.
942
 */
D
dzzxzz 已提交
943
rt_thread_t rt_thread_find(char *name)
944
{
945
    return (rt_thread_t)rt_object_find(name, RT_Object_Class_Thread);
946
}
947

948
RTM_EXPORT(rt_thread_find);
949

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