Hongmengカーネルソースコード分析(タスク/スレッド管理)

注:コアオープンソースのあいまいさの分析に基づいて、公式ソース[ kernel_liteos_a ]公式ドキュメント[ docs ]リファレンスドキュメント[ Huawei LiteOS ]
作者:Hong Mengコア愛好家は、あいまいなカーネルの研究を続け、ブログを更新する予定です。コンテンツは個人的な見解のみを表しており、エラーは歓迎されます。誰でも修正して改善することができます。このシリーズのすべての記事を
あいまいなシステムのソースコード分析に表示(リスト)


この記事では、タスク/スレッド管理のソースコードを詳細に分析します:los_task.c

目次

序文

1.タスクを理解する方法

1.公式文書はスレッドをどのように説明していますか

2. taskコマンドを実行します

3.タスクはどのように見えますか?

第二に、タスクを管理する方法

1.タスクプールとは何ですか?

2.レディキューの問題

3.タスクスタックの問題

4.タスクスタックの初期化

3、タスク関数セット

1.使用シナリオと機能

2.タスクを作成するプロセス

3.言及されていないタスク/スレッドパーツの重要な内容は何ですか?

詳細については、Hongmeng System Source Code Analysis(General Catalog)をクリックしてください。


序文

Hongmengカーネルでは、タスクは広義のスレッドとして理解できます


1.タスクを理解する方法

1.公式文書はスレッドをどのように説明していますか

基本的な概念
システムの観点から見ると、スレッドはシステムリソースをめぐって競合する操作の最小単位です。スレッドは、CPUやメモリ空間などのシステムリソースを使用または待機し、他のスレッドとは独立して実行できます。

Hongmengカーネルの各プロセスのスレッドは独立して実行され、独立してスケジュールされます。現在のプロセスのスレッドのスケジュールは、プロセスの他のスレッドの影響を受けません。

Hongmengカーネルのスレッドは、プリエンプティブスケジューリングメカニズムを採用しており、タイムスライスのラウンドロビンスケジューリングとFIFOスケジューリングをサポートしています。

Hongmengカーネルのスレッドには、合計32の優先度(0〜31)があり、最高の優先度は0、最低の優先度は31です。

現在のプロセスの高優先度スレッドは、現在のプロセスの低優先度スレッドをプリエンプトでき、現在のプロセスの低優先度スレッドは、現在のプロセスの高優先度スレッドがブロックまたは終了された後にのみスケジュールできます。

スレッドステータスの説明:

初期化(Init):スレッドを作成しています。

準備完了(Ready):スレッドは準備完了リストにあり、CPUスケジューリングを待機しています。

実行中:スレッドは実行中です。

Blocked:スレッドはブロックされ、中断されています。ブロックされた状態には、保留(ロック、イベント、セマフォなどのため)、一時停止(アクティブな保留)、遅延(遅延ブロック)、保留時間(ロック、イベント、セマフォ時間などのため、長時間待機)があります。

終了(Exit):スレッドは終了し、親スレッドが制御ブロックリソースを再利用するのを待ちます。

図1スレッド状態の移行の概略図。
ここに画像の説明を挿入
公式ドキュメントではスレッドについて説明しており、タスクについては言及されていないことに注意してください。ただし、カーネルソースコードには多くのタスクコードがあり、スレッドコードはほとんどありません。
実際、Hongmengカーネルではタスクはスレッドであり、初心者はこのように理解できますが、両者には違いがあります。
違いはなんですか?管理上の違いであり、タスクはスケジューリングレベルの概念、スレッドはプロセスレベルの概念です。同じ人が異なる管理システムで異なるアイデンティティを持っているのと同じように、男性は異なる視点と機能を持つ子供、父親、夫、またはプログラマーになることができます。

それを証明する方法が一つであることは、見下し続けます。

2. taskコマンドを実行します

Hongmengタスクコマンドの実行結果:
ここに画像の説明を挿入

taskコマンドは、ライフサイクル内の各タスクの実行ステータス、その実行メモリスペース、優先度、タイムスライス、エントリ実行関数、プロセスID、ステータス、およびその他の非常に複雑な情報を検出します。このような複雑な情報を運ぶには、構造が必要です。そして、この構造はLosTaskCB(タスク制御ブロック)です。

