Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Introduction to the principle and related operations of TencentOS tiny events

2025-03-31 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/02 Report--

This article introduces the relevant knowledge of "the principle of TencentOS tiny events and related operations". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

Event

In the operating system, event is a kind of kernel resource, which is mainly used for synchronization between tasks, interrupts and tasks, and does not provide data transfer function!

It is slightly different from using semaphore synchronization: events can achieve one-to-many, many-to-many synchronization. That is, a task can wait for multiple events to occur: it can wake up the task for event processing when any event occurs, or it can wake up the task for event processing after several events have occurred. Similarly, multiple tasks can synchronize multiple events.

Each event group needs very little RAM space to hold the event flag. An event (control block) contains a flag, each bit of the flag represents an "event", and the flag is stored in a variable of type k_event_flag_t (the name is flag, which simply means an event tag variable), which is defined in the event control block, each representing an event. The task is associated with one or more events through logical and or logical OR, and the task is awakened when the event occurs.

Event "logical OR" is independent synchronization, which means that any one of the several events that the task is waiting for can be awakened.

The event "logical and" is related synchronization, which means that it is awakened only when all of the events waiting for the task occur.

Event is a mechanism to realize the communication between tasks, which can be used to realize the synchronization between tasks, but there is no data transmission for events. In a multitasking environment, synchronous operations are often needed between tasks and interrupts, and an event will inform the waiting task, that is, to form a synchronization between task and task, interrupt and task.

Events are not queued, that is, setting the same event to a task multiple times (if the task has not had time to read away) is equivalent to setting it only once.

In addition, events can provide one-to-many, many-to-many synchronization.

One-to-many synchronization model: it is common for a task to wait for multiple events to be triggered.

Many-to-many synchronization model: multiple tasks wait for multiple events to be triggered, and tasks can trigger and wait events by setting event bits.

Event data structure event control block

TencentOS tiny manipulates events through the event control block, whose data type is k_event_t, and the event control block is composed of multiple elements.

Pend_obj is somewhat similar to object-oriented inheritance, inheriting properties that describe the types of kernel resources (such as mutexes, queues, mutexes, etc., as well as a waiting list list).

Flag is a flag, a 32-bit variable, so each event control block can only identify a maximum of 32 events!

Typedef struct k_event_st {pend_obj_t pend_obj; k_event_flag_t flag;} ktask eventual; task control block event related data structure typedef struct k_task_st {k_opt_t opt_event_pend; / * *

< 等待事件的的操作类型:TOS_OPT_EVENT_PEND_ANY 、 TOS_OPT_EVENT_PEND_ALL */ k_event_flag_t flag_expect; /**< 期待发生的事件 */ k_event_flag_t *flag_match; /**< 等待到的事件(匹配的事件) */ ···} k_task_t;与事件相关的宏定义 在tos_config.h中,配置事件开关的宏定义是TOS_CFG_EVENT_EN #define TOS_CFG_EVENT_EN 1u 在tos_event.h中,存在一些宏定义是用于操作事件的(opt选项): // if we are pending an event, for any flag we expect is set is ok, this flag should be passed to tos_event_pend #define TOS_OPT_EVENT_PEND_ANY (k_opt_t)0x0001// if we are pending an event, must all the flag we expect is set is ok, this flag should be passed to tos_event_pend #define TOS_OPT_EVENT_PEND_ALL (k_opt_t)0x0002#define TOS_OPT_EVENT_PEND_CLR (k_opt_t)0x0004 TOS_OPT_EVENT_PEND_ANY:任务在等待任意一个事件发生,即"逻辑或"! TOS_OPT_EVENT_PEND_ALL:任务在等待所有事件发生,即"逻辑与"! TOS_OPT_EVENT_PEND_CLR:清除等待到的事件旗标,可以与TOS_OPT_EVENT_PEND_ANY、TOS_OPT_EVENT_PEND_ALL混合使用(通过"|"运算符)。 除此之外还有一个枚举类型的数据结构,用于发送事件时的选项操作,可以在发送事件时清除事件旗标的其他位(即覆盖,影响其他事件),也可以保持原本旗标中的其他位(不覆盖,不影响其他事件)。 typedef enum opt_event_post_en { OPT_EVENT_POST_KEP, OPT_EVENT_POST_CLR,} opt_event_post_t;创建事件 系统中每个事件都有对应的事件控制块,事件控制块中包含了事件的所有信息,比如它的等待列表、它的资源类型,以及它的事件旗标值,那么可以想象一下,创建事件的本质是不是就是对事件控制块进行初始化呢?很显然就是这样子的。因为在后续对事件的操作都是通过事件控制块来操作的,如果控制块没有信息,那怎么能操作嘛~ 创建事件函数是tos_event_create(),传入一个事件控制块的指针*event,除此之外还可以指定事件初始值init_flag。 事件的创建实际上就是调用pend_object_init()函数将事件控制块中的event->

