123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686 |
- /*
- * File : thread.c
- * This file is part of RT-Thread RTOS
- * COPYRIGHT (C) 2006 - 2010, RT-Thread Development Team
- *
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rt-thread.org/license/LICENSE
- *
- * Change Logs:
- * Date Author Notes
- * 2006-03-28 Bernard first version
- * 2006-04-29 Bernard implement thread timer
- * 2006-04-30 Bernard add THREAD_DEBUG
- * 2006-05-27 Bernard fix the rt_thread_yield bug
- * 2006-06-03 Bernard fix the thread timer init bug
- * 2006-08-10 Bernard fix the timer bug in thread_sleep
- * 2006-09-03 Bernard change rt_timer_delete to rt_timer_detach
- * 2006-09-03 Bernard implement rt_thread_detach
- * 2008-02-16 Bernard fix the rt_thread_timeout bug
- * 2010-03-21 Bernard change the errno of rt_thread_delay/sleep to RT_EOK.
- * 2010-11-10 Bernard add cleanup callback function in thread exit.
- */
- #include <rtthread.h>
- #include <rthw.h>
- #include "kservice.h"
- /*#define THREAD_DEBUG */
- extern rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];
- extern struct rt_thread* rt_current_thread;
- extern rt_uint8_t rt_current_priority;
- extern rt_list_t rt_thread_defunct;
- static void rt_thread_exit(void);
- void rt_thread_timeout(void* parameter);
- static rt_err_t _rt_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)
- {
- /* init thread list */
- rt_list_init(&(thread->tlist));
- thread->entry = (void*)entry;
- thread->parameter = parameter;
- /* stack init */
- thread->stack_addr = stack_start;
- thread->stack_size = stack_size;
- /* init thread stack */
- rt_memset(thread->stack_addr, '#', thread->stack_size);
- thread->sp = (void*)rt_hw_stack_init(thread->entry, thread->parameter,
- (void *) ((char *)thread->stack_addr + thread->stack_size - 4),
- (void*)rt_thread_exit);
- /* priority init */
- RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX);
- thread->init_priority = priority;
- thread->current_priority = priority;
- /* tick init */
- thread->init_tick = tick;
- thread->remaining_tick = tick;
- /* error and flags */
- thread->error = RT_EOK;
- thread->stat = RT_THREAD_INIT;
- /* initialize cleanup function and user data */
- thread->cleanup = 0;
- thread->user_data = 0;
- /* init thread timer */
- rt_timer_init(&(thread->thread_timer),
- thread->name,
- rt_thread_timeout,
- thread,
- 0,
- RT_TIMER_FLAG_ONE_SHOT);
- return RT_EOK;
- }
- /**
- * @addtogroup Thread
- */
- /*@{*/
- /**
- * 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 the operation status, RT_EOK on OK, -RT_ERROR on error
- *
- */
- rt_err_t rt_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)
- {
- /* thread check */
- RT_ASSERT(thread != RT_NULL);
- RT_ASSERT(stack_start != RT_NULL);
- /* init thread object */
- 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);
- }
- #ifdef RT_USING_HEAP
- /**
- * 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,
- void (*entry)(void* parameter), void* parameter,
- rt_uint32_t stack_size,
- rt_uint8_t priority,
- rt_uint32_t tick)
- {
- 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;
- stack_start = (void*)rt_malloc(stack_size);
- 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;
- }
- #endif
- /**
- * This function will return self thread object
- *
- * @return the self thread object
- *
- */
- rt_thread_t rt_thread_self (void)
- {
- return rt_current_thread;
- }
- /**
- * This function will start a thread and put it to system ready queue
- *
- * @param thread the thread to be started
- *
- * @return the operation status, RT_EOK on OK, -RT_ERROR on error
- *
- */
- rt_err_t rt_thread_startup (rt_thread_t thread)
- {
- /* thread check */
- RT_ASSERT(thread != RT_NULL);
- RT_ASSERT(thread->stat == RT_THREAD_INIT);
- /* set current priority to init priority */
- thread->current_priority = thread->init_priority;
- /* calculate priority attribute */
- #if RT_THREAD_PRIORITY_MAX > 32
- thread->number = thread->current_priority >> 3; /* 5bit */
- thread->number_mask = 1L << thread->number;
- thread->high_mask = 1L << (thread->current_priority & 0x07); /* 3bit */
- #else
- thread->number_mask = 1L << thread->current_priority; //1L means long int,fixed compile mistake with IAR EW M16C v3.401,fify 20100410
- #endif
- #ifdef THREAD_DEBUG
- rt_kprintf("startup a thread:%s with priority:%d\n", thread->name, thread->init_priority);
- #endif
- /* change thread stat */
- thread->stat = RT_THREAD_SUSPEND;
- /* then resume it */
- rt_thread_resume(thread);
- return RT_EOK;
- }
- static void rt_thread_exit()
- {
- struct rt_thread* thread;
- register rt_base_t temp;
- /* disable interrupt */
- temp = rt_hw_interrupt_disable();
- /* get current thread */
- thread = rt_current_thread;
- /* remove from schedule */
- rt_schedule_remove_thread(thread);
- /* change stat */
- thread->stat = RT_THREAD_CLOSE;
- /* release thread timer */
- rt_timer_detach(&(thread->thread_timer));
- /* enable interrupt */
- rt_hw_interrupt_enable(temp);
- if ((rt_object_is_systemobject((rt_object_t)thread) == RT_EOK) &&
- thread->cleanup == RT_NULL)
- {
- rt_object_detach((rt_object_t)thread);
- }
- #ifdef RT_USING_HEAP
- else
- {
- /* disable interrupt */
- temp = rt_hw_interrupt_disable();
- /* insert to defunct thread list */
- rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));
- /* enable interrupt */
- rt_hw_interrupt_enable(temp);
- }
- #endif
- /* switch to next task */
- rt_schedule();
- }
- /**
- * This function will detach a thread. The thread object will be removed from
- * thread queue and detached/deleted from system object management.
- *
- * @param thread the thread to be deleted
- *
- * @return the operation status, RT_EOK on OK, -RT_ERROR on error
- *
- */
- rt_err_t rt_thread_detach (rt_thread_t thread)
- {
- rt_base_t lock;
- /* thread check */
- RT_ASSERT(thread != RT_NULL);
- /* remove from schedule */
- rt_schedule_remove_thread(thread);
- /* release thread timer */
- rt_timer_detach(&(thread->thread_timer));
- /* change stat */
- thread->stat = RT_THREAD_CLOSE;
- /* detach object */
- rt_object_detach((rt_object_t)thread);
- if (thread->cleanup != RT_NULL)
- {
- /* disable interrupt */
- lock = rt_hw_interrupt_disable();
- /* insert to defunct thread list */
- rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));
- /* enable interrupt */
- rt_hw_interrupt_enable(lock);
- }
- return RT_EOK;
- }
- #ifdef RT_USING_HEAP
- /**
- * This function will delete a thread. The thread object will be removed from
- * thread queue and detached/deleted from system object management.
- *
- * @param thread the thread to be deleted
- *
- * @return the operation status, RT_EOK on OK, -RT_ERROR on error
- *
- */
- rt_err_t rt_thread_delete (rt_thread_t thread)
- {
- rt_base_t lock;
- /* thread check */
- RT_ASSERT(thread != RT_NULL);
- /* remove from schedule */
- rt_schedule_remove_thread(thread);
- /* release thread timer */
- rt_timer_detach(&(thread->thread_timer));
- /* change stat */
- thread->stat = RT_THREAD_CLOSE;
- /* disable interrupt */
- lock = rt_hw_interrupt_disable();
- /* insert to defunct thread list */
- rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));
- /* enable interrupt */
- rt_hw_interrupt_enable(lock);
- return RT_EOK;
- }
- #endif
- /**
- * 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.
- *
- * @return RT_EOK
- *
- */
- rt_err_t rt_thread_yield ()
- {
- register rt_base_t level;
- struct rt_thread *thread;
- /* disable interrupt */
- level = rt_hw_interrupt_disable();
- /* set to current thread */
- thread = rt_current_thread;
- /* if the thread stat is READY and on ready queue list */
- if (thread->stat == RT_THREAD_READY && thread->tlist.next != thread->tlist.prev)
- {
- /* remove thread from thread list */
- rt_list_remove(&(thread->tlist));
- /* put thread to end of ready queue */
- rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
- &(thread->tlist));
- /* enable interrupt */
- rt_hw_interrupt_enable(level);
- rt_schedule();
- return RT_EOK;
- }
- /* enable interrupt */
- rt_hw_interrupt_enable(level);
- return RT_EOK;
- }
- /**
- * This function will let current thread sleep for some ticks.
- *
- * @param tick the sleep ticks
- *
- * @return RT_EOK
- *
- */
- rt_err_t rt_thread_sleep (rt_tick_t tick)
- {
- register rt_base_t temp;
- struct rt_thread *thread;
- /* disable interrupt */
- temp = rt_hw_interrupt_disable();
- /* set to current thread */
- thread = rt_current_thread;
- RT_ASSERT(thread != RT_NULL);
- /* suspend thread */
- rt_thread_suspend(thread);
- /* reset the timeout of thread timer and start it */
- rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &tick);
- rt_timer_start(&(thread->thread_timer));
- /* enable interrupt */
- rt_hw_interrupt_enable(temp);
- rt_schedule();
- /* clear error number of this thread to RT_EOK */
- if (thread->error == -RT_ETIMEOUT)
- thread->error = RT_EOK;
- return RT_EOK;
- }
- /**
- * This function will let current thread delay for some ticks.
- *
- * @param tick the delay ticks
- *
- * @return RT_EOK
- *
- */
- rt_err_t rt_thread_delay(rt_tick_t tick)
- {
- return rt_thread_sleep(tick);
- }
- /**
- * 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
- * RT_THREAD_CTRL_CHANGE_PRIORITY for changing priority level of thread;
- * RT_THREAD_CTRL_STARTUP for starting a thread;
- * RT_THREAD_CTRL_CLOSE for delete a thread.
- * @param arg the argument of control command
- *
- * @return RT_EOK
- */
- rt_err_t rt_thread_control (rt_thread_t thread, rt_uint8_t cmd, void* arg)
- {
- register rt_base_t temp;
- /* thread check */
- RT_ASSERT(thread != RT_NULL);
- switch (cmd)
- {
- case RT_THREAD_CTRL_CHANGE_PRIORITY:
- /* disable interrupt */
- temp = rt_hw_interrupt_disable();
- /* for ready thread, change queue */
- if (thread->stat == 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;
- case RT_THREAD_CTRL_STARTUP:
- return rt_thread_startup(thread);
- #ifdef RT_USING_HEAP
- case RT_THREAD_CTRL_CLOSE:
- return rt_thread_delete(thread);
- #endif
- default:
- break;
- }
- return RT_EOK;
- }
- /**
- * This function will suspend the specified thread.
- *
- * @param thread the thread to be suspended
- *
- * @return the operation status, RT_EOK on OK, -RT_ERROR on error
- *
- * @note if suspend self thread, after this function call, the
- * rt_schedule() must be invoked.
- */
- rt_err_t rt_thread_suspend (rt_thread_t thread)
- {
- register rt_base_t temp;
- /* thread check */
- RT_ASSERT(thread != RT_NULL);
- #ifdef THREAD_DEBUG
- rt_kprintf("thread suspend: %s\n", thread->name);
- #endif
- if (thread->stat != RT_THREAD_READY)
- {
- #ifdef THREAD_DEBUG
- rt_kprintf("thread suspend: thread disorder, %d\n", thread->stat);
- #endif
- return -RT_ERROR;
- }
- /* disable interrupt */
- temp = rt_hw_interrupt_disable();
- /* change thread stat */
- thread->stat = RT_THREAD_SUSPEND;
- rt_schedule_remove_thread(thread);
- /* enable interrupt */
- rt_hw_interrupt_enable(temp);
- return RT_EOK;
- }
- /**
- * This function will resume a thread and put it to system ready queue.
- *
- * @param thread the thread to be resumed
- *
- * @return the operation status, RT_EOK on OK, -RT_ERROR on error
- *
- */
- rt_err_t rt_thread_resume (rt_thread_t thread)
- {
- register rt_base_t temp;
- /* thread check */
- RT_ASSERT(thread != RT_NULL);
- #ifdef THREAD_DEBUG
- rt_kprintf("thread resume: %s\n", thread->name);
- #endif
- if (thread->stat != RT_THREAD_SUSPEND)
- {
- #ifdef THREAD_DEBUG
- rt_kprintf("thread resume: thread disorder, %d\n", thread->stat);
- #endif
- return -RT_ERROR;
- }
- /* disable interrupt */
- temp = rt_hw_interrupt_disable();
- /* remove from suspend list */
- rt_list_remove(&(thread->tlist));
- /* remove thread timer */
- rt_list_remove(&(thread->thread_timer.list));
- /* change timer state */
- thread->thread_timer.parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
- /* enable interrupt */
- rt_hw_interrupt_enable(temp);
- /* insert to schedule ready list */
- rt_schedule_insert_thread(thread);
- return RT_EOK;
- }
- /**
- * This function is the timeout function for thread, normally which is invoked
- * when thread is timeout to wait some recourse.
- *
- * @param parameter the parameter of thread timeout function
- *
- */
- void rt_thread_timeout(void* parameter)
- {
- struct rt_thread* thread;
- thread = (struct rt_thread*) parameter;
- /* thread check */
- RT_ASSERT(thread != RT_NULL);
- RT_ASSERT(thread->stat == RT_THREAD_SUSPEND);
- /* set error number */
- thread->error = -RT_ETIMEOUT;
- /* remove from suspend list */
- rt_list_remove(&(thread->tlist));
- /* insert to schedule ready list */
- rt_schedule_insert_thread(thread);
- /* do schedule */
- rt_schedule();
- }
- /**
- * This function will find the specified thread.
- *
- * @param name the name of thread finding
- *
- * @return the found thread
- *
- * @note please don't invoke this function in interrupt status.
- */
- rt_thread_t rt_thread_find(char* name)
- {
- struct rt_object_information *information;
- struct rt_object* object;
- struct rt_list_node* node;
- extern struct rt_object_information rt_object_container[];
- /* enter critical */
- if (rt_thread_self() != RT_NULL)
- rt_enter_critical();
- /* try to find device object */
- information = &rt_object_container[RT_Object_Class_Thread];
- for (node = information->object_list.next; node != &(information->object_list); node = node->next)
- {
- object = rt_list_entry(node, struct rt_object, list);
- if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0)
- {
- /* leave critical */
- if (rt_thread_self() != RT_NULL)
- rt_exit_critical();
- return (rt_thread_t)object;
- }
- }
- /* leave critical */
- if (rt_thread_self() != RT_NULL)
- rt_exit_critical();
- /* not found */
- return RT_NULL;
- }
- /*@}*/
|