RT-threadオペレーティングシステムスレッド作成プロセスの詳細


RT-Threadオペレーティングシステムのスレッドには、静的スレッドと動的スレッドの2つがあります.次に、RT-Threadソースコードを使用して、スレッドがどのように作成されたのか、およびこの2つのスレッドの違いを説明します.
静的スレッドの作成
まず、RT-Threadの静的スレッド作成に関するソースコードを貼り付けます.
rt_thread_init
/**
 * This function will initialize a thread, normally it's used to initialize a
 * static thread object.
 *
 * @param thread the static thread object
 * @param name the name of thread, which shall be unique
 * @param entry the entry function of thread
 * @param parameter the parameter of thread enter function
 * @param stack_start the start address of thread stack
 * @param stack_size the size of thread stack
 * @param priority the priority of thread
 * @param tick the time slice if there are same priority thread
 *
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
 */
rt_err_t rt_thread_init(struct rt_thread *thread,
                        const char       *name,
                        void (*entry)(void *parameter),
                        void             *parameter,
                        void             *stack_start,
                        rt_uint32_t       stack_size,
                        rt_uint8_t        priority,
                        rt_uint32_t       tick)
{
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
    RT_ASSERT(stack_start != RT_NULL);

    /* init thread object */
    rt_object_init((rt_object_t)thread, RT_Object_Class_Thread, name);

    return _rt_thread_init(thread,
                           name,
                           entry,
                           parameter,
                           stack_start,
                           stack_size,
                           priority,
                           tick);
}


コードの30行目の文は、指定されたオブジェクト名(3番目のパラメータ)によってスレッドオブジェクトに割り当てられ、指定されたオブジェクトタイプ(2番目のパラメータ)によってオブジェクトシステム管理(情報リスト)に追加されるスレッドを初期化する役割を果たすスレッドであることがわかります.rt_object_initソースコード(無関係成分を削除):
/**
 * This function will initialize an object and add it to object system
 * management.
 *
 * @param object the specified object to be initialized.
 * @param type the object type.
 * @param name the object name. In system, the object's name must be unique.
 */
void rt_object_init(struct rt_object         *object,
                    enum rt_object_class_type type,
                    const char               *name)
{
    register rt_base_t temp;
    struct rt_object_information *information;

    /* get object information */
    information = rt_object_get_information(type);
    RT_ASSERT(information != RT_NULL);

    /* initialize object's parameters */

    /* set object type to static */
    object->type = type | RT_Object_Class_Static;

    /* copy name */
    rt_strncpy(object->name, name, RT_NAME_MAX);

    RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object));

    /* lock interrupt */
    temp = rt_hw_interrupt_disable();

    {
        /* insert object into information object list */
        rt_list_insert_after(&(information->object_list), &(object->list));
    }

    /* unlock interrupt */
    rt_hw_interrupt_enable(temp);
}