3.タスクはどのように見えますか?

LosTaskCBについて説明する前に、公式ドキュメントのタスク状態に対応する定義について説明しましょう。タスクとスレッドは同じものであることがわかります。 

#define OS_TASK_STATUS_INIT         0x0001U
#define OS_TASK_STATUS_READY        0x0002U
#define OS_TASK_STATUS_RUNNING      0x0004U
#define OS_TASK_STATUS_SUSPEND      0x0008U
#define OS_TASK_STATUS_PEND         0x0010U
#define OS_TASK_STATUS_DELAY        0x0020U
#define OS_TASK_STATUS_TIMEOUT      0x0040U
#define OS_TASK_STATUS_PEND_TIME    0x0080U
#define OS_TASK_STATUS_EXIT         0x0100U

LosTaskCBはどのように見えますか?申し訳ありませんが、少し長くなりますが、写真全体を投稿する必要があります。

typedef struct {
    VOID            *stackPointer;      /**< Task stack pointer */
    UINT16          taskStatus;         /**< Task status */
    UINT16          priority;           /**< Task priority */
    UINT16          policy;
    UINT16          timeSlice;          /**< Remaining time slice */
    UINT32          stackSize;          /**< Task stack size */
    UINTPTR         topOfStack;         /**< Task stack top */
    UINT32          taskID;             /**< Task ID */
    TSK_ENTRY_FUNC  taskEntry;          /**< Task entrance function */
    VOID            *joinRetval;        /**< pthread adaption */
    VOID            *taskSem;           /**< Task-held semaphore */
    VOID            *taskMux;           /**< Task-held mutex */
    VOID            *taskEvent;         /**< Task-held event */
    UINTPTR         args[4];            /**< Parameter, of which the maximum number is 4 */
    CHAR            taskName[OS_TCB_NAME_LEN]; /**< Task name */
    LOS_DL_LIST     pendList;           /**< Task pend node */
    LOS_DL_LIST     threadList;         /**< thread list */
    SortLinkList    sortList;           /**< Task sortlink node */
    UINT32          eventMask;          /**< Event mask */
    UINT32          eventMode;          /**< Event mode */
    UINT32          priBitMap;          /**< BitMap for recording the change of task priority,
                                             the priority can not be greater than 31 */
    INT32           errorNo;            /**< Error Num */
    UINT32          signal;             /**< Task signal */
    sig_cb          sig;
#if (LOSCFG_KERNEL_SMP == YES)
    UINT16          currCpu;            /**< CPU core number of this task is running on */
    UINT16          lastCpu;            /**< CPU core number of this task is running on last time */
    UINT16          cpuAffiMask;        /**< CPU affinity mask, support up to 16 cores */
    UINT32          timerCpu;           /**< CPU core number of this task is delayed or pended */
#if (LOSCFG_KERNEL_SMP_TASK_SYNC == YES)
    UINT32          syncSignal;         /**< Synchronization for signal handling */
#endif
#if (LOSCFG_KERNEL_SMP_LOCKDEP == YES)
    LockDep         lockDep;
#endif
#if (LOSCFG_KERNEL_SCHED_STATISTICS == YES)
    SchedStat       schedStat;          /**< Schedule statistics */
#endif
#endif
    UINTPTR         userArea;
    UINTPTR         userMapBase;
    UINT32          userMapSize;        /**< user thread stack size ,real size : userMapSize + USER_STACK_MIN_SIZE */
    UINT32          processID;          /**< Which belong process */
    FutexNode       futex;
    LOS_DL_LIST     joinList;           /**< join list */
    LOS_DL_LIST     lockList;           /**< Hold the lock list */
    UINT32          waitID;             /**< Wait for the PID or GID of the child process */
    UINT16          waitFlag;           /**< The type of child process that is waiting, belonging to a group or parent,
                                             a specific child process, or any child process */
#if (LOSCFG_KERNEL_LITEIPC == YES)
    UINT32          ipcStatus;
    LOS_DL_LIST     msgListHead;
    BOOL            accessMap[LOSCFG_BASE_CORE_TSK_LIMIT];
#endif
} LosTaskCB;

