[] TencentOS крошечное глубокий анализ исходного кода (7) - событие

введение

Мы, вероятно , чтобы обнажить металл часто используется в программировании flagэтой переменной, используется для обозначения того, что произойдет событие, а затем определить , происходит ли эти маркеры в цикле, если ждать несколько событий, вы можете также , if((xxx_flag)&&(xxx_flag))как это сделать суждение. Конечно, если немного умные студенты будут принимать сделать знаки, такие как первая цифра указывает на переменную событие, второй представляет собой случай, когда два события происходят, определяется , что значение является числом, для того , чтобы определить какое событие произошло.flag某些位ABflag&0x03

Но как мы достигнем в операционной системе?

событие

В операционной системе, 事件ядро ресурсов, в основном для , функция передачи данных!任务与任务间、中断与任务间同步不提供

А использование 信号量синхронизации немного отличается: он может достичь событийно-многим, многие-синхронизации. Это задача может ждать произойти несколько событий: либо тревожная задачу обработки событий во время любого одного события, также может быть несколько событий произошли после того, как задачи обработки событий пробуждения. Кроме того , может быть несколько задач для синхронизации нескольких событий.

Каждая группа события требует минимального RAMместа для хранения флага события, 事件(控制块)содержит 旗标, что 旗标каждый бит представляет собой 事件«» флаги хранятся в k_event_flag_tтипе переменного (имя flag, флаг просто понять 事件标记变量), переменная определена в блоках управления событием, каждый представляет собой событие, задачу “逻辑与”или “逻辑或”с одним или более связанными с ним событиями, задача будет разбужена , когда происходит событие.

  • Событие «ИЛИ» является 独立型同步ссылкой на один из нескольких событий в случае задача ждет пробудиться;

  • Событие «логика» 关联型同步, имея в виду количество событий во всех задач , ожидающих пробудиться только произойдет.

коммуникация задачи события представляет собой механизм реализации, может быть использована для достижения синхронизации между задачами, но нет события передачи данных. Многозадачной среде, задачи, часто необходимо синхронизировать операции между прерываниями, говорит задачу ожидания в том случае, если формирование задачи с задачей, прерывания и синхронизации задач.

Событие , 无排队性который установлен более чем один раз в одной и той же задачи , события (если задача еще не успела прочитать идти), эквивалентно множеству только один раз.

Дальнейшие события могут обеспечить многие, многие ко многим синхронной работы.

  • 一对多Синхронизация модель: задача ждет в триггере нескольких событий, эта ситуация является более распространенной;

  • 多对多Синхронизация модели: несколько задач, ожидающих запуска нескольких событий задача может быть выполнена событие, инициирующее событие и ждать операции путем установки бита.

Структура данных событий

Блок управления событий

TencentOS tinyСобытие Управления с помощью блока управления события, которое является типом данных k_event_t, блок управления события состоит из множества элементов.

  • pend_objНесколько похожи на объектно-ориентированное наследование, некоторые свойства, там описаны типа ресурсов ядра (например мьютекс взаимной блокировки очереди, и т.д., и список ожидания list).
  • flagФлаг, 32-битная переменная, так что каждый блок 32 управления событием можно определить только события!
typedef struct k_event_st {
    pend_obj_t      pend_obj;
    k_event_flag_t  flag;
} k_event_t;

Целевая управляющая структура блока данных, связанное с событием

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;

Создать событие

Система, каждое событие имеет соответствующий блок управления событием, Event Блок управления содержит всю информацию о событии, например, его список ожидания, его тип ресурса, и его значение флага события, то представьте себе, создать событие это не то, что суть блока управления событием для его инициализации? Очевидно, что это так. Поскольку последующая операция события блока управления события работают, блок управления, если нет информации, как она может работать Ну ~

Создание функции является событием tos_event_create(), передавая указатель на блок контроля событий *event, в дополнении к событию вы можете задать начальное значение init_flag.

Создать событие на самом деле вызова pend_object_init()функции в блоке управления событием event->pend_objпеременной член инициализируется, он определяется как тип ресурса PEND_TYPE_EVENT. Затем event->flagпеременная элемент установлен , чтобы отметить начальное значение флага события 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 K_ERR_NONE;
}

