2021SC@SDUSC TencentOS Tiny event

2021SC@SDUSC

Wait event

tos_ event_ The pend() function is used to obtain events. Through this function, you can know which bit in the event flag is set to 1, that is, which event has occurred. Then, the task can specify "logical and" and "logical or" to wait for the waiting 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. The blocking time timeout is specified by the user. During this time, if the event does not occur, the task will remain in the blocking state to wait for the event to occur. When other tasks or interrupt service programs set the corresponding flag bit to the event flag they are waiting for, the task will automatically change from blocking state to ready state. When the waiting time of the task exceeds the specified blocking time, the task will automatically transfer from blocking state to ready state even if the event has not occurred. This subsystem effectively reflects the real-time performance of the operating system.

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

The process of waiting for events is as follows:

1. First, check whether the parameters passed in are correct., Note opt_ The option for pend must have TOS_OPT_EVENT_PEND_ALL or TOS_OPT_EVENT_PEND_ANY, and both are not allowed to exist at the same time (mutually exclusive).

2. Call event_ is_ The match () function determines whether the waiting event has occurred).

3. In event_ is_ In the match() function, opt is selected according to the wait option_ Pend determines whether to wait for any event (TOS_OPT_EVENT_PEND_ANY) or all events (TOS_OPT_EVENT_PEND_ANY). If it is matched, K is returned_ True, otherwise K is returned_ False, and the waiting events pass the flag_ The match variable returns (a match has occurred). For the option of waiting for all times, it is matched if and only if all events occur: (Event & flag_expect) = = flag_ Expect), for the option of waiting for any event, the occurrence of one of the events is a match: (Event & flag_expect).

4. If the event does not occur, the currently obtained task may be blocked. Check whether the blocking time timeout specified by the user is not blocking TOS_TIME_NOWAIT. If it is not blocked, K is returned directly_ ERR_ PEND_ Nowait error code.

5. If the scheduler is locked knl_is_sched_locked(), the wait operation cannot be performed, and the error code K is returned_ ERR_ PEND_ SCHED_ Locked. After all, tasks need to be switched. If the scheduler is locked, tasks cannot be switched.

6. Set the event variable in the task control block, that is, set the event k that the task expects to wait for_ curr_ task->flag_ Expect, event K matching the task_ curr_ task->flag_ Match, and the option K of the task waiting event_ curr_ task->opt_ event_ pend.

7. Call pend_ task_ The block () function blocks the task, which actually removes the task from the ready list k_rdyq.task_list_head[task_prio], and insert it into the waiting list object - > list. If the waiting time is not permanent, wait for TOS_ TIME_ Before, the task is also inserted into the time list k_tick_list, the blocking time is timeout, and then perform a task scheduling knl_sched().

8. When the program can continue to execute, it means that the task has waited for an event, or the waiting has timed out, and the task does not need to wait for an event. At this time, the content in the task control block is cleared, that is, the event K for which the task expects to wait is cleared_ curr_ task->flag_ Expect, event K matching the task_ curr_ task->flag_ Match, and the option K of the task waiting event_ curr_ task->opt_ event_ Pend, which is also called_ The state2errno () function obtains the waiting status of the task, finds out what causes the task to resume running, and returns the result to the task calling the waiting event function.

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 K_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 K_ERR_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 K_ERR_EVENT_PEND_OPT_INVALID;
    }

    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 K_ERR_PEND_NOWAIT;
    }

    if (knl_is_sched_locked()) {
        TOS_CPU_INT_ENABLE();
        return K_ERR_PEND_SCHED_LOCKED;
    }

    k_curr_task->flag_expect      = flag_expect;
    k_curr_task->flag_match       = flag_match;
    k_curr_task->opt_event_pend   = opt_pend;

    pend_task_block(k_curr_task, &event->pend_obj, timeout);

    TOS_CPU_INT_ENABLE();
    knl_sched();

    k_curr_task->flag_expect      = (k_event_flag_t)0u;
    k_curr_task->flag_match       = (k_event_flag_t *)K_NULL;
    k_curr_task->opt_event_pend   = (k_opt_t)0u;

    return pend_state2errno(k_curr_task->pend_state);
}

Send event

TencentOS tiny provides two functions to send events: tos_event_post() and tos_event_post_keep(), both functions essentially call the same function event_do_post() implements the operation of sending events, but the options are different. Use TOS_ event_ The post() function overwrites the specified event and may affect other events that have occurred, while TOS_ event_ post_ The keep () function can keep other event bits unchanged and events occur at the same time. In practice, the latter is more commonly used.

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. At this time, it is necessary to traverse the event waiting list waiting on the event object to determine whether the expected event of the task matches the value of the current event flag. If so, wake up the task.

To put it simply, set the event flag bit defined by yourself to 1, and see if there is a task waiting for this event. If so, wake it up.

A good design in TencentOS tiny is simplicity and low coupling. These two api interfaces essentially call event_ do_ The post () function is used to generate events, just through opt_ Different processing methods are selected for different post parameters.

In event_ do_ The processing in the post() function is also very simple and clear. Its execution idea is as follows:

1. First, judge how the event happened opt_post, if OPT_EVENT_POST_KEP uses the or operation "|" to write the event flag, otherwise it is assigned directly.

2. Use TOS_LIST_FOR_EACH_SAFE traverses the event waiting list waiting on the event object through event_ is_ The match() function judges whether there is an event expected by the task that matches the value of the current event flag. If so, it calls pend_task_wakeup() function wakes up the corresponding task.

3. If the wake-up waiting task specifies to clear the corresponding event, the flag value of the event will be cleared.

4. Perform the last 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 K_ERR_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_is_match(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);

    return event_do_post(event, flag, OPT_EVENT_POST_KEP);
}

Posted by mnewhart on Sun, 28 Nov 2021 05:49:57 -0800