rt_inline rt_err_trt_ipc_list_suspend(rt_list_t*list,structrt_thread*thread,rt_uint8_t flag){/* suspend thread */rt_thread_suspend(thread);switch(flag){case RT_IPC_FLAG_FIFO:rt_list_insert_before(list,&(thread->tlist));break;case RT_IPC_FLAG_PRIO:{structrt_list_node*n;structrt_thread*sthread;/* find a suitable position */for(n = list->next; n != list; n = n->next){
sthread =rt_list_entry(n,structrt_thread, tlist);/* find out */if(thread->current_priority < sthread->current_priority){/* insert this thread before the sthread */rt_list_insert_before(&(sthread->tlist),&(thread->tlist));break;}}/*
* not found a suitable position,
* append to the end of suspend_thread list
*/if(n == list)rt_list_insert_before(list,&(thread->tlist));}break;}return RT_EOK;}
rt_err_trt_sem_take(rt_sem_t sem,rt_int32_t time){registerrt_base_t temp;structrt_thread*thread;/* parameter check */RT_ASSERT(sem != RT_NULL);RT_ASSERT(rt_object_get_type(&sem->parent.parent)== RT_Object_Class_Semaphore);RT_OBJECT_HOOK_CALL(rt_object_trytake_hook,(&(sem->parent.parent)));/* disable interrupt */
temp =rt_hw_interrupt_disable();RT_DEBUG_LOG(RT_DEBUG_IPC,("thread %s take sem:%s, which value is: %d\n",rt_thread_self()->name,((structrt_object*)sem)->name,
sem->value));if(sem->value >0){/* semaphore is available */
sem->value --;/* enable interrupt */rt_hw_interrupt_enable(temp);}else{/* no waiting, return with timeout */if(time ==0){rt_hw_interrupt_enable(temp);return-RT_ETIMEOUT;}else{/* current context checking */
RT_DEBUG_IN_THREAD_CONTEXT;/* semaphore is unavailable, push to suspend list *//* get current thread */
thread =rt_thread_self();/* reset thread error number */
thread->error = RT_EOK;RT_DEBUG_LOG(RT_DEBUG_IPC,("sem take: suspend thread - %s\n",
thread->name));/* suspend thread */rt_ipc_list_suspend(&(sem->parent.suspend_thread),
thread,
sem->parent.parent.flag);/* has waiting time, start thread timer */if(time >0){RT_DEBUG_LOG(RT_DEBUG_IPC,("set thread:%s to timer list\n",
thread->name));/* reset the timeout of thread timer and start it */rt_timer_control(&(thread->thread_timer),
RT_TIMER_CTRL_SET_TIME,&time);rt_timer_start(&(thread->thread_timer));}/* enable interrupt */rt_hw_interrupt_enable(temp);/* do schedule */rt_schedule();if(thread->error != RT_EOK){return thread->error;}}}RT_OBJECT_HOOK_CALL(rt_object_take_hook,(&(sem->parent.parent)));return RT_EOK;}
/**
* flag defintions in event
*/#defineRT_EVENT_FLAG_AND0x01/**< logic and */#defineRT_EVENT_FLAG_OR0x02/**< logic or */#defineRT_EVENT_FLAG_CLEAR0x04/**< clear flag */
rt_err_trt_event_send(rt_event_t event,rt_uint32_t set){structrt_list_node*n;structrt_thread*thread;registerrt_ubase_t level;registerrt_base_t status;rt_bool_t need_schedule;/* parameter check */RT_ASSERT(event != RT_NULL);RT_ASSERT(rt_object_get_type(&event->parent.parent)== RT_Object_Class_Event);if(set ==0)return-RT_ERROR;
need_schedule = RT_FALSE;/* disable interrupt */
level =rt_hw_interrupt_disable();/* set event */
event->set |= set;RT_OBJECT_HOOK_CALL(rt_object_put_hook,(&(event->parent.parent)));if(!rt_list_isempty(&event->parent.suspend_thread)){/* search thread list to resume thread */
n = event->parent.suspend_thread.next;while(n !=&(event->parent.suspend_thread)){/* get thread */
thread =rt_list_entry(n,structrt_thread, tlist);
status =-RT_ERROR;if(thread->event_info & RT_EVENT_FLAG_AND){if((thread->event_set & event->set)== thread->event_set){/* received an AND event */
status = RT_EOK;}}elseif(thread->event_info & RT_EVENT_FLAG_OR){if(thread->event_set & event->set){/* save recieved event set */
thread->event_set = thread->event_set & event->set;/* received an OR event */
status = RT_EOK;}}/* move node to the next */
n = n->next;/* condition is satisfied, resume thread */if(status == RT_EOK){/* clear event */if(thread->event_info & RT_EVENT_FLAG_CLEAR)
event->set &=~thread->event_set;/* resume thread, and thread list breaks out */rt_thread_resume(thread);/* need do a scheduling */
need_schedule = RT_TRUE;}}}/* enable interrupt */rt_hw_interrupt_enable(level);/* do a schedule */if(need_schedule == RT_TRUE)rt_schedule();return RT_EOK;}
rt_err_trt_event_recv(rt_event_t event,rt_uint32_t set,rt_uint8_t option,rt_int32_t timeout,rt_uint32_t*recved){structrt_thread*thread;registerrt_ubase_t level;registerrt_base_t status;
RT_DEBUG_IN_THREAD_CONTEXT;/* parameter check */RT_ASSERT(event != RT_NULL);RT_ASSERT(rt_object_get_type(&event->parent.parent)== RT_Object_Class_Event);if(set ==0)return-RT_ERROR;/* init status */
status =-RT_ERROR;/* get current thread */
thread =rt_thread_self();/* reset thread error */
thread->error = RT_EOK;RT_OBJECT_HOOK_CALL(rt_object_trytake_hook,(&(event->parent.parent)));/* disable interrupt */
level =rt_hw_interrupt_disable();/* check event set */if(option & RT_EVENT_FLAG_AND){if((event->set & set)== set)
status = RT_EOK;}elseif(option & RT_EVENT_FLAG_OR){if(event->set & set)
status = RT_EOK;}else{/* either RT_EVENT_FLAG_AND or RT_EVENT_FLAG_OR should be set */RT_ASSERT(0);}if(status == RT_EOK){/* set received event */if(recved)*recved =(event->set & set);/* received event */if(option & RT_EVENT_FLAG_CLEAR)
event->set &=~set;}elseif(timeout ==0){/* no waiting */
thread->error =-RT_ETIMEOUT;}else{/* fill thread event info */
thread->event_set = set;
thread->event_info = option;/* put thread to suspended thread list */rt_ipc_list_suspend(&(event->parent.suspend_thread),
thread,
event->parent.parent.flag);/* if there is a waiting timeout, active thread timer */if(timeout >0){/* reset the timeout of thread timer and start it */rt_timer_control(&(thread->thread_timer),
RT_TIMER_CTRL_SET_TIME,&timeout);rt_timer_start(&(thread->thread_timer));}/* enable interrupt */rt_hw_interrupt_enable(level);/* do a schedule */rt_schedule();if(thread->error != RT_EOK){/* return error */return thread->error;}/* received an event, disable interrupt to protect */
level =rt_hw_interrupt_disable();/* set received event */if(recved)*recved = thread->event_set;}/* enable interrupt */rt_hw_interrupt_enable(level);RT_OBJECT_HOOK_CALL(rt_object_take_hook,(&(event->parent.parent)));return thread->error;}
rt_err_trt_mq_send(rt_mq_t mq,void*buffer,rt_size_t size){registerrt_ubase_t temp;structrt_mq_message*msg;/* parameter check */RT_ASSERT(mq != RT_NULL);RT_ASSERT(rt_object_get_type(&mq->parent.parent)== RT_Object_Class_MessageQueue);RT_ASSERT(buffer != RT_NULL);RT_ASSERT(size !=0);/* greater than one message size */if(size > mq->msg_size)return-RT_ERROR;RT_OBJECT_HOOK_CALL(rt_object_put_hook,(&(mq->parent.parent)));/* disable interrupt */
temp =rt_hw_interrupt_disable();/* get a free list, there must be an empty item */
msg =(structrt_mq_message*)mq->msg_queue_free;/* message queue is full */if(msg == RT_NULL){/* enable interrupt */rt_hw_interrupt_enable(temp);return-RT_EFULL;}/* move free list pointer */
mq->msg_queue_free = msg->next;/* enable interrupt */rt_hw_interrupt_enable(temp);/* the msg is the new tailer of list, the next shall be NULL */
msg->next = RT_NULL;/* copy buffer */rt_memcpy(msg +1, buffer, size);/* disable interrupt */
temp =rt_hw_interrupt_disable();/* link msg to message queue */if(mq->msg_queue_tail != RT_NULL){/* if the tail exists, */((structrt_mq_message*)mq->msg_queue_tail)->next = msg;}/* set new tail */
mq->msg_queue_tail = msg;/* if the head is empty, set head */if(mq->msg_queue_head == RT_NULL)
mq->msg_queue_head = msg;/* increase message entry */
mq->entry ++;/* resume suspended thread */if(!rt_list_isempty(&mq->parent.suspend_thread)){rt_ipc_list_resume(&(mq->parent.suspend_thread));/* enable interrupt */rt_hw_interrupt_enable(temp);rt_schedule();return RT_EOK;}/* enable interrupt */rt_hw_interrupt_enable(temp);return RT_EOK;}
接收
主要工作同邮箱接收类似,这里的消息接收是从消息队列头进行接收的,保证接收的都是最新消息。
rt_err_trt_mq_recv(rt_mq_t mq,void*buffer,rt_size_t size,rt_int32_t timeout){structrt_thread*thread;registerrt_ubase_t temp;structrt_mq_message*msg;rt_uint32_t tick_delta;/* parameter check */RT_ASSERT(mq != RT_NULL);RT_ASSERT(rt_object_get_type(&mq->parent.parent)== RT_Object_Class_MessageQueue);RT_ASSERT(buffer != RT_NULL);RT_ASSERT(size !=0);/* initialize delta tick */
tick_delta =0;/* get current thread */
thread =rt_thread_self();RT_OBJECT_HOOK_CALL(rt_object_trytake_hook,(&(mq->parent.parent)));/* disable interrupt */
temp =rt_hw_interrupt_disable();/* for non-blocking call */if(mq->entry ==0&& timeout ==0){rt_hw_interrupt_enable(temp);return-RT_ETIMEOUT;}/* message queue is empty */while(mq->entry ==0){
RT_DEBUG_IN_THREAD_CONTEXT;/* reset error number in thread */
thread->error = RT_EOK;/* no waiting, return timeout */if(timeout ==0){/* enable interrupt */rt_hw_interrupt_enable(temp);
thread->error =-RT_ETIMEOUT;return-RT_ETIMEOUT;}/* suspend current thread */rt_ipc_list_suspend(&(mq->parent.suspend_thread),
thread,
mq->parent.parent.flag);/* has waiting time, start thread timer */if(timeout >0){/* get the start tick of timer */
tick_delta =rt_tick_get();RT_DEBUG_LOG(RT_DEBUG_IPC,("set thread:%s to timer list\n",
thread->name));/* reset the timeout of thread timer and start it */rt_timer_control(&(thread->thread_timer),
RT_TIMER_CTRL_SET_TIME,&timeout);rt_timer_start(&(thread->thread_timer));}/* enable interrupt */rt_hw_interrupt_enable(temp);/* re-schedule */rt_schedule();/* recv message */if(thread->error != RT_EOK){/* return error */return thread->error;}/* disable interrupt */
temp =rt_hw_interrupt_disable();/* if it's not waiting forever and then re-calculate timeout tick */if(timeout >0){
tick_delta =rt_tick_get()- tick_delta;
timeout -= tick_delta;if(timeout <0)
timeout =0;}}/* get message from queue */
msg =(structrt_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;/* decrease message entry */
mq->entry --;/* enable interrupt */rt_hw_interrupt_enable(temp);/* copy message */rt_memcpy(buffer, msg +1, size > mq->msg_size ? mq->msg_size : size);/* disable interrupt */
temp =rt_hw_interrupt_disable();/* put message to free list */
msg->next =(structrt_mq_message*)mq->msg_queue_free;
mq->msg_queue_free = msg;/* enable interrupt */rt_hw_interrupt_enable(temp);RT_OBJECT_HOOK_CALL(rt_object_take_hook,(&(mq->parent.parent)));return RT_EOK;}