Research on RTOS kernel technology: thread switching and running

preface

The primary role of RTOS is to switch threads, just like interrupt processing logic. After interrupt, handle other things. After processing, return to normal and continue execution.

Thread switching

RT thread kernel code is used here to verify

The main functions of thread switching are written in assembly language. I think we will continue to deeply study how to implement each function later.

Suppose we have a thread switching function, how to switch a thread? If you call other functions directly in a [stack space], it is also switching.

Here, the management of thread stack is used to realize the switching between several threads, and the priority scheduling (SWITCHING) logic is not realized for the time being. That is, simple implementation: [switch to which thread you want to switch to]

Engineering construction

Here you need to implement the RTOS kernel related code

For the cpuport part, you can directly use the RT thread kernel source code. I use the STM32F103 platform here, so

rt-thread\libcpu\arm\cortex-m3

Directory, copy the whole to your own test project, and manually add Keil MDK5 project.

Here you only need to comment out: context_ rvds. In S: rt_hw_hard_fault_exception, i.e. not used temporarily: hardfault_ Override of handler.

The following kernel files can be compiled normally without all copies.

Definition of type and data structure: rtdef h

/* rtdef.h Type, data structure definition */

#ifndef __RTDEF_H__
#define __RTDEF_H__

typedef signed char         rt_int8_t;
typedef signed short        rt_int16_t;
typedef signed int          rt_int32_t;
typedef unsigned char       rt_uint8_t;
typedef unsigned short      rt_uint16_t;
typedef unsigned int        rt_uint32_t;
typedef int                 rt_bool_t;
typedef long                rt_base_t;
typedef unsigned long       rt_ubase_t;
typedef rt_base_t           rt_err_t;
typedef rt_uint32_t         rt_tick_t;

#define RT_TRUE             1
#define RT_FALSE            0

#define RT_EOK              0
#define RT_ERROR            1

#define ALIGN(n)                     __attribute__((aligned(n)))

#define RT_ALIGN(size, align)       (((size) + (align) - 1) & ~ ((align) - 1))
#define RT_ALIGN_DOWN(size, align)  ((size) & ~ ((align) - 1))

#define RT_NULL             (0)

struct rt_thread
{
    /* stack point and entry */
    void                *sp;
    void                *entry;
    void                *parameter;
    void                *stack_addr;
    rt_uint32_t         stack_size;
};

#endif

rthw.h

Interface switches related to hardware migration, interrupt stack initialization, etc. this part of the interface mainly comes from the migration file, such as context_rvds.S assembly file.

/* rthw.h Hardware transplantation related interface switch, interrupt stack initialization, etc */

#ifndef __RT_HW_H__
#define __RT_HW_H__

#include <rtthread.h>

rt_base_t rt_hw_interrupt_disable(void);
void rt_hw_interrupt_enable(rt_base_t level);

void rt_hw_context_switch_to(rt_uint32_t to);
void rt_hw_context_switch(rt_uint32_t from, rt_uint32_t to);

rt_uint8_t *rt_hw_stack_init(void       *tentry,
                             void       *parameter,
                             rt_uint8_t *stack_addr,
                             void       *texit);

#endif

rtthread.h file

For the main header file, you only need to implement the inclusion of other header files and the interface between thread initialization and scheduling.

/* rtthread.h Main header file */

#ifndef __RTTHREAD_H__
#define __RTTHREAD_H__

#include <string.h>

#include <rtdef.h>
#include <rtconfig.h>
#include <rthw.h>

void rt_system_scheduler_start(struct rt_thread *to_thread);

void rt_thread_init(struct rt_thread *thread,
                    void (*entry)(void *param),
                    void *param,
                    void *stack_start,
                    rt_uint32_t stack_size);

#endif

thread.c

Function implementation: thread initialization

/* thread.c  Thread related functions are implemented, such as initialization */
#include <rtthread.h>

void rt_thread_init(struct rt_thread *thread,
                    void (*entry)(void *param),
                    void *param,
                    void *stack_start,
                    rt_uint32_t stack_size)
{
    thread->entry = (void *)entry;
    thread->parameter = param;
    thread->stack_addr = stack_start;
    thread->stack_size = stack_size;

    memset(thread->stack_addr, '#', thread->stack_size);

    thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
                    (rt_uint8_t *)((char *)thread->stack_addr + thread->stack_size - sizeof(rt_uint32_t)),
                    RT_NULL);
}

Scheduler: scheduler c

Only the initial enabling thread is implemented here.

/* scheduler.c Manual scheduling is implemented here */

#include <rtthread.h>

void rt_system_scheduler_start(struct rt_thread *to_thread)
{
    rt_hw_context_switch_to((rt_ubase_t)&to_thread->sp);
}

User test program

task_test.c. It is mainly used to test the definition and initialization of threads and the implementation of thread switching logic

/* task_test.c */

#include <rtthread.h>
#include <board.h>
#include <string.h>
#include <rthw.h>
//#include "printk.h"
#include "task_test.h"

#define TASK1_STACK_SIZE        1024
#define TASK2_STACK_SIZE        1024
#define TASK3_STACK_SIZE        1024
#define TASK4_STACK_SIZE        1024

ALIGN(RT_ALIGN_SIZE)

struct rt_thread t4;
struct rt_thread t3;
struct rt_thread t2;
struct rt_thread t1;

