Notes on wildfire RT thread Kernel Implementation and application development 3. Implementation of RTT kernel object container

Keywords: C# stm32

1. What is the object?
  1. The object type enumeration is defined as follows:

    enum rt_object_class_type {
        RT_Object_Class_Thread = 0,     /* The object is a thread */
        RT_Object_Class_Semaphore,      /* The object is a semaphore */
        RT_Object_Class_Mutex,          /* Objects are mutexes */
        RT_Object_Class_Event,          /* Objects are events */
        RT_Object_Class_MailBox,        /* The object is a mailbox */
        RT_Object_Class_MessageQueue,   /* The object is a message queue */
        RT_Object_Class_MemHeap,        /* The object is a memory heap */
        RT_Object_Class_Mempool,        /* The object is a memory pool */
        RT_Object_Class_Device,         /* The object is a device */
        RT_Object_Class_Timer,          /* The object is a timer */
        RT_Object_Class_Module,         /* The object is a module */
        RT_Object_Class_Unknown,        /* The object is unknown */
        RT_Object_Class_Static = 0x80   /* Object is a static object */
    };
    
  2. Object data types are defined as follows:

    struct rt_object {
        char        name[RT_NAME_MAX];  /* The name of the kernel object */
        rt_uint8_t  type;               /* Type of kernel object */
        rt_uint8_t  flag;               /* The state of the kernel object */
        rt_list_t   list;               /* List node of kernel object */
    };
    
  3. Adds an object member to a thread control block

    In RT thread, each object will have a corresponding structure, which is called the control block of the object. For example, a thread will have a thread control block, in which the members of the object structure are placed at the beginning of the thread control block. The specific source code is as follows:

    struct rt_thread {
        /* rt object */
        char        name[RT_NAME_MAX];  /* Object name */
        rt_uint8_t  type;               /* object type */
        rt_uint8_t  flags;              /* State of the object */
        rt_list_t   list;               /* Object's list node */
        
        rt_list_t    tlist;             /* Thread linked list node */
        void        *sp;                /* Thread stack pointer */
        void        *entry;             /* Thread entry address */
        void        *parameter;         /* Thread parameters */
        void        *stack_addr;        /* Thread stack start address */
        rt_uint32_t  stack_size;        /* Thread stack size, in bytes */
    };
    
  4. What is a container

    From the code point of view, the container is an array. Each element corresponds to different object types. Each new object will be attached to the linked list of corresponding elements. The source code of the definition part of the container is as follows:

    static struct rt_object_information
    rt_object_container[RT_Object_Info_Unknown] = {
        /* Initialize object container - thread */
        {
            RT_Object_Class_Thread,
            _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Thread),
            sizeof(struct rt_thread)
        },
    
    #ifdef RT_USING_SEMAPHORE
        /* Initialize object container - semaphore */
        {
            RT_Object_Class_Semaphore,
            _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Semaphore),
            sizeof(struct rt_semaphore)
        },
    #endif
        
    #ifdef RT_USING_MUTEX
        /* Initialize object container - mutex */
        {
            RT_Object_Class_Mutex,
            _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Mutex),
            sizeof(struct rt_mutex)
        },
    #endif
    	. . . 
        . . . 
        . . . 
    }
    

    Type struct rt_object_information is defined as follows:

    struct rt_object_information {
        enum rt_object_class_type   type;           /* object type */
        rt_list_t                   object_list;    /* Object list node header */
        rt_size_t                   object_size;    /* Object size */
    };
    

    The schematic diagram of the initial object container is shown in the figure below. The next and prev pointers in the node headers of all element linked lists point to themselves.

2. Interface implementation of container
  1. Gets object information of the specified type

    When the container is defined, the size is fixed and determined by RT_Object_Info_Unknown is determined by the enumeration value, but the member index value in the container is not fixed, that is, the fixed index cannot be used to obtain the information of the members in the container. Therefore, it is necessary to traverse the entire container object. If the object type is equal to the type specified by us, then the address of the container member is returned. The type of the address is struct rt_object_information, the specific source code is as follows:

    struct rt_object_information *
    rt_object_get_information(enum rt_object_class_type type)
    {
        int index;
        
        for (index = 0; index < RT_Object_Class_Unknown; index++) {
            if (rt_object_container[index].type == type) {
                return &rt_object_container[index];
            }
        }
        return RT_NULL;
    }
    
  2. Object initialization

    Each time you create an object, you need to initialize it. It is mainly divided into two parts. First, initialize the object related members in the object control block, and then insert the object into the object container. The specific source code is as follows:

    /**
     * This function initializes the object and adds it to the object container
     *
     * @param object    Object to initialize
     * @param type      Type of object
     * @param name      The name of the object. In the whole system, the name of the object 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 the object information, that is, get the corresponding object list header pointer from the container */
        information = rt_object_get_information(type);
        
        /* Set the object type to static */
        object->type = type | RT_Object_Class_Static;
        
        /* Copy name */
        rt_strncpy(object->name, name, RT_NAME_MAX);
        
        /* Off interrupt */
        temp = rt_hw_interrupt_disable();
        
        /* Insert the object into the corresponding list of the container. The list of different types of objects is different */
        rt_list_insert_after(&(information->object_list), &(object->list));
        
        /* Enable interrupt */
        rt_hw_interrupt_enable(temp);
    }
    
  3. Call object initialization function

    The object initialization function is called in the thread initialization function. The specific source code is as follows:

    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)
    {
        /* 
         * Thread object initialization 
         * The four members at the beginning of the thread structure are rt_object_t member 
         */
        rt_object_init((rt_object_t)thread, RT_Object_Class_Thread, name);
        
        rt_list_init(&(thread->tlist));
        
        thread->entry = (void *)entry;
        thread->parameter = parameter;
        
        thread->stack_addr = stack_start;
        thread->stack_size = stack_size;
        
        /* Initialize the thread stack and return the thread stack pointer */
        thread->sp = 
        (void *)rt_hw_stack_init(thread->entry,
                                 thread->parameter,
        (void *)((char *)thread->stack_addr + thread->stack_size - 4));
        
        return RT_EOK;
    }
    

    If two threads are created, after thread initialization, the thread will hang itself to the object chain list of the container through its own list node. The schematic diagram in the container is shown in the following figure:

Posted by mjlively on Sat, 16 Oct 2021 02:12:23 -0700