The pend_obj member variable is initialized and its resource type is identified as PEND_TYPE_EVENT. Then set the event- > flag member variable to the event flag initial value init_flag.

_ _ API__ k_err_t tos_event_create (k_event_t * event, k_event_flag_t init_flag) {TOS_PTR_SANITY_CHECK (event); pend_object_init (& event- > pend_obj, PEND_TYPE_EVENT); event- > flag = init_flag; return kryptonite;} destroy event

The event destruction function is directly terminated according to the event control block. After the event is terminated, all the information of the event will be cleared, and the event cannot be used again. When the event is destroyed, there are tasks in the waiting list. It is necessary for the system to wake up these waiting tasks and inform the task that the PEND_STATE_DESTROY has been destroyed. A task schedule is then generated to switch to the highest priority task execution.

The TencentOS tiny process for event destruction is as follows:

Call the pend_is_nopending () function to determine whether a task is waiting for an event

If there are tasks waiting for events, call the pend_wakeup_all () function to wake them up and tell them that the waiting task event has been destroyed (that is, set the wait state member variable pend_state in the task control block to PEND_STATE_DESTROY).

Call the pend_object_deinit () function to clear the contents of the event control block, most importantly by setting the resource type in the control block to PEND_TYPE_NONE, so that this event cannot be used.

Restore the event- > flag member variable to the default value of 0.

Perform task scheduling knl_sched ()

Note: if the RAM of the event control block is statically allocated by the compiler, this memory cannot be freed even if the event is destroyed. Of course, you can also use dynamic memory to allocate memory for event control blocks, but release the memory after destruction to avoid memory leaks.

_ _ API__ k_err_t tos_event_destroy (k_event_t * event) {TOS_CPU_CPSR_ALLOC (); TOS_PTR_SANITY_CHECK (event); # if TOS_CFG_OBJECT_VERIFY_EN > 0u if (! pend_object_verify (& event- > pend_obj, PEND_TYPE_EVENT)) {return Knowled OBJINVALID;} # endif TOS_CPU_INT_DISABLE () If (! pend_is_nopending (& event- > pend_obj)) {pend_wakeup_all (& event- > pend_obj, PEND_STATE_DESTROY);} pend_object_deinit (& event- > pend_obj); event- > flag = (k_event_flag_t) 0u; TOS_CPU_INT_ENABLE (); knl_sched (); return Knowerr response NONEE;} wait event

The tos_event_pend () function is used to get the event, through which you can know which one in the event flag is set to 1, that is, which event occurred, and then the task can specify "logical and", "logical OR" to wait for the event (opt_pend option).

And this function implements the wait timeout mechanism, and the task can wait for the event only when the event it is waiting for occurs. When the event does not occur, the task waiting for the event will enter the blocking state, and the blocking time timeout is specified by the user. During this period, if the event does not occur, the task will remain blocked to wait for the event to occur. When other tasks or interrupt service programs set corresponding flag bits to the event flag they are waiting for, the task will automatically change from blocking state to ready state. When the waiting time of a task exceeds the specified blocking time, even if the event has not occurred, the task will automatically shift from the blocked state to the ready state. This effectively reflects the real-time performance of the operating system.

When a task acquires an event, you can choose to clear the event action.

Operations waiting for events are not allowed to run in the interrupt context!

The process of waiting for an event is as follows:

First check whether the passed parameters are correct. Note that either TOS_OPT_EVENT_PEND_ALL or TOS_OPT_EVENT_PEND_ANY must exist for the opt_pend option, and both are not allowed to exist (mutually exclusive).

Call the event_is_match () function to determine whether the waiting event has occurred (that is, whether the event the task is waiting for matches the flag in the event control block).

In the event_is_match () function, a match is made based on whether the waiting option opt_pend waits for any event (TOS_OPT_EVENT_PEND_ANY) or all events (TOS_OPT_EVENT_PEND_ANY). If there is a match, K_TRUE is returned, otherwise K_FALSE is returned, and the waiting event is returned through the flag_match variable (matching has occurred). For the option of waiting for all times, it is a match if and only if all events occur: (event & flag_expect) = = flag_expect), for the option of waiting for any one event, one of the events occurs is considered a match: (event & flag_expect).