static uint8_t task4_stack[TASK3_STACK_SIZE];
static uint8_t task3_stack[TASK3_STACK_SIZE];
static uint8_t task2_stack[TASK2_STACK_SIZE];
static uint8_t task1_stack[TASK1_STACK_SIZE];

void task1_entry(void *param)
{
    rt_ubase_t level;
    static rt_ubase_t cnt = 0x00;

    while (1)
    {
        //printk("task1 run.\r\n");
        HAL_Delay(3000);
        level = rt_hw_interrupt_disable();
        cnt++;
        rt_hw_interrupt_enable(level);
        if (cnt >= 3)
        {
            cnt = 0;
            //printk("1->2\r\n");
            task1_to_task2();
        }
    }
}

void task2_entry(void *param)
{
    rt_ubase_t level;
    static rt_ubase_t cnt = 0x00;

    while (1)
    {
        //printk("task2 run.\r\n");
        HAL_Delay(3000);
        level = rt_hw_interrupt_disable();
        cnt++;
        rt_hw_interrupt_enable(level);
        if (cnt >= 3)
        {
            cnt = 0;
            //printk("2->3\r\n");
            task2_to_task3();
        }
    }
}

void task3_entry(void *param)
{
    rt_ubase_t level;
    static rt_ubase_t cnt = 0x00;

    while (1)
    {
        //printk("task3 run.\r\n");
        HAL_Delay(3000);
        level = rt_hw_interrupt_disable();
        cnt++;
        rt_hw_interrupt_enable(level);
        if (cnt >= 3)
        {
            cnt = 0;
            //printk("3->1\r\n");
            task3_to_task1();
        }
    }
}

void task4_entry(void *param)
{
    rt_ubase_t level;
    static rt_ubase_t cnt = 0x00;

    while (1)
    {
        //printk("task4 run.\r\n");
        HAL_Delay(3000);
        level = rt_hw_interrupt_disable();
        cnt++;
        rt_hw_interrupt_enable(level);
        if (cnt >= 3)
        {
            cnt = 0;
            //printk("4->1\r\n");
            task4_to_task1();
        }
    }
}

void task1_init(void)
{
    rt_thread_init(&t1, task1_entry, RT_NULL, task1_stack, TASK1_STACK_SIZE);
}

void task2_init(void)
{
    rt_thread_init(&t2, task2_entry, RT_NULL, task2_stack, TASK2_STACK_SIZE);
}

void task3_init(void)
{
    rt_thread_init(&t3, task3_entry, RT_NULL, task3_stack, TASK3_STACK_SIZE);
}

void task4_init(void)
{
    rt_thread_init(&t4, task4_entry, RT_NULL, task4_stack, TASK4_STACK_SIZE);
}

void task1_run(void)
{
    rt_system_scheduler_start(&t1);
}

void task2_run(void)
{
    rt_system_scheduler_start(&t2);
}

void task3_run(void)
{
    rt_system_scheduler_start(&t3);
}

void task4_run(void)
{
    rt_system_scheduler_start(&t4);
}

void task1_to_task2(void)
{
    rt_hw_context_switch((rt_ubase_t)&t1.sp,
        (rt_ubase_t)&t2.sp);
}

void task2_to_task3(void)
{
    rt_hw_context_switch((rt_ubase_t)&t2.sp,
        (rt_ubase_t)&t3.sp);
}

void task3_to_task1(void)
{
    rt_hw_context_switch((rt_ubase_t)&t3.sp,
        (rt_ubase_t)&t1.sp);
}

void task4_to_task1(void)
{
    rt_hw_context_switch((rt_ubase_t)&t4.sp,
        (rt_ubase_t)&t1.sp);
}

task_test.h

/* task_test.h */

#ifndef __TASK_TEST_H__
#define __TASK_TEST_H__

void task1_init(void);
void task2_init(void);
void task3_init(void);
void task4_init(void);

void task1_run(void);
void task2_run(void);
void task3_run(void);
void task4_run(void);

void task1_to_task2(void);
void task2_to_task3(void);
void task3_to_task1(void);
void task4_to_task1(void);

#endif

Open test main

#include <board.h>
#include <drv_common.h>
#include "test.h"
#include "task_test.h"

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
    hw_board_init();
    //stmfd_test();

    /* Thread initialization */
    task1_init();
    task2_init();
    task3_init();
    task4_init();

    task1_run();    /* Run the first thread */
    task1_to_task2();   /* Switch thread Task1 - > task2*/

    while (1)
    {
        HAL_GPIO_WritePin(GPIOE, GPIO_PIN_4, GPIO_PIN_RESET);
        HAL_Delay(1000);
        HAL_GPIO_WritePin(GPIOE, GPIO_PIN_4, GPIO_PIN_SET);
        HAL_Delay(1000);
    }
}

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

Compilation, download and debugging:

Comment out irrelevant code and set the path. It should be able to compile and download normally.

Software debugging: it is found that the thread can be initialized normally and the thread can be started (do not continue to execute while (1) of main)

Each thread can be flexibly manually switched and executed.

Run task1

 

Switch task2 and run

 

Summary

The preliminary switching idea has been clear

Continue to drill down into thread switching (task context switching)

Understand the scheduler, such as priority scheduling, for thread switching logic implementation

Keywords: RTOS

Added by basement on Mon, 17 Jan 2022 00:17:22 +0200