Try   HackMD

作業系統工程-Thread

Table Of Content

tags: 作業系統工程 Operating System Programming note, 110-1, 2021


先放上 struct Thread 在 rtdef 中的定義

/** * 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) ,還沒開始執行時,就處於初始狀態;在此狀態 thread 不參與調度。在 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 主動延時一段時間而掛起。在此狀態 thread 不參與調度。在 RT-Thread 中的宏定義為 RT_THREAD_SUSPEND
關閉狀態(exit/delete/detach) 當 thread 執行結束時將處於關閉狀態。在此狀態 thread 不參與調度。在 RT-Thread 中的宏定義為 RT_THREAD_CLOSE
  • RT-Thread 提供 OS 使用的 function,使得 process state 在這五個 state 之間切換。
  • 狀態的轉換如下圖所示:
  • 下方 process 程式碼的介紹就會按照這張圖的順序一一解釋

補充說明 process 的錯誤碼(error return)

  • 一個 thread 就是一個執行場景,錯誤碼是與執行環境密切相關的,所以每個線程配備了一個變量用於保存錯誤碼,線程的錯誤碼有以下幾種:
#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

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 時得放入的參數(指標函數)
{ 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 時得放入的參數(指標函數)
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
{ /* 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
/* 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

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。
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

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 有下列三種功能
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
#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);