If the event does not occur, the currently acquired task may be blocked to see if the user-specified blocking time timeout is not blocking TOS_TIME_NOWAIT, and if it does not block, it will directly return the K_ERR_PEND_NOWAIT error code.

If the scheduler is locked knl_is_sched_locked (), the wait operation cannot be performed and the error code K_ERR_PEND_SCHED_LOCKED is returned. After all, the task needs to be switched, and the scheduler cannot switch tasks if the scheduler is locked.

Set the variable on the event in the task control block, that is, set the event that the task expects to wait, the event that the task expects to wait, the event that the task matches, the flag_match-> flag_match, and the option that the task waits for the event.

Call the pend_task_block () function to block the task, which actually removes the task from the ready list and inserts it into the waiting list object- > list. If the waiting time is not permanent waiting for TOS_TIME_FOREVER, it inserts the task into the time list k_tick_list with a blocking time of timeout, and then makes a task scheduling knl_sched ().

When the program can continue to execute, it means that the task waits until the event occurs, or when the timeout occurs, the task does not need to wait for the event. At this time, the contents of the task control block are cleared, that is, the event that the task expects to wait is cleared, the event that the task is expected to wait, the event that the task is expected to wait, the event that the task matches, the event that the task is expected to wait, and the option for the task to wait for events are cleared, that is, the event that the task expects to wait flag_expect, the event that the task matches, and the option that the task waits for the event. At the same time, the pend_state2errno () function is called to get the wait state of the task, to see which situation causes the task to resume running, and to return the result to the task that called the waiting event function.

Note: when the task waiting for the event can resume running from the block, it may not necessarily wait until the event occurs, or it may be a timeout, so when writing the program, you must judge the status of the waiting event. If it is K_ERR_NONE, it means success!

The code is as follows:

