From 7018ab0661e5a5c4be00283a5ab9eabc5d3ab0ee Mon Sep 17 00:00:00 2001 From: "bernard.xiong" Date: Fri, 12 Nov 2010 10:16:33 +0000 Subject: [PATCH] add cleanup callback function on thread exit; add IPC object reset command. git-svn-id: https://rt-thread.googlecode.com/svn/trunk@1043 bbd45198-f89e-11dd-88c7-29a3b14d5316 --- include/rtdef.h | 26 ++++++----- src/idle.c | 18 +++++-- src/ipc.c | 121 ++++++++++++++++++++++++++++++++++++++++++++---- src/thread.c | 22 ++++++++- 4 files changed, 160 insertions(+), 27 deletions(-) diff --git a/include/rtdef.h b/include/rtdef.h index 0f814ff2f3..cd448f5424 100644 --- a/include/rtdef.h +++ b/include/rtdef.h @@ -10,8 +10,9 @@ * Change Logs: * Date Author Notes * 2007-01-10 Bernard the first version - * 2008-07-12 Bernard remove all rt_int8, rt_uint32_t etc typedef + * 2008-07-12 Bernard remove all rt_int8, rt_uint32_t etc typedef * 2010-10-26 yi.qiu add module support + * 2010-11-10 Bernard add cleanup callback function in thread exit. */ #ifndef __RT_DEF_H__ #define __RT_DEF_H__ @@ -301,14 +302,12 @@ typedef struct rt_timer* rt_timer_t; */ /* thread state definitions */ -#define RT_THREAD_RUNNING 0x0 /* Running. */ -#define RT_THREAD_READY 0x1 /* Ready. */ -#define RT_THREAD_SUSPEND 0x2 /* Suspend. */ -#define RT_THREAD_BLOCK RT_THREAD_SUSPEND /* Blocked. */ -#define RT_THREAD_CLOSE 0x3 /* Closed. */ -#define RT_THREAD_INIT RT_THREAD_CLOSE /* Inited. */ - -#define RT_THREAD_FLAGS_TIMERSLICE 0x01 +#define RT_THREAD_INIT 0x00 /* Inited. */ +#define RT_THREAD_READY 0x01 /* Ready. */ +#define RT_THREAD_SUSPEND 0x02 /* Suspend. */ +#define RT_THREAD_RUNNING 0x03 /* Running. */ +#define RT_THREAD_BLOCK RT_THREAD_SUSPEND /* Blocked. */ +#define RT_THREAD_CLOSE 0x04 /* Closed. */ #define RT_THREAD_CTRL_STARTUP 0x00 /* Starup thread. */ #define RT_THREAD_CTRL_CLOSE 0x01 /* Close thread. */ @@ -328,7 +327,7 @@ struct rt_thread rt_uint8_t flags; /* thread's flags */ #ifdef RT_USING_MODULE - void* module_id; /* id of application module */ + void* module_id; /* id of application module */ #endif rt_list_t list; /* the object list */ @@ -366,6 +365,8 @@ struct rt_thread struct rt_timer thread_timer; /* thread timer */ + void (*cleanup)(struct rt_thread* tid); /* cleanup function when thread exit */ + rt_uint32_t user_data; /* user data */ }; /*@}*/ @@ -407,6 +408,9 @@ typedef struct rt_module* rt_module_t; #define RT_IPC_FLAG_FIFO 0x00 /* FIFOed IPC. @ref IPC. */ #define RT_IPC_FLAG_PRIO 0x01 /* PRIOed IPC. @ref IPC. */ +#define RT_IPC_CMD_UNKNOWN 0x00 /* unknown IPC command */ +#define RT_IPC_CMD_RESET 0x01 /* reset IPC object */ + #define RT_WAITING_FOREVER -1 /* Block forever until get resource. */ #define RT_WAITING_NO 0 /* Non-block. */ @@ -443,7 +447,7 @@ struct rt_mutex { struct rt_ipc_object parent; - rt_uint8_t value; /* value of mutex. */ + rt_uint16_t value; /* value of mutex. */ rt_uint8_t original_priority; /* priority of last thread hold the mutex. */ rt_uint8_t hold; /* numbers of thread hold the mutex. */ diff --git a/src/idle.c b/src/idle.c index a0a87677e2..82ed7cec49 100644 --- a/src/idle.c +++ b/src/idle.c @@ -10,6 +10,7 @@ * Change Logs: * Date Author Notes * 2006-03-23 Bernard the first version + * 2010-11-10 Bernard add cleanup callback function in thread exit. */ #include @@ -74,20 +75,29 @@ void rt_thread_idle_excute(void) { /* get defunct thread */ thread = rt_list_entry(rt_thread_defunct.next, struct rt_thread, tlist); - #ifdef RT_USING_MODULE /* get thread's parent module */ module = (rt_module_t)thread->module_id; /* if the thread is module's main thread */ - if(module->module_thread == thread) + if(module != RT_NULL && module->module_thread == thread) { /* detach module's main thread */ module->module_thread = RT_NULL; - } + } #endif /* remove defunct thread */ rt_list_remove(&(thread->tlist)); + /* invoke thread cleanup */ + if (thread->cleanup != RT_NULL) thread->cleanup(thread); + + /* if it's a system object, not delete it */ + if (rt_object_is_systemobject((rt_object_t)thread) == RT_EOK) + { + /* enable interrupt */ + rt_hw_interrupt_enable(lock); + return; + } } else { @@ -109,7 +119,6 @@ void rt_thread_idle_excute(void) #endif /* release thread's stack */ rt_free(thread->stack_addr); - /* delete thread object */ rt_object_delete((rt_object_t)thread); @@ -126,7 +135,6 @@ void rt_thread_idle_excute(void) } #endif //RT_USING_MODULE } - #endif //RT_USING_HEAP } diff --git a/src/ipc.c b/src/ipc.c index 96b11410c1..15a2f99b2f 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -33,6 +33,7 @@ * 2010-01-20 mbbill remove rt_ipc_object_decrease function. * 2010-04-20 Bernard move memcpy outside interrupt disable in mq * 2010-10-26 yi.qiu add module support in rt_mp_delete and rt_mq_delete + * 2010-11-10 Bernard add IPC reset command implementation. */ #include @@ -448,7 +449,27 @@ rt_err_t rt_sem_release(rt_sem_t sem) */ rt_err_t rt_sem_control(rt_sem_t sem, rt_uint8_t cmd, void* arg) { - return RT_EOK; + rt_ubase_t level; + RT_ASSERT(sem != RT_NULL); + + if (cmd == RT_IPC_CMD_RESET) + { + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + /* resume all waiting thread */ + rt_ipc_object_resume_all(&sem->parent); + + /* set new value */ + sem->value = (rt_uint16_t)arg; + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + return RT_EOK; + } + + return -RT_ERROR; } #endif /* end of RT_USING_SEMAPHORE */ @@ -738,20 +759,20 @@ rt_err_t rt_mutex_release(rt_mutex_t mutex) if (mutex->hold == 0) { /* change the owner thread to original priority */ - if (mutex->owner->init_priority != mutex->owner->current_priority) + if (mutex->original_priority != mutex->owner->current_priority) { rt_thread_control(mutex->owner, RT_THREAD_CTRL_CHANGE_PRIORITY, - &(mutex->owner->init_priority)); + &(mutex->original_priority)); } /* wakeup suspended thread */ if( !rt_list_isempty(&mutex->parent.suspend_thread) ) { - /* get thread entry */ + /* get suspended thread */ thread = rt_list_entry(mutex->parent.suspend_thread.next, struct rt_thread, tlist); #ifdef RT_IPC_DEBUG - rt_kprintf("mutex_release: resume thread: %s\n", thread->name); + rt_kprintf("mutex_release: resume thread: %s\n", thread->name); #endif /* set new owner and priority */ mutex->owner = thread; @@ -770,7 +791,7 @@ rt_err_t rt_mutex_release(rt_mutex_t mutex) /* clear owner */ mutex->owner = RT_NULL; - mutex->original_priority = 0; + mutex->original_priority = 0xff; } } @@ -794,7 +815,7 @@ rt_err_t rt_mutex_release(rt_mutex_t mutex) */ rt_err_t rt_mutex_control(rt_mutex_t mutex, rt_uint8_t cmd, void* arg) { - return RT_EOK; + return -RT_ERROR; } #endif /* end of RT_USING_MUTEX */ @@ -1110,7 +1131,27 @@ rt_err_t rt_event_recv(rt_event_t event, rt_uint32_t set, rt_uint8_t option, rt_ */ rt_err_t rt_event_control (rt_event_t event, rt_uint8_t cmd, void* arg) { - return RT_EOK; + rt_ubase_t level; + RT_ASSERT(event != RT_NULL); + + if (cmd == RT_IPC_CMD_RESET) + { + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + /* resume all waiting thread */ + rt_ipc_object_resume_all(&event->parent); + + /* init event set */ + event->set = 0; + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + return RT_EOK; + } + + return -RT_ERROR; } #endif /* end of RT_USING_EVENT */ @@ -1422,7 +1463,29 @@ rt_err_t rt_mb_recv (rt_mailbox_t mb, rt_uint32_t* value, rt_int32_t timeout) */ rt_err_t rt_mb_control(rt_mailbox_t mb, rt_uint8_t cmd, void* arg) { - return RT_EOK; + rt_ubase_t level; + RT_ASSERT(mb != RT_NULL); + + if (cmd == RT_IPC_CMD_RESET) + { + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + /* resume all waiting thread */ + rt_ipc_object_resume_all(&mb->parent); + + /* re-init mailbox */ + mb->entry = 0; + mb->in_offset = 0; + mb->out_offset = 0; + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + return RT_EOK; + } + + return -RT_ERROR; } #endif /* end of RT_USING_MAILBOX */ @@ -1894,7 +1957,45 @@ rt_err_t rt_mq_recv (rt_mq_t mq, void* buffer, rt_size_t size, rt_int32_t timeou */ rt_err_t rt_mq_control(rt_mq_t mq, rt_uint8_t cmd, void* arg) { - return RT_EOK; + rt_ubase_t level; + struct rt_mq_message *msg; + + RT_ASSERT(mq != RT_NULL); + + if (cmd == RT_IPC_CMD_RESET) + { + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + /* resume all waiting thread */ + rt_ipc_object_resume_all(&mq->parent); + + /* release all message in the queue */ + while (mq->msg_queue_head != RT_NULL) + { + /* get message from queue */ + msg = (struct rt_mq_message*) mq->msg_queue_head; + + /* move message queue head */ + mq->msg_queue_head = msg->next; + /* reach queue tail, set to NULL */ + if (mq->msg_queue_tail == msg) mq->msg_queue_tail = RT_NULL; + + /* put message to free list */ + msg->next = (struct rt_mq_message*)mq->msg_queue_free; + mq->msg_queue_free = msg; + } + + /* clean entry */ + mq->entry = 0; + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + return RT_EOK; + } + + return -RT_ERROR; } #endif /* end of RT_USING_MESSAGEQUEUE */ diff --git a/src/thread.c b/src/thread.c index 05eb403b56..32471bad3f 100644 --- a/src/thread.c +++ b/src/thread.c @@ -19,6 +19,7 @@ * 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 @@ -240,7 +241,8 @@ static void rt_thread_exit() /* enable interrupt */ rt_hw_interrupt_enable(temp); - if (rt_object_is_systemobject((rt_object_t)thread) == RT_EOK) + if ((rt_object_is_systemobject((rt_object_t)thread) == RT_EOK) && + thread->cleanup == RT_NULL) { rt_object_detach((rt_object_t)thread); } @@ -273,6 +275,8 @@ static void rt_thread_exit() */ rt_err_t rt_thread_detach (rt_thread_t thread) { + rt_base_t lock; + /* thread check */ RT_ASSERT(thread != RT_NULL); @@ -282,8 +286,24 @@ rt_err_t rt_thread_detach (rt_thread_t 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; }