LosTaskCBの構造には多くのコンテンツがありますが、どういう意味ですか?
LosTaskCBは、カーネル内のタスクのIDに相当します。これは、ライフサイクル内の各タスクの操作を反映しています。これはサイクルであるため、状態があり、実行にはメモリ領域が必要であり、カーネルアルゴリズムによってスケジュールされる必要があります。選択したCPUがコードセグメント命令を実行します。CPUが実行する場合は、マルチスレッドであるため、実行を開始する場所を指示する必要がありますが、 1つのCPUのみが常にタスクを切り替える必要がある場合、実行は中断され、実行を再開する必要があります。再開されたタスクの実行が失敗しないようにする方法?これらの問題を明確にする必要があります。

第二に、タスクを管理する方法

1.タスクプールとは何ですか?

先に述べたように、タスクはカーネルスケジューリングレベルの概念であり、スケジューリングアルゴリズムはタスクの規則正しい実行を保証します。スケジューリングアルゴリズムの詳細については、フォローアップで説明します。
非常に多くのタスクを管理および実行する方法は?管理はタスクプールとレディキューに依存し、実行はスケジューリングアルゴリズムに依存します。
コードは次のとおりです(OsTaskInit)。

LITE_OS_SEC_TEXT_INIT UINT32 OsTaskInit(VOID)
{
   
    UINT32 index;
    UINT32 ret;
    UINT32 size;

    g_taskMaxNum = LOSCFG_BASE_CORE_TSK_LIMIT;//任务池中最多默认128个,可谓铁打的任务池流水的线程
    size = (g_taskMaxNum + 1) * sizeof(LosTaskCB);
    /* * This memory is resident memory and is used to save the system resources * of task control block and will not be freed. */
    g_taskCBArray = (LosTaskCB *)LOS_MemAlloc(m_aucSysMem0, size);//任务池 常驻内存,不被释放
    if (g_taskCBArray == NULL) {
   
        return LOS_ERRNO_TSK_NO_MEMORY;
    }
    (VOID)memset_s(g_taskCBArray, size, 0, size);

    LOS_ListInit(&g_losFreeTask);//空闲任务链表
    LOS_ListInit(&g_taskRecyleList);//需回收任务链表
    for (index = 0; index < g_taskMaxNum; index++) {
   
        g_taskCBArray[index].taskStatus = OS_TASK_STATUS_UNUSED;
        g_taskCBArray[index].taskID = index;//任务ID最大默认127
        LOS_ListTailInsert(&g_losFreeTask, &g_taskCBArray[index].pendList);//都插入空闲任务链表
    }

    ret = OsPriQueueInit();//创建32个任务优先级队列,即32个双向循环链表
    if (ret != LOS_OK) {
   
        return LOS_ERRNO_TSK_NO_MEMORY;
    }

    /* init sortlink for each core */
    for (index = 0; index < LOSCFG_KERNEL_CORE_NUM; index++) {
   
        ret = OsSortLinkInit(&g_percpu[index].taskSortLink);//每个CPU内核都有一个执行任务链表
        if (ret != LOS_OK) {
   
            return LOS_ERRNO_TSK_NO_MEMORY;
        }
    }
    return LOS_OK;
}

g_taskCBArrayはタスクプールであり、128のタスクがデフォルトで作成され、メモリに常駐し、解放されません。
g_losFreeTaskは、リンクされたアイドルタスクのリストです。タスクを作成する場合は、ここにアクセスして無料のタスクを申請してください。使い切ると、再利用され、後続のアプリケーションで引き続き使用されます。
g_taskRecyleListは、出口タスクのリサイクル専用のリサイクルタスクのリストです。タスクによって占有されたリソースは、確認されて返された後、完全に削除されます。従業員の辞任と同様に、辞任キューとプロセスが必要です。コンピュータとメールボックスが返される必要があります。そして他の操作。

2.レディキューの問題