событие Destruction

деструктор Event очищается на основе всей информации , будет прямое уничтожением блока управления событием, после разрушения события, но не может использовать это событие еще раз, когда событие будет уничтожено, его список ожидания существует задачу, система необходима для тех , кто ждет этих задачи проснуться и сообщить событие задачи было уничтожено PEND_STATE_DESTROY. А затем генерирует планировщик задач для переключения на наивысший приоритет выполнения задач.

TencentOS tiny Процесс уничтожения событий выглядит следующим образом:

  1. Вызовите pend_is_nopending()функцию , чтобы определить , есть ли задачи , ожидающие события
  2. Если есть задачи , ожидающие события , он вызывается в pend_wakeup_all()функции этих задач проснется, и сказали ждать события задачи была уничтожен (т.е. установить ожидание состояние управление задачами переменного член блока pend_stateявляется PEND_STATE_DESTROY).
  3. Вызов pend_object_deinit()функции для управления событием в удалении блока контента, наиболее важным является тип управления ресурсным блока установлен PEND_TYPE_NONE, так что ребенок не сможет использовать этот инцидент.
  4. В event->flagпеременных членах восстановления к их значениям по умолчанию 0.
  5. планирование задачknl_sched()

Примечание: Если событие определяется управление блоком памяти 编译器静态分配, так что даже если событие будет уничтожено, это не существует способ , чтобы освободить память. Конечно, вы можете также использовать динамический блок управления памятью , чтобы выделить память для события, но после разрушения освобожденного хотите эту память , чтобы избежать утечек памяти.

__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 K_ERR_OBJ_INVALID;
    }
#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 K_ERR_NONE;
}

Ожидание события

tos_event_pend()Функция используется для получения событий через эту функцию, вы можете узнать , 事件旗标что это 置1такое событие , которое произошло, то задача может быть задана для ожидания события “逻辑与”、“逻辑或”операции ожидания ( opt_pend选项).

И эта функция реализует 等待超时механизм, и только тогда , когда возникает задача ожидает события, задача может ждать события. Когда событие не произошло, то задача ожидает событие , переходит в состоянии блокировки, время блокировки , timeoutуказанное пользователем, в это время, если событие не произошло, то задача будет по- прежнему заблокирована ждет событие произойдет. Когда стандартный набор флаги флага соответствующего события других задач или процедуры обслуживания прерывания их ожидания, задача будет автоматически состояния блокировки в состояние готовности. Когда время выполнения задачи ожидания превышает заданное время блокировки, даже если событие не произошло, то задача будет автоматически переведен из состояния блокировки в состояние готовности. Как это очень эффективно отражает операционную систему реального времени.

Когда задача приобрела событие, вы можете выбрать, чтобы очистить действие события.

Подождите прерывания события операция не разрешена в контексте работы!