rt_object_initでスレッドを初期化した後、32行目にrt_object_init関数の値が返されます.この関数は静的スレッド作成関数_rt_thread_initとよく似ています.実は静的スレッド作成関数rt_thread_initはシェルであり、そのコアコードこそこのrt_thread_init関数である.
前の関数_rt_thread_initによって、スレッドに名前が付けられ、オブジェクトシステム管理に組み込まれました.rt_object_initの関数を分析する必要があります._rt_thread_init関数ソースコード(無関係成分を削除):
static rt_err_t _rt_thread_init(struct rt_thread *thread,
                                const char       *name,
                                void (*entry)(void *parameter),
                                void             *parameter,
                                void             *stack_start,
                                rt_uint32_t       stack_size,
                                rt_uint8_t        priority,
                                rt_uint32_t       tick)
{
    /* init thread list */
    rt_list_init(&(thread->tlist));

    thread->entry = (void *)entry;
    thread->parameter = parameter;

    /* stack init */
    thread->stack_addr = stack_start;
    thread->stack_size = stack_size;

    /* init thread stack */
    rt_memset(thread->stack_addr, '#', thread->stack_size);

    thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
                                          (void *)((char *)thread->stack_addr + thread->stack_size - sizeof(rt_ubase_t)),
                                          (void *)rt_thread_exit);


    /* priority init */
    RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX);
    thread->init_priority    = priority;
    thread->current_priority = priority;

    thread->number_mask = 0;

    /* tick init */
    thread->init_tick      = tick;
    thread->remaining_tick = tick;

    /* error and flags */
    thread->error = RT_EOK;
    thread->stat  = RT_THREAD_INIT;

    /* initialize cleanup function and user data */
    thread->cleanup   = 0;
    thread->user_data = 0;

    /* init thread timer */
    rt_timer_init(&(thread->thread_timer),
                  thread->name,
                  rt_thread_timeout,
                  thread,
                  0,
                  RT_TIMER_FLAG_ONE_SHOT);

    RT_OBJECT_HOOK_CALL(rt_thread_inited_hook, (thread));

    return RT_EOK;
}
_rt_thread_init関数ソースコードの23行目の_rt_thread_init関数は、制御ブロックからスレッドに関する情報(すなわち、スレッドスタック)を格納するための構造体を定義する役割を果たし、ソースコードは以下の通りである.rt_hw_stack_init関数ソースコード(無関係成分を削除):
rt_uint8_t *rt_hw_stack_init(void       *tentry,
                             void       *parameter,
                             rt_uint8_t *stack_addr,
                             void       *texit)
{
    struct stack_frame *stack_frame;
    rt_uint8_t         *stk;
    unsigned long       i;

    stk  = stack_addr + sizeof(rt_uint32_t);
    stk  = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8);
    stk -= sizeof(struct stack_frame);

    stack_frame = (struct stack_frame *)stk;

    /* init all register */
    for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++)
    {
        ((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef;
    }

    stack_frame->exception_stack_frame.r0  = (unsigned long)parameter; /* r0 : argument */
    stack_frame->exception_stack_frame.r1  = 0;                        /* r1 */
    stack_frame->exception_stack_frame.r2  = 0;                        /* r2 */
    stack_frame->exception_stack_frame.r3  = 0;                        /* r3 */
    stack_frame->exception_stack_frame.r12 = 0;                        /* r12 */
    stack_frame->exception_stack_frame.lr  = (unsigned long)texit;     /* lr */
    stack_frame->exception_stack_frame.pc  = (unsigned long)tentry;    /* entry point, pc */
    stack_frame->exception_stack_frame.psr = 0x01000000L;              /* PSR */

    /* return task's current stack address */
    return stk;
}

rt_hw_stack_init関数ソースコードの10行目は、スタックの開始アドレスに32ビットを加えて末尾アドレスとすることに相当する.11行目のrt_hw_stack_init関数は、指定された幅の整列の下数を返す役割を果たし、例えばRT_ALIGN_DOWNは12を返す.12行目は、スタックをフォーマットして整列した後、スタック構造が占有する空間を減算します.すなわち、このときのstkはスレッドスタックの開始アドレスに等しくなり、stkに戻ります.
このときRT_ALIGN_DOWN(13, 4)関数23行目に戻り、上述した説明から、このときスレッドのスタックポインタspは_rt_thread_init関数が返すstk、すなわちstack_を指すことがわかるframeの開始アドレス.48行目のrt_hw_stack_init関数は、通常、静的タイマオブジェクトを初期化するタイマを初期化する役割を果たす.このタイマーはタイムスライスカウントとして機能する
それ以外のコードは、構成制御ブロックとして機能します.
最後のrt_timer_initはカーネルオブジェクトフック関数です.
ダイナミックスレッドの作成
rt_thread_create
#ifdef RT_USING_HEAP
/**
 * This function will create a thread object and allocate thread object memory
 * and stack.
 *
 * @param name the name of thread, which shall be unique
 * @param entry the entry function of thread
 * @param parameter the parameter of thread enter function
 * @param stack_size the size of thread stack
 * @param priority the priority of thread
 * @param tick the time slice if there are same priority thread
 *
 * @return the created thread object
 */
rt_thread_t rt_thread_create(const char *name,
                             void (*entry)(void *parameter),
                             void       *parameter,
                             rt_uint32_t stack_size,
                             rt_uint8_t  priority,
                             rt_uint32_t tick)
{
    struct rt_thread *thread;
    void *stack_start;

    thread = (struct rt_thread *)rt_object_allocate(RT_Object_Class_Thread,
                                                    name);
    if (thread == RT_NULL)
        return RT_NULL;

    stack_start = (void *)RT_KERNEL_MALLOC(stack_size);
    if (stack_start == RT_NULL)
    {
        /* allocate stack failure */
        rt_object_delete((rt_object_t)thread);

        return RT_NULL;
    }

    _rt_thread_init(thread,
                    name,
                    entry,
                    parameter,
                    stack_start,
                    stack_size,
                    priority,
                    tick);

    return thread;
}


静的スレッドの作成過程を理解すると,動的スレッドの作成過程も容易に理解できる.
動的スレッドの作成と静的スレッドの作成の違いは、動的スレッドがスレッド制御ブロックとスレッドスタックを手動で定義する必要はありませんが、1つのスレッドが有線制御ブロックとスレッドスタックを常に必要とするように実行できることです.動的スレッドの作成は、システムを利用してスレッド制御ブロックとスレッドスタックとして動的メモリを作成することです.
以上のコードの22行目から37行目まで、このコードの役割は、まず1つの制御ブロックポインタと1つのスタックポインタを定義し、その後、RT_OBJECT_HOOK_CALL関数を介してシステムリソースから1つのオブジェクトを割り当ててスレッド制御ブロック情報を格納し、その後、rt_object_allocate関数を介してカーネルに動的メモリを要求してスレッド実行リソースを格納することであることが容易に分かる.
その後、コードは静的スレッド作成プロセスと同じになります.
静的スレッドと動的スレッドのそれぞれの作成過程を解析したところ,静的スレッドと動的スレッドは本質的に同じであるが,静的スレッドのスレッド制御ブロックとスレッドスタックはユーザがカスタマイズした静的メモリ空間に格納され,動的スレッドのスレッド制御ブロックとスレッドスタックはシステムによって割り当てられた動的メモリ空間であることが分かった.
スレッドを作成する過程からも分かるように、スレッドを作成します.主な任務は、スレッドスタックポインタを定義したスタックに向け、タイマをオンにし、他の制御ブロックパラメータを構成することです.