CPUの実行速度は非常に高速です。Hongmengカーネルのデフォルトのタイムスライスは10msです。リソースは限られているため、多くのタスク間で切り替えを行う必要があります。したがって、CPUはタスクを待機することを許可してはなりません。CPUは、会社の最大のリーダー、以下の多くの部門などです。指導者達が承認して食べに来る。誰もがリーダーを待っている、リーダーがあなたを待つ理由はないので、事前に作業を準備する必要があり、各部門の優先順位が異なるため、各部門にはタスクキューが必要です。タスクキューはリーダーに配置され、直接処理できます。タスク、準備ができていない場合は入れないでください。これは、CPUのために事前に準備された食べ物です。
これがレディキューの原則です。スレッドの優先度はデフォルトで32であるため、プロセスとスレッドの両方に32のレディキューがあり、各キューは同じ優先度のタスクを配置します。
ソースコードを見てみましょう

#define OS_PRIORITY_QUEUE_NUM 32
UINT32 OsPriQueueInit(VOID)
{
   
    UINT32 priority;

    /* system resident resource */
    g_priQueueList = (LOS_DL_LIST *)LOS_MemAlloc(m_aucSysMem0, (OS_PRIORITY_QUEUE_NUM * sizeof(LOS_DL_LIST)));//常驻内存,不被释放
    if (g_priQueueList == NULL) {
   
        return LOS_NOK;
    }

    for (priority = 0; priority < OS_PRIORITY_QUEUE_NUM; ++priority) {
   
        LOS_ListInit(&g_priQueueList[priority]);
    }
    return LOS_OK;
}

g_priQueueListのメモリ割り当て(32 LOS_DL_LIST)に注意してください。LOS_DL_LISTの魔法の効果を覚えていますか?わからない場合は、Hongmeng システムソースコード分析(総合カタログ)に移動してください 

3.タスクスタックの問題

各タスクは独立して開かれ、タスクも互いに独立しています。タスク間の通信はIPCを介して行われます。ここでの「独立」とは、各タスクに独自の動作環境スタックスペース(タスクスタック、スタックと呼ばれる)があることを意味しますスペースに格納される情報には、ローカル変数、レジスター、関数パラメーター、関数戻りアドレスなどが含まれます。
ただし、システムにはCPUが1つしかなく、タスクは独立しています。スケジューリングの本質は、CPUが新しいタスクを実行し、古いタスクがどこで中断されるかです。はっきりしていません、ランダムです。では、古いタスクが、再度スケジュールされたときに、前回中断された場所から引き続き再生できるようにする方法を教えてください。

答えは:タスクコンテキスト、CPUには多数のレジスターがあります。CPU動作の本質は、これらのレジスターの値が常に変化していることです。これらの値が切り替え時に保存され、その後復元される限り、タスクの継続的な実行が保証され、ユーザーが離れることはありません。知覚。

これは、私たちが若いころにピーカブーゲームをプレイしたときと同じです。ゲームの途中で両親に邪魔され、コールバックして食事をしました。午後も引き続きプレイしました。張山、ツリーに戻って非表示にする必要があります。LiSiはベッドの下に隠れ続けました。 5番目は、チャンサンをキャッチし、リーシーがキャッチを続け、最初にシーンを復元し、次にプレイを続けることです。これは全員の場所を記録し、役割情報はタスクコンテキストです。実際、タスクは繰り返し中断されることになっており、Hongmengカーネルは20msのタスク実行時間を与えます。つまり、マルチタスクの競争の場合、1秒に最大50回の切り替えが必要になります。


タスクコンテキスト(TaskContext)とは何ですか?まだソースコードを直接見てください

/* The size of this structure must be smaller than or equal to the size specified by OS_TSK_STACK_ALIGN (16 bytes). */
typedef struct {
   
#if !defined(LOSCFG_ARCH_FPU_DISABLE)
    UINT64 D[FP_REGS_NUM]; /* D0-D31 */
    UINT32 regFPSCR;       /* FPSCR */
    UINT32 regFPEXC;       /* FPEXC */
#endif
    UINT32 resved;          /* It's stack 8 aligned */
    UINT32 regPSR;
    UINT32 R[GEN_REGS_NUM]; /* R0-R12 */
    UINT32 SP;              /* R13 */
    UINT32 LR;              /* R14 */
    UINT32 PC;              /* R15 */
} TaskContext;

基本的にはCPUレジスタのリカバリフィールド値であることがわかり、各レジ​​スタの具体的な機能はインターネットで確認でき、後日紹介する特別記事があります。ここに3つのレジスタSP、LR、PCがあります

