thread.c 28.0 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
 *
L
liukangcc 已提交
43
 * @note    The hook function must be simple and never be blocked or suspend.
44
 *
L
liukangcc 已提交
45
 * @param   hook is 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
 *
L
liukangcc 已提交
55
 * @note    The hook function must be simple and never be blocked or suspend.
56
 *
L
liukangcc 已提交
57
 * @param   hook is 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
 *
L
liukangcc 已提交
67
 * @param   hook is 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

/**
L
liukangcc 已提交
243
 * @brief   This function will initialize a thread. It's used to initialize a
244 245
 *          static thread object.
 *
L
liukangcc 已提交
246
 * @param   thread is the static thread object.
247
 *
L
liukangcc 已提交
248
 * @param   name is the name of thread, which shall be unique.
249
 *
L
liukangcc 已提交
250
 * @param   entry is the entry function of thread.
251
 *
L
liukangcc 已提交
252
 * @param   parameter is the parameter of thread enter function.
253
 *
L
liukangcc 已提交
254
 * @param   stack_start is the start address of thread stack.
255
 *
L
liukangcc 已提交
256
 * @param   stack_size is the size of thread stack.
257
 *
L
liukangcc 已提交
258
 * @param   priority is the priority of thread.
259
 *
L
liukangcc 已提交
260
 * @param   tick is the time slice if there are same priority thread.
261
 *
L
liukangcc 已提交
262 263
 * @return  Return the operation status. If the return value is RT_EOK, the function is successfully executed.
 *          If 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
 *
L
liukangcc 已提交
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
 *
L
liukangcc 已提交
318
 * @param   thread is the thread to be started.
319
 *
L
liukangcc 已提交
320 321
 * @return  Return the operation status. If the return value is RT_EOK, the function is successfully executed.
 *          If 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
 * @brief   This function will detach a thread. The thread object will be removed from
L
liukangcc 已提交
360
 *          thread queue and detached/deleted from the system object management.
361
 *
L
liukangcc 已提交
362
 * @param   thread is the thread to be deleted.
363
 *
L
liukangcc 已提交
364 365
 * @return  Return the operation status. If the return value is RT_EOK, the function is successfully executed.
 *          If 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
 * @brief   This function will create a thread object and allocate thread object memory.
 *          and stack.
 *
L
liukangcc 已提交
416
 * @param   name is the name of thread, which shall be unique.
417
 *
L
liukangcc 已提交
418
 * @param   entry is the entry function of thread.
419
 *
L
liukangcc 已提交
420
 * @param   parameter is the parameter of thread enter function.
421
 *
L
liukangcc 已提交
422
 * @param   stack_size is the size of thread stack.
423
 *
L
liukangcc 已提交
424
 * @param   priority is the priority of thread.
425
 *
L
liukangcc 已提交
426
 * @param   tick is the time slice if there are same priority thread.
427
 *
L
liukangcc 已提交
428 429
 * @return  If the return value is a rt_thread structure pointer, the function is successfully executed.
 *          If the return value is RT_NULL, it means this operation failed.
430 431
 */
rt_thread_t rt_thread_create(const char *name,
432 433 434 435 436
                             void (*entry)(void *parameter),
                             void       *parameter,
                             rt_uint32_t stack_size,
                             rt_uint8_t  priority,
                             rt_uint32_t tick)
437
{
438 439 440 441 442 443 444 445
    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 已提交
446
    stack_start = (void *)RT_KERNEL_MALLOC(stack_size);
447 448 449 450 451 452 453 454
    if (stack_start == RT_NULL)
    {
        /* allocate stack failure */
        rt_object_delete((rt_object_t)thread);

        return RT_NULL;
    }

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

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

468
/**
469 470
 * @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.
471
 *
L
liukangcc 已提交
472
 * @param   thread is the thread to be deleted.
473
 *
L
liukangcc 已提交
474 475
 * @return  Return the operation status. If the return value is RT_EOK, the function is successfully executed.
 *          If the return value is any other values, it means this operation failed.
476
 */
D
dzzxzz 已提交
477
rt_err_t rt_thread_delete(rt_thread_t thread)
478
{
479
    rt_base_t lock;
480

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

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

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

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

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

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

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

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

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

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

/**
L
liukangcc 已提交
518 519 520
 * @brief   This function will let current thread yield processor, and scheduler will
 *          choose the highest thread to run. After yield processor, the current thread
 *          is still in READY state.
521
 *
L
liukangcc 已提交
522 523
 * @return  Return the operation status. If the return value is RT_EOK, the function is successfully executed.
 *          If the return value is any other values, it means this operation failed.
524
 */
D
dzzxzz 已提交
525
rt_err_t rt_thread_yield(void)
526
{
527 528 529 530 531 532 533
    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 已提交
534
    rt_schedule();
535
    rt_hw_interrupt_enable(lock);
536

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

/**
542 543
 * @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.
544
 *
L
liukangcc 已提交
545
 * @param   tick is the sleep ticks.
546
 *
L
liukangcc 已提交
547 548
 * @return  Return the operation status. If the return value is RT_EOK, the function is successfully executed.
 *          If the return value is any other values, it means this operation failed.
549
 */
D
dzzxzz 已提交
550
rt_err_t rt_thread_sleep(rt_tick_t tick)
551
{
552 553
    register rt_base_t temp;
    struct rt_thread *thread;
554

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

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

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

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

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

573
    rt_schedule();
574

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

579
    return RT_EOK;
580 581 582
}

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

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

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

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

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

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

        /* suspend thread */
        rt_thread_suspend(thread);

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

    return RT_EOK;
}
656
RTM_EXPORT(rt_thread_delay_until);
657

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

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

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

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

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

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

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

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

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

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

791 792
        default:
            break;
793
    }
794

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

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

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

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

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

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

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

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

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

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

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

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

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

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

875 876
        return -RT_ERROR;
    }
877

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

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

884
    rt_timer_stop(&thread->thread_timer);
885

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

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

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

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

908
    thread = (struct rt_thread *)parameter;
909

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

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

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

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

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

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

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

/**
936
 * @brief   This function will find the specified thread.
937
 *
L
liukangcc 已提交
938
 * @note    Please don't invoke this function in interrupt status.
939
 *
L
liukangcc 已提交
940
 * @param   name is the name of thread finding.
B
bernard.xiong@gmail.com 已提交
941
 *
L
liukangcc 已提交
942 943
 * @return  If the return value is a rt_thread structure pointer, the function is successfully executed.
 *          If the return value is RT_NULL, it means this operation failed.
944
 */
D
dzzxzz 已提交
945
rt_thread_t rt_thread_find(char *name)
946
{
947
    return (rt_thread_t)rt_object_find(name, RT_Object_Class_Thread);
948
}
949

950
RTM_EXPORT(rt_thread_find);
951

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