В ожидании событий выглядит следующим образом:

  1. Во- первых обнаружены входные параметры являются правильными. , Примечание opt_pendПараметры должны существовать TOS_OPT_EVENT_PEND_ALLили TOS_OPT_EVENT_PEND_ANYодин, и как право на существование ( 互斥).
  2. Позвоните event_is_match()ли ждать функций , чтобы определить , произошло событие (то есть, задача ждет событий и управление блоком событий ли флаг 匹配).
  3. В event_is_match()функции на основе опции ждет opt_pend, чтобы ждать , пока какое - либо событие ( TOS_OPT_EVENT_PEND_ANY) или подождать , пока все события ( TOS_OPT_EVENT_PEND_ANY) , чтобы судить о том матче , если матч возвращается K_TRUE, в противном случае возвращается K_FALSE, во время ожидания события по flag_matchпеременным доходностям (матч произошел) , Время ожидания для всех вариантов, если и только если все события происходят считаются матчем: (event & flag_expect) == flag_expect)Для любого варианта ждать события, событие , которое произошло считается матчем: (event & flag_expect).
  4. Если событие происходит, оно не может блокировать приобретение текущей задачи, обратите внимание на указанное пользователем время блокировки timeoutили не блокировать TOS_TIME_NOWAIT, если не заблокирован непосредственно возвращает K_ERR_PEND_NOWAITкод ошибки.
  5. Если планировщик заблокирован knl_is_sched_locked(), вы не можете ждать операции и возвращает код ошибки K_ERR_PEND_SCHED_LOCKED, в конце концов, нужно переключить задачи, планировщик закрыта , вы не можете переключиться на другую задачу.
  6. Контрольные задачи блока переменных о событии набора о выполнении этой задачи , чтобы установить событие , как ожидается, ждать k_curr_task->flag_expect, задача согласования события k_curr_task->flag_matchи задачи событий ждет возможности k_curr_task->opt_event_pend.
  7. Вызов pend_task_block()функции задача заблокирована, эта функция фактически готова быть удалены из списка задач k_rdyq.task_list_head[task_prio], и вставляется в список ожидания object->list, если время ожидания не ждать вечно TOS_TIME_FOREVER, но и время , задача вставки списка k_tick_list, время блокировки timeout, то задача о планировании knl_sched().
  8. Когда программа может продолжать, то это означает 任务等待到事件, или если 等待发生了超时задаче не нужно ждать события, и на этот раз содержимое блока управления задачей рассеялось, очистить ожидающее задание желаемых событий k_curr_task->flag_expect, событий , которые соответствуют задачам k_curr_task->flag_match, и ожидание задачи варианты событий k_curr_task->opt_event_pend, а также вызова pend_state2errno()функции , чтобы получить о состоянии задачи ожидания, обратите внимание на какие обстоятельства , ведущие к задаче восстановления для запуска, и результат возвращается в вызывающую функцию ждет событийной задачи.

Примечание: Когда задача ожидает события от обструкции возобновить работу, не обязательно ждать , пока не произойдет событие, может быть тайм - аут произошел, поэтому при написании программы должна ждать , пока государство , чтобы определить , какие события, если оно K_ERR_NONEизвлекает успех!

Код выглядит следующим образом:

__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);
}

Отправить событие

TencentOS tinyОтправить событие предоставляет две функции, а именно: tos_event_post()и tos_event_post_keep()эти две функции, по существу , та же функция вызывается event_do_post()для реализации операции, отправившего событие, единственный вариант отличается, используйте tos_event_post()функцию перепишет указанное событие, может повлиять на другие события , которые имели место, и tos_event_post_keep()функция может поддерживаться одновременные события и другие события положение не меняется, в самом деле, последний чаще используется.

Эта функция используется для записи события произошло событие флага указанное положение, когда соответствующий бит установлен, то задача ожидает события , которое может быть восстановлено, на этот раз нужно ждать на объект события для обхода события очередникам чтобы определить , есть ли задачи 期望的事件с текущим 事件旗标значением совпадает, если есть, то просыпаются задача.

Проще говоря, это установить свое собственное определение флага события на 1 и посмотреть, если есть задачи, которые ждут этого события, да, она проснется.

TencentOS tinyХорошее место в конструкции просто и низкая сцепка, призывает как характер интерфейса API event_do_post()функций к возникновению события, но по opt_postразличным параметрам выбрали другой подход.

В event_do_post()обработчик очень прост, исполнение идеи заключается в следующем:

  1. Во- первых, определить , какой способ событий opt_post, если он OPT_EVENT_POST_KEPиспользуется или операция “|”записывается флаг событий или прямого назначения.
  2. Используйте TOS_LIST_FOR_EACH_SAFEсобытие для обхода объекта события ждать в списке ожидания, с помощью event_is_match()функции , чтобы определить , есть ли задачи 期望的事件с текущими 事件旗标значениями совпадают, если вы звоните pend_task_wakeup()функцию бодрствования соответствующей задачу.
  3. Если после ожидания задач, поставленных, чтобы очистить соответствующее событие, а затем сбрасывает значение флага события.
  4. Наконец, планирование задач 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);
}

Я хотел бы сосредоточиться на нем!

Я приветствую внимание общественности No.

Относящийся код может ответить «19» Вернитесь в общедоступном номере.
Для получения дополнительной информации , пожалуйста , концерн «Развитие вещи IoT,» общественность номер!

рекомендация

отwww.cnblogs.com/iot-dev/p/11689002.html