LRに
は2つの目的があります。1つ目はサブルーチンの戻りアドレスを保存することです。BL、BX、BLXなどのジャンプ命令が呼び出されると、戻りアドレスは自動的にLRに保存されます。2つ目は、例外が発生したときに例外戻りアドレスを保存することです。

PC(プログラムカウンター)
は、プログラムの実行アドレスを保存するために使用されるプログラムカウンターです。ARMの3ステージパイプラインアーキテクチャでは、プログラムパイプラインには、アドレス指定、デコード、実行の3つのステージが含まれます。PCは、現在のアドレスのプログラムアドレスを指します。 、32ビットARMでは、デコードアドレス(解析されてまだ実行されていないプログラム)はPC-4であり、実行アドレス(現在実行中のプログラムのアドレス)はPC-8です。突然割り込みが発生すると、PCが保存されますのアドレス。

SPの
各例外モードには、独自の独立したr13があり、これは通常、例外モード専用のスタックを指します。ARMが例外モードに入ると、プログラムは汎用レジスターをスタックにプッシュし、戻り時にスタックをポップできます。さまざまなモードでのプログラムの状態の完全性。

4.タスクスタックの初期化

タスクスタックの初期化は、タスクコンテキストの初期化です。タスクが実行を開始していないため、コンテキスト以外のコンテンツはありません。コンテキストはスタックの一番下に格納されていることに注意してください。

3、タスク関数セット

LITE_OS_SEC_TEXT_INIT VOID *OsTaskStackInit(UINT32 taskID, UINT32 stackSize, VOID *topStack, BOOL initFlag)
{
   
    UINT32 index = 1;
    TaskContext *taskContext = NULL;

    if (initFlag == TRUE) {
   
        OsStackInit(topStack, stackSize);
    }
    taskContext = (TaskContext *)(((UINTPTR)topStack + stackSize) - sizeof(TaskContext));//注意看上下文将存放在栈的底部

    /* initialize the task context */
#ifdef LOSCFG_GDB
    taskContext->PC = (UINTPTR)OsTaskEntrySetupLoopFrame;
#else
    taskContext->PC = (UINTPTR)OsTaskEntry;//程序计数器,CPU首次执行task时跑的第一条指令位置
#endif
    taskContext->LR = (UINTPTR)OsTaskExit;  /* LR should be kept, to distinguish it's THUMB or ARM instruction */
    taskContext->resved = 0x0;
    taskContext->R[0] = taskID;             /* R0 */
    taskContext->R[index++] = 0x01010101;   /* R1, 0x01010101 : reg initialed magic word */
    for (; index < GEN_REGS_NUM; index++) {
   //R2 - R12的初始化很有意思,为什么要这么做?
        taskContext->R[index] = taskContext->R[index - 1] + taskContext->R[1]; /* R2 - R12 */
    }

#ifdef LOSCFG_INTERWORK_THUMB // 16位模式
    taskContext->regPSR = PSR_MODE_SVC_THUMB; /* CPSR (Enable IRQ and FIQ interrupts, THUMNB-mode) */
#else
    taskContext->regPSR = PSR_MODE_SVC_ARM;   /* CPSR (Enable IRQ and FIQ interrupts, ARM-mode) */
#endif

#if !defined(LOSCFG_ARCH_FPU_DISABLE)
    /* 0xAAA0000000000000LL : float reg initialed magic word */
    for (index = 0; index < FP_REGS_NUM; index++) {
   
        taskContext->D[index] = 0xAAA0000000000000LL + index; /* D0 - D31 */
    }
    taskContext->regFPSCR = 0;
    taskContext->regFPEXC = FP_EN;
#endif

    return (VOID *)taskContext;
}

1.使用シナリオと機能

タスクの作成後、カーネルは、タスクスケジューリングのロック、タスクスケジューリングのロック解除、一時停止、再開、遅延などの操作を実行できます。同時に、タスクの優先順位を設定し、タスクの優先順位を取得することもできます。タスクが終了すると、現在のタスクの自己削除操作が実行されます。
Huawei LiteOSシステムのタスク管理モジュールは、ユーザーに次の機能を提供します。