_ _ STATIC__ int event_is_match (k_event_flag_t event, k_event_flag_t flag_expect, k_event_flag_t * flag_match, k_opt_t opt_pend) {if (opt_pend & TOS_OPT_EVENT_PEND_ALL) {if ((event & flag_expect) = = flag_expect) {* flag_match = flag_expect; return K_TRUE }} else if (opt_pend & TOS_OPT_EVENT_PEND_ANY) {if (event & flag_expect) {* flag_match = event & flag_expect; return Knowle true;}} return K_FALSE } _ _ API__ k_err_t tos_event_pend (k_event_t * event, k_event_flag_t flag_expect, k_event_flag_t * flag_match, k_tick_t timeout, k_opt_t opt_pend) {TOS_CPU_CPSR_ALLOC (); TOS_PTR_SANITY_CHECK (event); TOS_PTR_SANITY_CHECK (flag_match); TOS_IN_IRQ_CHECK () # if TOS_CFG_OBJECT_VERIFY_EN > 0u if (! pend_object_verify (& event- > pend_obj, PEND_TYPE_EVENT)) {return Knowleer _ OBJ _ invalid;} # endif if (! (opt_pend & TOS_OPT_EVENT_PEND_ALL) & &! (opt_pend & TOS_OPT_EVENT_PEND_ANY)) {return K_ERR_EVENT_PEND_OPT_INVALID } if ((opt_pend & TOS_OPT_EVENT_PEND_ALL) & & (opt_pend & TOS_OPT_EVENT_PEND_ANY)) {return TOS_CPU_INT_DISABLE () If (event_is_match (event- > flag, flag_expect, flag_match, opt_pend) {if (opt_pend & TOS_OPT_EVENT_PEND_CLR) {/ / destroy the bridge after get across the river event- > flag = (k_event_flag_t) 0u;} TOS_CPU_INT_ENABLE (); return K_ERR_NONE } if (timeout = = TOS_TIME_NOWAIT) {TOS_CPU_INT_ENABLE (); return Karmerr current current task-> flag_match = flag_match;} if (knl_is_sched_locked ()) {TOS_CPU_INT_ENABLE (); return Knowerr efficiency PENDSCHEDLOCKED;} kink curry task-> flag_expect = knight curry task-> flag_match = flag_match Flag_expect-> opt_event_pend = opt_pend; pend_task_block (k_curr_task, & event- > pend_obj, timeout); TOS_CPU_INT_ENABLE (); knl_sched (); flag_expect = (k_event_flag_t) 0u; flag_match = (k_event_flag_t *) K_NULL Send events: return pend_state2errno (k_opt_t currents task-> pend_state); send events

TencentOS tiny provides two functions to send events, namely: tos_event_post () and tos_event_post_keep (). In essence, both functions call the same function event_do_post () to implement the operation of sending events, but the options are different. Using the tos_event_post () function will overwrite the specified event and may affect other events that have occurred. On the other hand, the tos_event_post_keep () function can keep the other event bits unchanged while the event occurs at the same time, which is more commonly used in practice.

This function is used to write the event that has occurred to the bit specified in the event flag. When the corresponding bit is set to 1, the task waiting for the event may be resumed. In this case, you need to traverse the event waiting list on the event object to determine whether any event expected by the task matches the value of the current event flag, and if so, wake up the task.

To put it simply, set the self-defined event flag to 1, and see if any tasks are waiting for the event, and if so, wake it up.

What is well designed in TencentOS tiny is simplicity and low coupling. These two api interfaces essentially call the event_do_post () function to generate events, but choose different processing methods through different opt_post parameters.

The processing in the event_do_post () function is also very simple and straightforward, and its execution ideas are as follows:

First, determine the way in which the event occurs, opt_post. If it is OPT_EVENT_POST_KEP, use the "|" operation to write the event flag, otherwise assign the value directly.

Use TOS_LIST_FOR_EACH_SAFE to traverse the event wait list waiting on the event object, determine whether any event expected by the task matches the value of the current event flag through the event_is_match () function, and if so, call the pend_task_wakeup () function to wake up the corresponding task.

If the waking wait task specifies to clear the corresponding event, the flag value of the event is cleared.

Finally, do a task scheduling knl_sched ().

_ _ STATIC__ k_err_t event_do_post (k_event_t * event, k_event_flag_t flag, opt_event_post_t opt_post) {TOS_CPU_CPSR_ALLOC (); k_task_t * task; k_list_t * curr, * next # if TOS_CFG_OBJECT_VERIFY_EN > 0u if (! pend_object_verify (& event- > pend_obj, PEND_TYPE_EVENT)) {return Knowleer _ OBJ _ invalid;} # endif if (opt_post = = OPT_EVENT_POST_KEP) {event- > flag | = flag;} else {event- > flag = flag;} TOS_CPU_INT_DISABLE () TOS_LIST_FOR_EACH_SAFE (curr, next, & event- > pend_obj.list) {task = TOS_LIST_ENTRY (curr, k_task_t, pend_list); if (event- > flag, task- > flag_expect, task- > flag_match, task- > opt_event_pend) {pend_task_wakeup (TOS_LIST_ENTRY (curr, k_task_t, pend_list), PEND_STATE_POST) / / if anyone pending the event has set the TOS_OPT_EVENT_PEND_CLR, then no wakeup for the others pendig for the event. If (task- > opt_event_pend & TOS_OPT_EVENT_PEND_CLR) {event- > flag = (k_event_flag_t) 0u; break;} TOS_CPU_INT_ENABLE (); knl_sched (); return K_ERR_NONE } _ API__ k_err_t tos_event_post (k_event_t * event, k_event_flag_t flag) {TOS_PTR_SANITY_CHECK (event); return event_do_post (event, flag, OPT_EVENT_POST_CLR);} _ API__ k_err_t tos_event_post_keep (k_event_t * event, k_event_flag_t flag) {TOS_PTR_SANITY_CHECK (event) This is the end of the introduction of return event_do_post (event, flag, OPT_EVENT_POST_KEP);} "introduction to the principles and related operations of TencentOS tiny events". Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report