[] TencentOS小さな奥行きソースコード解析(7) - イベント

入門

私たちはしばしば、プログラミングで使用される金属裸可能性があるflagイベントが発生するかをマークするために使用されるこの変数を、そしてそれは、あなたにもあり、複数のイベントを待つのであれば、その後、ループ内でこれらのマーカーが発生したかどうかを判断するif((xxx_flag)&&(xxx_flag))。このような判断を行うこと。もちろん、学生が取る賢明であろう場合に、このような最初の桁として行う兆候は、可変示すイベントを、第二の表す2つのイベントが起こっているときに、入射し、それと判定された値を判断するために、数ありますどのイベントが発生しました。flag某些位ABflag&0x03

しかし、どのように我々は、オペレーティング・システムに達成しますか?

イベント

オペレーティングシステムでは、事件カーネルリソース、主のためにデータ送信機能!任务与任务间、中断与任务间同步不提供

そして、の使用信号量同期が若干異なります。それは、イベントの多くは、多くの同期を達成することができます。これは、複数のイベントが発生したため、タスクが待つことができます:いずれかのウェイクアップイベント処理タスクいずれかのイベント中に、また、いくつかのイベントウェイクアップイベント処理タスクの後に発生したことができます。同様に、複数のイベントを同期するために、複数のタスクが存在することができます。

各イベント・グループは、最小限必要RAMイベントフラグを保持するための空間を事件(控制块)含んでいる旗标こと、旗标各ビットが「を表し事件、」フラグに格納されているk_event_flag_t変数(名前の種類flag、理解するのが簡単フラグ事件标记变量)、変数は、それぞれイベント、タスクを表し、イベント制御ブロックで定義されている“逻辑与”か、“逻辑或”イベントが発生したときに1つ以上の関連イベントと、タスクが起床されるであろう。

  • イベント「OR」であり独立型同步、タスクが起こされるのを待ちイベントにはいくつかのイベントのいずれかを参照して、;

  • イベント「論理」で关联型同步待機しているすべてのタスクでのイベントの数を参照して、唯一の目覚めが発生すること。

イベントタスクの通信は、タスク間の同期を達成するために使用することができる実施メカニズムが、データなしの送信イベントです。マルチタスク環境、タスク、多くの場合、割り込みの間に操作を同期する必要があるが、タスク、中断して、タスク間の同期とタスクの形成した場合で待っているタスクを伝えます。

イベント无排队性かつて一度だけセットと同等の同じイベントタスク(タスクがまだ行く読む時間を持っていない場合)、より多くのを設定します。

さらにイベントは、多くの同期動作の多くを、多くを提供することができます。

  • 一对多同期モデル:トリガー複数のイベントを待っているタスクは、このような状況がより一般的です。

  • 多对多同期モデル:トリガー複数のイベントを待っている複数のタスク、タスクがイベントをトリガするイベントを達成し、ビットを設定することにより、操作を待つことができます。

イベントデータ構造

イベント制御ブロック

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:タスクは、任意のイベント、「OR」を待っています!
  • TOS_OPT_EVENT_PEND_ALL:タスクはすべてのイベント、すなわち「AND」を待っています!
  • TOS_OPT_EVENT_PEND_CLR:保留中のイベントフラグをクリアするには、あってもよいTOS_OPT_EVENT_PEND_ANYTOS_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->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;
}

破壊イベント

イベントデストラクタは、すべての情報に基づいてクリアされるイベントの破壊後、イベント制御ブロックの直接破壊されますが、イベントが破棄されると、その待機リストにタスクが存在する、再びこのイベントを使用することはできません、システムは、これらのタスクを待っていたものに必要です目を覚ますとタスクイベントが破棄された通知します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()

注意:イベントは制御ブロックRAMによって決定された場合编译器静态分配、そのイベントが破壊されても、これはメモリを解放する方法はありません。もちろん、あなたもイベントのためにメモリを割り当てる動的メモリ制御ブロックを使用することができますが、破壊は、このメモリは、メモリリークを避けたい解放された後。

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

私はそれに焦点を当てるのが好き!

私は世間の注目号を歓迎します

関連のコードは、バック公共数の取得「19」を返信することができます。
詳細については懸念「物事のIoT開発、」公共の番号を喜ばせます!

おすすめ

転載: www.cnblogs.com/iot-dev/p/11689002.html