関数分類 インターフェース名 解説
タスクの作成と削除 LOS_TaskCreateOnly タスクを作成し、タスクをスケジュールせずに中断状態にします。
  LOS_TaskCreate タスクを作成し、タスクを準備完了状態にして、スケジュールします。
  LOS_TaskDelete 指定されたタスクを削除します。
タスク状態管理 LOS_TaskResume 中断されたタスクを再開します。
  LOS_TaskSuspend 指定されたタスクを一時停止します。
  LOS_TaskDelay タスクが遅れています。
  LOS_TaskYield 明示的な分散化、指定された優先度のタスクスケジューリング順序を調整します。
タスクスケジューリング制御 LOS_TaskLock タスクのスケジュールをロックします。
  LOS_TaskUnlock タスクのスケジュールを解除します。
タスク優先制御 LOS_CurTaskPriSet 現在のタスクの優先度を設定します。
  LOS_TaskPriSet 指定したタスクの優先度を設定します。
  LOS_TaskPriGet 指定されたタスクの優先度を取得します。
タスク情報取得 LOS_CurTaskIDGet 現在のタスクのIDを取得します。
  LOS_TaskInfoGet 指定したタスクの優先度を設定します。
  LOS_TaskPriGet 指定されたタスクに関する情報を取得します。
  LOS_TaskStatusGet 指定されたタスクのステータスを取得します。
  LOS_TaskNameGet 指定されたタスクの名前を取得します。
  LOS_TaskInfoMonitor すべてのタスクを監視し、すべてのタスクに関する情報を取得します。
  LOS_NextTaskIDGet スケジュールするタスクのIDを取得します。

2.タスクを作成するプロセス

タスクを作成する前に、別の構造体tagTskInitParamについて学びます

typedef struct tagTskInitParam {
   
    TSK_ENTRY_FUNC  pfnTaskEntry;  /**< Task entrance function */
    UINT16          usTaskPrio;    /**< Task priority */
    UINT16          policy;        /**< Task policy */
    UINTPTR         auwArgs[4];    /**< Task parameters, of which the maximum number is four */
    UINT32          uwStackSize;   /**< Task stack size */
    CHAR            *pcName;       /**< Task name */
#if (LOSCFG_KERNEL_SMP == YES)
    UINT16          usCpuAffiMask; /**< Task cpu affinity mask */
#endif
    UINT32          uwResved;      /**< It is automatically deleted if set to LOS_TASK_STATUS_DETACHED. It is unable to be deleted if set to 0. */
    UINT16          consoleID;     /**< The console id of task belongs */
    UINT32          processID;
    UserTaskParam   userParam;
} TSK_INIT_PARAM_S;

これらの初期化パラメーターは、タスクの公開された初期パラメーターでありpfnTaskEntry 对java来说就是你new进程的run(),、上位ユーザーが提供する必要があります。

例を見てみましょう:シェルでpingコマンドを入力して、作成プロセスを確認します

u32_t osShellPing(int argc, const char **argv)
{
   
    int ret;
    u32_t i = 0;
    u32_t count = 0;
    int count_set = 0;
    u32_t interval = 1000; /* default ping interval */
    u32_t data_len = 48; /* default data length */
    ip4_addr_t dst_ipaddr;
    TSK_INIT_PARAM_S stPingTask;
    // ...省去一些中间代码
    /* start one task if ping forever or ping count greater than 60 */
    if (count == 0 || count > LWIP_SHELL_CMD_PING_RETRY_TIMES) {
   
        if (ping_taskid > 0) {
   
            PRINTK("Ping task already running and only support one now\n");
            return LOS_NOK;
        }
        stPingTask.pfnTaskEntry = (TSK_ENTRY_FUNC)ping_cmd;//线程的执行函数
        stPingTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;//0x4000 = 16K 
        stPingTask.pcName = "ping_task";
        stPingTask.usTaskPrio = 8; /* higher than shell 优先级高于10,属于内核态线程*/ 
        stPingTask.uwResved = LOS_TASK_STATUS_DETACHED;
        stPingTask.auwArgs[0] = dst_ipaddr.addr; /* network order */
        stPingTask.auwArgs[1] = count;
        stPingTask.auwArgs[2] = interval;
        stPingTask.auwArgs[3] = data_len;
        ret = LOS_TaskCreate((UINT32 *)(&ping_taskid), &stPingTask);
    }
	// ...
    return LOS_OK;
ping_error:
    lwip_ping_usage();
    return LOS_NOK;
}

