Rtthread event
event主要用于线程间通信,线程结构体中有thread->event_info成员,存放FLAG标志,
当FLAG标志为RT_EVENT_FLAG_AND时,需要满足
(thread->event_set & event->set) == thread->event_set 才能唤醒该线程
当FLAG标志为RT_EVENT_FLAG_OR时,满足 thread->event_set & event->set 即可唤醒线程。
当FLAG标志为 thread->event_info & RT_EVENT_FLAG_CLEAR,则在发送完event后会清掉该
event。
#ifdef RT_USING_EVENT
/**
* flag defintions in event
*/
#define RT_EVENT_FLAG_AND 0x01 /**< logic and */
#define RT_EVENT_FLAG_OR 0x02 /**< logic or */
#define RT_EVENT_FLAG_CLEAR 0x04 /**< clear flag */
/*
* event structure
*/
struct rt_event
{
struct rt_ipc_object parent; /**< inherit from ipc_object */
rt_uint32_t set; /**< event set */
};
typedef struct rt_event *rt_event_t;
#endif
#ifdef RT_USING_EVENT
/**
* This function will initialize an event and put it under control of resource
* management.
*
* @param event the event object
* @param name the name of event
* @param flag the flag of event
*
* @return the operation status, RT_EOK on successful
*/
rt_err_t rt_event_init(rt_event_t event, const char *name, rt_uint8_t flag)
{
/* parameter check */
RT_ASSERT(event != RT_NULL);
/* initialize object */
rt_object_init(&(event->parent.parent), RT_Object_Class_Event, name);
/* set parent flag */
event->parent.parent.flag = flag;
/* initialize ipc object */
rt_ipc_object_init(&(event->parent));
/* initialize event */
event->set = 0;
return RT_EOK;
}
/**
* This function will detach an event object from resource management
*
* @param event the event object
*
* @return the operation status, RT_EOK on successful
*/
rt_err_t rt_event_detach(rt_event_t event)
{
/* parameter check */
RT_ASSERT(event != RT_NULL);
RT_ASSERT(rt_object_get_type(&event->parent.parent) == RT_Object_Class_Event);
RT_ASSERT(rt_object_is_systemobject(&event->parent.parent));
/* resume all suspended thread */
rt_ipc_list_resume_all(&(event->parent.suspend_thread));
/* detach event object */
rt_object_detach(&(event->parent.parent));
return RT_EOK;
}
#ifdef RT_USING_HEAP
/**
* This function will create an event object from system resource
*
* @param name the name of event
* @param flag the flag of event
*
* @return the created event, RT_NULL on error happen
*/
rt_event_t rt_event_create(const char *name, rt_uint8_t flag)
{
rt_event_t event;
RT_DEBUG_NOT_IN_INTERRUPT;
/* allocate object */
event = (rt_event_t)rt_object_allocate(RT_Object_Class_Event, name);
if (event == RT_NULL)
return event;
/* set parent */
event->parent.parent.flag = flag;
/* initialize ipc object */
rt_ipc_object_init(&(event->parent));
/* initialize event */
event->set = 0;
return event;
}
/**
* This function will delete an event object and release the memory
*
* @param event the event object
*
* @return the error code
*/
rt_err_t rt_event_delete(rt_event_t event)
{
/* parameter check */
RT_ASSERT(event != RT_NULL);
RT_ASSERT(rt_object_get_type(&event->parent.parent) == RT_Object_Class_Event);
RT_ASSERT(rt_object_is_systemobject(&event->parent.parent) == RT_FALSE);
RT_DEBUG_NOT_IN_INTERRUPT;
/* resume all suspended thread */
rt_ipc_list_resume_all(&(event->parent.suspend_thread));
/* delete event object */
rt_object_delete(&(event->parent.parent));
return RT_EOK;
}
#endif
/**
* This function will send an event to the event object, if there are threads
* suspended on event object, it will be waked up.
*
* @param event the event object
* @param set the event set
*
* @return the error code
*/
rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set)
{
struct rt_list_node *n;
struct rt_thread *thread;
register rt_ubase_t level;
register rt_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))//有在等待event的阻塞中的线程
{
/* search thread list to resume thread */
n = event->parent.suspend_thread.next;
while (n != &(event->parent.suspend_thread))//遍历suspend线程链表
{
/* get thread */
thread = rt_list_entry(n, struct rt_thread, tlist);//获取线程
status = -RT_ERROR;
if (thread->event_info & RT_EVENT_FLAG_AND)//线程FLAG满足与条件
{
if ((thread->event_set & event->set) == thread->event_set)//条件相与为真则唤醒
{
/* received an AND event */
status = RT_EOK;
}
}
else if (thread->event_info & RT_EVENT_FLAG_OR)//相或为真则唤醒该线程
{
if (thread->event_set & event->set)
{
/* save the received event set */
thread->event_set = thread->event_set & event->set;
/* received an OR event */
status = RT_EOK;
}
}
else
{
/* enable interrupt */
rt_hw_interrupt_enable(level);
return -RT_EINVAL;
}
/* move node to the next */
n = n->next;
/* condition is satisfied, resume thread */
if (status == RT_EOK)
{
//线程info中带该标志,则接受event后清除该event
if (thread->event_info & RT_EVENT_FLAG_CLEAR)
event->set &= ~thread->event_set;
//恢复线程
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;
}
/**
* This function will receive an event from event object, if the event is
* unavailable, the thread shall wait for a specified time.
*
* @param event the fast event object
* @param set the interested event set
* @param option the receive option, either RT_EVENT_FLAG_AND or
* RT_EVENT_FLAG_OR should be set.
* @param timeout the waiting time
* @param recved the received event, if you don't care, RT_NULL can be set.
*
* @return the error code
*/
rt_err_t rt_event_recv(rt_event_t event,
rt_uint32_t set,
rt_uint8_t option,
rt_int32_t timeout,
rt_uint32_t *recved)
{
struct rt_thread *thread;
register rt_ubase_t level;
register rt_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;
/* initialize 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)//该条件满足,说明已经有event事件产生了,直接由线程处理事件
{
if ((event->set & set) == set)
status = RT_EOK;
}
else if (option & RT_EVENT_FLAG_OR)//该条件满足,说明已经有event事件产生了,直接由线程处理事件
{
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);
/* fill thread event info */
thread->event_set = (event->set & set);//设置线程接收event条件
thread->event_info = option;//设置event 标志
/* received event */
if (option & RT_EVENT_FLAG_CLEAR)//设置完后清除event->set
event->set &= ~set;
}
else if (timeout == 0) //不等待,直接返回
{
/* no waiting */
thread->error = -RT_ETIMEOUT;
/* enable interrupt */
rt_hw_interrupt_enable(level);
return -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;
}
/**
* This function can get or set some extra attributions of an event object.
*
* @param event the event object
* @param cmd the execution command
* @param arg the execution argument
*
* @return the error code
*/
rt_err_t rt_event_control(rt_event_t event, int cmd, void *arg)
{
rt_ubase_t level;
/* parameter check */
RT_ASSERT(event != RT_NULL);
RT_ASSERT(rt_object_get_type(&event->parent.parent) == RT_Object_Class_Event);
if (cmd == RT_IPC_CMD_RESET)
{
/* disable interrupt */
level = rt_hw_interrupt_disable();
/* resume all waiting thread */
rt_ipc_list_resume_all(&event->parent.suspend_thread);
/* initialize event set */
event->set = 0;
/* enable interrupt */
rt_hw_interrupt_enable(level);
rt_schedule();
return RT_EOK;
}
return -RT_ERROR;
}
#endif /* end of RT_USING_EVENT */
#ifdef RT_USING_MAILBOX