# 作業系統工程-Thread
# Table Of Content
###### tags: `作業系統工程 Operating System Programming note`, `110-1`, `2021`
[TOC]
---
<style>
.blue {
color: blue;
}
.red {
color: red;
}
</style>
###### rt-thread github [links](https://github.com/RT-Thread/rt-thread/tree/master/src)
## 先放上 struct Thread 在 rtdef 中的定義
```c=
/**
* Thread structure
*/
struct rt_thread
{
/* rt object */
char name[RT_NAME_MAX]; /**< the name of thread */
rt_uint8_t type; /**< type of object */
rt_uint8_t flags; /**< thread's flags */
#ifdef RT_USING_MODULE
void *module_id; /**< id of application module */
#endif
rt_list_t list; /**< the object list */
rt_list_t tlist; /**< the thread list */
/* stack point and entry */
void *sp; /**< stack point */
void *entry; /**< entry */
void *parameter; /**< parameter */
void *stack_addr; /**< stack address */
rt_uint32_t stack_size; /**< stack size */
/* error code */
rt_err_t error; /**< error code */
rt_uint8_t stat; /**< thread status */
#ifdef RT_USING_SMP
rt_uint8_t bind_cpu; /**< thread is bind to cpu */
rt_uint8_t oncpu; /**< process on cpu */
rt_uint16_t scheduler_lock_nest; /**< scheduler lock count */
rt_uint16_t cpus_lock_nest; /**< cpus lock count */
rt_uint16_t critical_lock_nest; /**< critical lock count */
#endif /*RT_USING_SMP*/
/* priority */
rt_uint8_t current_priority; /**< current priority */
#if RT_THREAD_PRIORITY_MAX > 32
rt_uint8_t number;
rt_uint8_t high_mask;
#endif
rt_uint32_t number_mask;
#if defined(RT_USING_EVENT)
/* thread event */
rt_uint32_t event_set;
rt_uint8_t event_info;
#endif
#if defined(RT_USING_SIGNALS)
rt_sigset_t sig_pending; /**< the pending signals */
rt_sigset_t sig_mask; /**< the mask bits of signal */
#ifndef RT_USING_SMP
void *sig_ret; /**< the return stack pointer from signal */
#endif
rt_sighandler_t *sig_vectors; /**< vectors of signal handler */
void *si_list; /**< the signal infor list */
#endif
rt_ubase_t init_tick; /**< thread's initialized tick */
rt_ubase_t remaining_tick; /**< remaining tick */
#ifdef RT_USING_CPU_USAGE
rt_uint64_t duration_tick; /**< cpu usage tick */
#endif
struct rt_timer thread_timer; /**< built-in thread timer */
void (*cleanup)(struct rt_thread *tid);/**< cleanup function when thread exit */
/* light weight process if present */
#ifdef RT_USING_LWP
void *lwp;
#endif
rt_ubase_t user_data; /**< private user data beyond this thread */
};
typedef struct rt_thread *rt_thread_t;
```
# thread 大致觀念
## process state
| 狀態 | 描述 |
| ---- | ---- |
| 初始狀態(initial) | thread 剛被 created ==(RT_THREAD_CREATE)== ,還沒開始執行時,就處於初始狀態;<span class="red">在此狀態 thread 不參與調度。</span>在 RT-Thread 中的宏定義為 ==RT_THREAD_INIT== |
| 就緒狀態(ready) | thread **按照優先級**排隊,等待被執行;一旦當前 thread 執行完畢(finish running) 讓出處理器, OS 會尋找最高優先級的 ready state 的 thread 執行。在 RT-Thread 中的宏定義為 ==RT_THREAD_READY== |
| 執行狀態(running) | thread 當前正在執行。**單核**系統中,只有 rt_thread_self() 函數返回的 thread 處於運行狀態;**多核**系統中,可能就不止這一個 thread 處於運行狀態。在 RT-Thread 中的宏定義為 ==RT_THREAD_RUNNING==|
| 掛起狀態(hanging/waiting) | 因為該 thread 的資源不夠,thread 不可被執行而掛起(等待),或 thread 主動延時一段時間而掛起。<span class="red">在此狀態 thread 不參與調度。</span>在 RT-Thread 中的宏定義為 ==RT_THREAD_SUSPEND== |
| 關閉狀態(exit/delete/detach) | 當 thread 執行結束時將處於關閉狀態。<span class="red">在此狀態 thread 不參與調度。</span>在 RT-Thread 中的宏定義為 ==RT_THREAD_CLOSE== |
- RT-Thread 提供 OS 使用的 function,使得 process state 在這五個 state 之間切換。
- 狀態的轉換如下圖所示:

- 下方 process 程式碼的介紹就會按照這張圖的順序一一解釋
## 補充說明 process 的錯誤碼(error return)
- 一個 thread 就是一個執行場景,錯誤碼是與執行環境密切相關的,所以每個線程配備了一個變量用於保存錯誤碼,線程的錯誤碼有以下幾種:
```c=
#define RT_EOK 0 /* 無錯誤 */
#define RT_ERROR 1 /* 普通錯誤 */
#define RT_ETIMEOUT 2 /* 超時錯誤 */
#define RT_EFULL 3 /* 資源已滿 */
#define RT_EEMPTY 4 /* 無資源 */
#define RT_ENOMEM 5 /* 無内存 */
#define RT_ENOSYS 6 /* 系统不支持 */
#define RT_EBUSY 7 /* 系统忙 */
#define RT_EIO 8 /* IO 錯誤 */
#define RT_EINTR 9 /* 中斷系统調用 */
#define RT_EINVAL 10 /* 非法參數 */
```
## 補充說明 process 優先級(priority)
- 表示 thread 能夠進入 runnging 的先後順序。
> 每個 thread 都具有優先級, thread 越重要,賦予的優先級就應越高, thread 被使用的可能性才越大。
- RT-Thread 最大能夠使用 256 個 thread priority(0~255),**數值越小的優先級越高**(0 為 highest priority)。
(若整體 resource 較少的 system 可以只使用 8 或 32 priority)
- 若有比當前 thread priority 更高的 thread 在 ready state 時,當前 priority 較小的 thread 將立刻被 swap out,讓 high priority thread 使用 CPU(processor) 執行。
# 初始化 thread 的函式
## In Initial State
### 1. Create:創一個 new process
```c=
rt_thread_t rt_thread_create(const char* name, //
void (*entry)(void* parameter),//進入點的指標函式
void* parameter, //和上方指標函數相關參數
rt_uint32_t stack_size, //為了配置一塊屬於該 process 大小的 stack memory space
rt_uint8_t priority, //
rt_uint32_t tick); //
```
- 上方為呼叫 create function 時得放入的參數(指標函數)
```c=
{
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;
//記憶體可能因所剩的 hole size 不夠大,而 thread 無法得到一個屬於他的 memory space
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;
}
_thread_init(thread, name, entry, parameter, stack_start, stack_size, priority, tick);
return thread;
}
```
### 2. Initial:初始化 process
- 下方為呼叫 initial function 時得放入的參數(指標函數)
```c=
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 的參數裡面
如 entry、stack
```c=
{
/* init thread list */
rt_list_init(&(thread->tlist));
thread->entry = (void *)entry;//把傳入的 entry 指標函式放到該 thread entry
thread->parameter = parameter;//指標函式的參數也放到 thread上
/* stack init */
thread->stack_addr = stack_start;
thread->stack_size = stack_size;
/* init thread stack */
rt_memset(thread->stack_addr, '#', thread->stack_size);
#ifdef ARCH_CPU_STACK_GROWS_UPWARD
thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter, (void *)((char *)thread->stack_addr), (void *)_thread_exit);
#else
thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter, (rt_uint8_t *)((char *)thread->stack_addr + thread->stack_size - sizeof(rt_ubase_t)), (void *)_thread_exit);
#endif /* ARCH_CPU_STACK_GROWS_UPWARD */
```
- 初始化 priority
```c=
/* priority init */
RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX); //如果在合理範圍內
thread->current_priority = priority;//就把傳入的 priority 放到 thread priority
thread->number_mask = 0;
#if RT_THREAD_PRIORITY_MAX > 32 //當 system 需要使用到很大的 priority(>32個),才使用到其他變數
thread->number = 0;
thread->high_mask = 0;
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
/* tick init */
thread->init_tick = tick;
thread->remaining_tick = tick;
/* error and flags */
thread->error = RT_EOK;
thread->stat = RT_THREAD_INIT;//表示現在 thread 的狀態在"初始狀態",不可被使用(調度)
#ifdef RT_USING_SMP
/* not bind on any cpu */
thread->bind_cpu = RT_CPUS_NR;
thread->oncpu = RT_CPU_DETACHED;
/* lock init */
thread->scheduler_lock_nest = 0;
thread->cpus_lock_nest = 0;
thread->critical_lock_nest = 0;
#endif /* RT_USING_SMP */
/* initialize cleanup function and user data */
thread->cleanup = 0;
thread->user_data = 0;
/* initialize thread timer */
rt_timer_init(&(thread->thread_timer),thread->name,_thread_timeout,thread,0,RT_TIMER_FLAG_ONE_SHOT);
//下面就是有 define 到才需要初始化的變數
/* initialize signal */
#ifdef RT_USING_SIGNALS
thread->sig_mask = 0x00;
thread->sig_pending = 0x00;
#ifndef RT_USING_SMP
thread->sig_ret = RT_NULL;
#endif /* RT_USING_SMP */
thread->sig_vectors = RT_NULL;
thread->si_list = RT_NULL;
#endif /* RT_USING_SIGNALS */
#ifdef RT_USING_LWP
thread->lwp = RT_NULL;
#endif /* RT_USING_LWP */
#ifdef RT_USING_CPU_USAGE
thread->duration_tick = 0;
#endif
RT_OBJECT_HOOK_CALL(rt_thread_inited_hook, (thread));
return RT_EOK;
}
```
## From Initial to Ready State
### Start Up
-
```c=
rt_err_t rt_thread_startup(rt_thread_t thread)
{
/* parameter check */
RT_ASSERT(thread != RT_NULL);
RT_ASSERT((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_INIT);
RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
/* calculate priority attribute */
#if RT_THREAD_PRIORITY_MAX > 32
thread->number = thread->current_priority >> 3; /* 5bit */
thread->number_mask = 1L << thread->number;
thread->high_mask = 1L << (thread->current_priority & 0x07); /* 3bit */
#else
thread->number_mask = 1L << thread->current_priority;
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
RT_DEBUG_LOG(RT_DEBUG_THREAD, ("startup a thread:%s with priority:%d\n", thread->name, thread->current_priority));
/* change thread stat */
thread->stat = RT_THREAD_SUSPEND;
/* then resume it */
rt_thread_resume(thread);
if (rt_thread_self() != RT_NULL)
{
/* do a scheduling */
rt_schedule();
}
return RT_EOK;
}
```
# 和 Waiting State 有關的函式
## From Ready to Wating State
### 1. Suspend
- 使用時機:在準備狀態的 process 因持有的 resources 不足而無法執行,將被放入 waiting queue。
```c=
rt_err_t rt_thread_suspend(rt_thread_t thread)
{
register rt_base_t stat;
register rt_base_t temp;
/* parameter check */
RT_ASSERT(thread != RT_NULL);
RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
RT_ASSERT(thread == rt_thread_self());
RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend: %s\n", thread->name));
stat = thread->stat & RT_THREAD_STAT_MASK;
if ((stat != RT_THREAD_READY) && (stat != RT_THREAD_RUNNING))
{
RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend: thread disorder, 0x%2x\n", thread->stat));
return -RT_ERROR;
}
/* disable interrupt */
temp = rt_hw_interrupt_disable();
/* change thread state */
rt_schedule_remove_thread(thread);
thread->stat = RT_THREAD_SUSPEND | (thread->stat & ~RT_THREAD_STAT_MASK);
/* stop thread timer anyway */
rt_timer_stop(&(thread->thread_timer));
/* enable interrupt */
rt_hw_interrupt_enable(temp);
// 22-31 行:先關掉中斷再打開中斷,是因中間的 coding 會改到 shared memory space
RT_OBJECT_HOOK_CALL(rt_thread_suspend_hook, (thread));
return RT_EOK;
}
```
## From Running to Wating State
### 1. Delay
### 2. Take
-
## From Wating to Ready State
### 1. Resume
```c=
rt_err_t rt_thread_resume(rt_thread_t thread)
{
register rt_base_t temp;
/* parameter check */
RT_ASSERT(thread != RT_NULL);
RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume: %s\n", thread->name));
if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_SUSPEND)
{
RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume: thread disorder, %d\n",
thread->stat));
return -RT_ERROR;
}
/* disable interrupt */
temp = rt_hw_interrupt_disable();
/* remove from suspend list */
rt_list_remove(&(thread->tlist));
rt_timer_stop(&thread->thread_timer);
/* insert to schedule ready list */
rt_schedule_insert_thread(thread);
/* enable interrupt */
rt_hw_interrupt_enable(temp);
RT_OBJECT_HOOK_CALL(rt_thread_resume_hook, (thread));
return RT_EOK;
}
```
### 2. Release
-
# 和 Exit State 有關的函式
## From Running to Exit State
### 1. Exit
## From Waiting to Exit State
### 1. delete
### 2. detach
# set hook
- set hook 有下列三種功能
```c=
void rt_thread_resume_sethook(void (*hook)(rt_thread_t thread));
void rt_thread_inited_sethook(void (*hook)(rt_thread_t thread));
void rt_thread_inited_sethook(void (*hook)(rt_thread_t thread));
```
> - 下面為一些跟 hook 相關的 define
>```c=
>#ifndef __on_rt_thread_inited_hook
> #define __on_rt_thread_inited_hook(thread) __ON_HOOK_ARGS(rt_thread_inited_hook, (thread))
>#endif
>#ifndef __on_rt_thread_suspend_hook
> #define __on_rt_thread_suspend_hook(thread) __ON_HOOK_ARGS(rt_thread_suspend_hook, (thread))
>#endif
>#ifndef __on_rt_thread_resume_hook
> #define __on_rt_thread_resume_hook(thread) __ON_HOOK_ARGS(rt_thread_resume_hook, (thread))
>#endif
>
>#if defined(RT_USING_HOOK) && >defined(RT_HOOK_USING_FUNC_PTR)
>static void (*rt_thread_suspend_hook)(rt_thread_t thread);
>static void (*rt_thread_resume_hook) (rt_thread_t thread);
>static void (*rt_thread_inited_hook) (rt_thread_t thread);
>```