pingのスケジューリング優先順位はシェルの優先順位よりも高い8であることがわかりましたが、シェルの優先順位は何ですか?答えは:ソースコードが9であることを確認してください

LITE_OS_SEC_TEXT_MINOR UINT32 ShellTaskInit(ShellCB *shellCB)
{
   
    CHAR *name = NULL;
    TSK_INIT_PARAM_S initParam = {
   0};
    if (shellCB->consoleID == CONSOLE_SERIAL) {
   
        name = SERIAL_SHELL_TASK_NAME;
    } else if (shellCB->consoleID == CONSOLE_TELNET) {
   
        name = TELNET_SHELL_TASK_NAME;
    } else {
   
        return LOS_NOK;
    }
    initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ShellTask;
    initParam.usTaskPrio   = 9; /* 9:shell task priority */
    initParam.auwArgs[0]   = (UINTPTR)shellCB;
    initParam.uwStackSize  = 0x3000;
    initParam.pcName       = name;
    initParam.uwResved     = LOS_TASK_STATUS_DETACHED;
    (VOID)LOS_EventInit(&shellCB->shellEvent);
    return LOS_TaskCreate(&shellCB->shellTaskHandle, &initParam);
}

フォローアップのシェルの詳細な導入に引き続き注意を払ってください。
前提条件を理解した後は、タスクを段階的に作成する方法、プロセスにバインドする方法、スケジューリング準備キューに参加する方法、またはソースコードを引き続き確認する方法に依存します

LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreate(UINT32 *taskID, TSK_INIT_PARAM_S *initParam)
{
    UINT32 ret;
    UINT32 intSave;
    LosTaskCB *taskCB = NULL;

    if (initParam == NULL) {
        return LOS_ERRNO_TSK_PTR_NULL;
    }

    if (OS_INT_ACTIVE) {
        return LOS_ERRNO_TSK_YIELD_IN_INT;
    }

    if (initParam->uwResved & OS_TASK_FLAG_IDLEFLAG) {
        initParam->processID = OsGetIdleProcessID();
    } else if (OsProcessIsUserMode(OsCurrProcessGet())) {
        initParam->processID = OsGetKernelInitProcessID();
    } else {
        initParam->processID = OsCurrProcessGet()->processID;
    }
    initParam->uwResved &= ~OS_TASK_FLAG_IDLEFLAG;
    initParam->uwResved &= ~OS_TASK_FLAG_PTHREAD_JOIN;
    if (initParam->uwResved & LOS_TASK_STATUS_DETACHED) {
        initParam->uwResved = OS_TASK_FLAG_DETACHED;
    }

    ret = LOS_TaskCreateOnly(taskID, initParam);
    if (ret != LOS_OK) {
        return ret;
    }
    taskCB = OS_TCB_FROM_TID(*taskID);

    SCHEDULER_LOCK(intSave);
    taskCB->taskStatus &= ~OS_TASK_STATUS_INIT;
    OS_TASK_SCHED_QUEUE_ENQUEUE(taskCB, 0);
    SCHEDULER_UNLOCK(intSave);

    /* in case created task not running on this core,
       schedule or not depends on other schedulers status. */
    LOS_MpSchedule(OS_MP_CPU_ALL);
    if (OS_SCHEDULER_ACTIVE) {
        LOS_Schedule();//*kyf 任务创建完了 申请调度
    }

    return LOS_OK;
}

これまでのところ、作成は完了しており、すべて準備が整っています。ソースコードがLOS_Schedule()に最終的に適用されました。Hongmengの​​スケジューリングメソッドはプリエンプティブであるため、このタスクのタスク優先度は他の準備キューよりも高く、次にタスクが実行されますそれでおしまい!

3.言及されていないタスク/スレッドパーツの重要な内容は何ですか?

メモリの割り当て方法、スレッド間の通信方法、および動作中のスタックの実行方法メモリに関するフォローアップトークの後、IPCパーツは分析のために分解されます。

詳細については、Hongmeng System Source Code Analysis(General Catalog)をクリックしてください。 

 

おすすめ

転載: blog.csdn.net/kuangyufei/article/details/108621428