# 作業系統工程 ## 課程筆記 ## Thread :::success 檔案位置 : rt-thread/include/rtdef.h ::: ### 初始化thread ### ```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 堆疊 /* 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 */ // 調度CPU上的程序 #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*/ ``` ### 狀態 ```c= /* priority */ rt_uint8_t current_priority; /**< current priority */ rt_uint8_t init_priority; /**< initialized priority */ #if RT_THREAD_PRIORITY_MAX > 32 rt_uint8_t number; rt_uint8_t high_mask; #endif ``` :::info - 線程優先級 RT-Thread 最大支持 256 個線程優先級 (0\~255),數值越小的優先級越高,0 為最高優先級。在一些資源比較緊張的系統中,可以根據實際情況選擇只支持 8 個或 32 個優先級的系統配置; 對於 ARM Cortex-M 系列,普遍采用 32 個優先級。最低優先級默認分配給空閑線程使用,用戶一般不使用。 在系統中,當有比當前線程優先級更高的線程就緒時,當前線程將立刻被換出,高優先級線程搶占處理器運行。 ![](https://i.imgur.com/9ODQsCo.png) |狀態| 描述| |-|-| |RT_THREAD_INIT| 線程初始狀態。當線程剛開始創建還沒開始運行時就處於這個 狀態;在這個狀態下,線程不參與調度| |RT_THREAD_SUSPEND| 掛起態、阻塞態。線程此時被掛起:它可能因為資源不可用而掛起等待;或線程主動延時一段時間而被掛起。在這個狀態下 ,線程不參與調度| |RT_THREAD_READY| 就緒態。線程正在運行;或當前線程運行完讓出處理器後,操作系統尋找最高優先級的就緒態線程運行| |RT_THREAD_RUNNING| 運行態。線程當前正在運行,在單核系統中,只有rt_thread_self()函數返回的線程處於這個狀態;在多核系統中則不受這個限制。| |RT_THREAD_CLOSE| 線程結束態。當線程運行結束時將處於這個狀態。這個狀態的線程不參與線程的調度。| ::: ```c= #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 */ 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 */ }; ``` ### Thread流程圖 :::success 檔案位置 : rt-thread/src/thread.c ::: ![](https://i.imgur.com/qYmv7wX.png) Thread啟動流程 ![](https://i.imgur.com/879gGa5.png) ### 初始化 #### 靜態記憶體管理 #### rt_thread_init() :::info | `*thread` | `*name` | `*entry` | `*parameter` | | --------- | ------- | -------- | ------------ | | thread 本體 | 名字 | 要執行的副程式 | 副程式參數 | | `*stack_start` | `stack_size` | `priority` | `tick` | | -------------- | ------------ | ---------- | ------ | | thread 堆疊起點 | thread 堆疊大小 | 優先級 | 可執行的 tick 數 | ::: ```c= /** * 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); /* initialize 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); } RTM_EXPORT(rt_thread_init); ``` ### 動態記憶體管理 #### rt_thread_create() :::info | `*thread` | `*name` | `*entry` | `*parameter` | | --------- | ------- | -------- | ------------ | | thread 本體 | 名字 | 要執行的副程式 | 副程式參數 | | `*stack_start` | `stack_size` | `priority` | `tick` | | -------------- | ------------ | ---------- | ------ | | thread 堆疊起點 | thread 堆疊大小 | 優先級 | 可執行的 tick 數 | ::: ```c=344 /** * 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; } RTM_EXPORT(rt_thread_create); ``` #### _rt_thread_init() :::info 初始化 thread | `*thread` | `*name` | `*entry` | `*parameter` | | --------- | ------- | -------- | ------------ | | thread 本體 | 名字 | 要執行的副程式 | 副程式參數 | | `*stack_start` | `stack_size` | `priority` | `tick` | | -------------- | ------------ | ---------- | ------ | | thread 堆疊起點 | thread 堆疊大小 | 優先級 | 可執行的 tick 數 | ::: ```c= /** * 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); /* initialize 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); } RTM_EXPORT(rt_thread_init); ``` 透過 _rt_thread_init 完成初始化 rtthread_startup()是啟動入口 啟動順序: 1. 從啟動檔案開始執行 2. 進入rtthread_startup() 3. 進行RTT系統功能初始化 4. 進入使用者入口main() #### rtthread_startup() * 設定 priority ```c= /** * This function will start a thread and put it to system ready queue * * @param thread the thread to be started * * @return the operation status, RT_EOK on OK, -RT_ERROR on error */ rt_err_t rt_thread_startup(rt_thread_t thread) { /* thread 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); /* set current priority to initialize priority */ thread->current_priority = thread->init_priority; /* 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 ``` * 將 stat 設為 RT_THREAD_SUSPEND,再透過 rt_thread_resume 來完成啟動 * 啟動完成後呼叫 rt_scheduler() 來執行一次調度 ```c= RT_DEBUG_LOG(RT_DEBUG_THREAD, ("startup a thread:%s with priority:%d\n", thread->name, thread->init_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; } RTM_EXPORT(rt_thread_startup); ``` ### 暫停 thread #### rt_thread_suspend() :::info 暫停 thread | `*thread` | | --------- | | 欲暫停的 thread | ::: ```c= /** * This function will suspend the specified thread. * * @param thread the thread to be suspended * * @return the operation status, RT_EOK on OK, -RT_ERROR on error * * @note if suspend self thread, after this function call, the * rt_schedule() must be invoked. */ rt_err_t rt_thread_suspend(rt_thread_t thread) { register rt_base_t stat; register rt_base_t temp; /* thread 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 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(); if (stat == RT_THREAD_RUNNING) { /* not suspend running status thread on other core */ RT_ASSERT(thread == rt_thread_self()); } /* change thread stat */ 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); RT_OBJECT_HOOK_CALL(rt_thread_suspend_hook, (thread)); return RT_EOK; } RTM_EXPORT(rt_thread_suspend); ``` #### rt_thread_delay() :::info 延遲 thread | `tick` | | --------- | | 欲延遲的時間 | ::: ```c= /** * This function will let current thread delay for some ticks. * * @param tick the delay ticks * * @return RT_EOK */ rt_err_t rt_thread_delay(rt_tick_t tick) { return rt_thread_sleep(tick); } RTM_EXPORT(rt_thread_delay); ``` #### rt_thread_sleep() :::info 使 thread 休眠 | `tick` | | --------- | | 欲睡眠的時間 | ::: ```c= /** * This function will let current thread sleep for some ticks. * * @param tick the sleep ticks * * @return RT_EOK */ rt_err_t rt_thread_sleep(rt_tick_t tick) { register rt_base_t temp; struct rt_thread *thread; /* set to current thread */ thread = rt_thread_self(); RT_ASSERT(thread != RT_NULL); RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread); /* disable interrupt */ temp = rt_hw_interrupt_disable(); /* suspend thread */ rt_thread_suspend(thread); /* reset the timeout of thread timer and start it */ rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &tick); rt_timer_start(&(thread->thread_timer)); /* enable interrupt */ rt_hw_interrupt_enable(temp); rt_schedule(); /* clear error number of this thread to RT_EOK */ if (thread->error == -RT_ETIMEOUT) thread->error = RT_EOK; return RT_EOK; } ``` ### 復原 thread #### rt_thread_resume() :::info 復原 thread | `*thread` | | --------- | | 欲復原的 thread | ::: ```c= /** * This function will resume a thread and put it to system ready queue. * * @param thread the thread to be resumed * * @return the operation status, RT_EOK on OK, -RT_ERROR on error */ rt_err_t rt_thread_resume(rt_thread_t thread) { register rt_base_t temp; /* thread 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); /* enable interrupt */ rt_hw_interrupt_enable(temp); /* insert to schedule ready list */ rt_schedule_insert_thread(thread); RT_OBJECT_HOOK_CALL(rt_thread_resume_hook, (thread)); return RT_EOK; } RTM_EXPORT(rt_thread_resume); ``` - 從 suspend list 移除,停止 timer,掛回去 ready list - `rt_schedule_insert_thread` 會將狀態修改成 `RT_THREAD_READY` ### 離開 thread #### rt_thread_exit :::info 暫停 thread ::: ```c= void rt_thread_exit(void) { struct rt_thread *thread; register rt_base_t level; /* get current thread */ thread = rt_thread_self(); /* disable interrupt */ level = rt_hw_interrupt_disable(); _thread_cleanup_execute(thread); /* remove from schedule */ rt_schedule_remove_thread(thread); /* change stat */ thread->stat = RT_THREAD_CLOSE; /* remove it from timer list */ rt_timer_detach(&thread->thread_timer); if (rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE) { rt_object_detach((rt_object_t)thread); } else { /* insert to defunct thread list */ rt_list_insert_after(&rt_thread_defunct, &(thread->tlist)); } /* switch to next task */ rt_schedule(); /* enable interrupt */ rt_hw_interrupt_enable(level); } ``` ### 刪除 thread #### rt_thread_delete :::info | `*thread` | | --------- | | 欲刪除的 thread | ::: ```c= /** * This function will delete a thread. The thread object will be removed from * thread queue and deleted from system object management in the idle thread. * * @param thread the thread to be deleted * * @return the operation status, RT_EOK on OK, -RT_ERROR on error */ rt_err_t rt_thread_delete(rt_thread_t thread) { rt_base_t lock; /* thread check */ RT_ASSERT(thread != RT_NULL); RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread); RT_ASSERT(rt_object_is_systemobject((rt_object_t)thread) == RT_FALSE); if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE) return RT_EOK; if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT) { /* remove from schedule */ rt_schedule_remove_thread(thread); } _thread_cleanup_execute(thread); /* release thread timer */ rt_timer_detach(&(thread->thread_timer)); /* disable interrupt */ lock = rt_hw_interrupt_disable(); /* change stat */ thread->stat = RT_THREAD_CLOSE; /* insert to defunct thread list */ rt_list_insert_after(&rt_thread_defunct, &(thread->tlist)); /* enable interrupt */ rt_hw_interrupt_enable(lock); return RT_EOK; } RTM_EXPORT(rt_thread_delete); #endif ``` #### rt_thread_detach :::info | `*thread` | | --------- | | 欲刪除的 thread | ::: ```c= /** * This function will detach a thread. The thread object will be removed from * thread queue and detached/deleted from system object management. * * @param thread the thread to be deleted * * @return the operation status, RT_EOK on OK, -RT_ERROR on error */ rt_err_t rt_thread_detach(rt_thread_t thread) { rt_base_t lock; /* thread check */ RT_ASSERT(thread != RT_NULL); RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread); RT_ASSERT(rt_object_is_systemobject((rt_object_t)thread)); if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE) return RT_EOK; if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT) { /* remove from schedule */ rt_schedule_remove_thread(thread); } _thread_cleanup_execute(thread); /* release thread timer */ rt_timer_detach(&(thread->thread_timer)); /* change stat */ thread->stat = RT_THREAD_CLOSE; if (rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE) { rt_object_detach((rt_object_t)thread); } else { /* disable interrupt */ lock = rt_hw_interrupt_disable(); /* insert to defunct thread list */ rt_list_insert_after(&rt_thread_defunct, &(thread->tlist)); /* enable interrupt */ rt_hw_interrupt_enable(lock); } return RT_EOK; } RTM_EXPORT(rt_thread_detach); ``` --- ## Scheduler :::success 檔案位置 : rt-thread/src/scheduler.c ::: ### 初始化 :::info 系統啟動時需要執行調度器的初始化,以初始化系統調度器用到的一些全局變量。調 度器初始化可以調用下面的函數接口。 ::: #### `rt_system_scheduler_init(void)` ```c= /** * @ingroup SystemInit * This function will initialize the system scheduler */ void rt_system_scheduler_init(void) { #ifdef RT_USING_SMP int cpu; #endif /*RT_USING_SMP*/ register rt_base_t offset; #ifndef RT_USING_SMP rt_scheduler_lock_nest = 0; #endif /*RT_USING_SMP*/ RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("start scheduler: max priority 0x%02x\n", RT_THREAD_PRIORITY_MAX)); for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset ++) { rt_list_init(&rt_thread_priority_table[offset]); } #ifdef RT_USING_SMP for (cpu = 0; cpu < RT_CPUS_NR; cpu++) { struct rt_cpu *pcpu = rt_cpu_index(cpu); for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset ++) { rt_list_init(&pcpu->priority_table[offset]); } pcpu->irq_switch_flag = 0; pcpu->current_priority = RT_THREAD_PRIORITY_MAX - 1; pcpu->current_thread = RT_NULL; pcpu->priority_group = 0; #if RT_THREAD_PRIORITY_MAX > 32 rt_memset(pcpu->ready_table, 0, sizeof(pcpu->ready_table)); #endif } #endif /*RT_USING_SMP*/ /* initialize ready priority group */ rt_thread_ready_priority_group = 0; #if RT_THREAD_PRIORITY_MAX > 32 /* initialize ready table */ rt_memset(rt_thread_ready_table, 0, sizeof(rt_thread_ready_table)); #endif /* initialize thread defunct */ rt_list_init(&rt_thread_defunct); } ``` ### 啟動 scheduler :::info 初始化後切換到第一個scheduler ::: #### `rt_system_scheduler_start(void)` ```c= /** * @ingroup SystemInit * This function will startup scheduler. It will select one thread * with the highest priority level, then switch to it. */ void rt_system_scheduler_start(void) { register struct rt_thread *to_thread; rt_ubase_t highest_ready_priority; to_thread = _get_highest_priority_thread(&highest_ready_priority); #ifdef RT_USING_SMP to_thread->oncpu = rt_hw_cpu_id(); #else rt_current_thread = to_thread; #endif /*RT_USING_SMP*/ rt_schedule_remove_thread(to_thread); to_thread->stat = RT_THREAD_RUNNING; /* switch to new thread */ #ifdef RT_USING_SMP rt_hw_context_switch_to((rt_ubase_t)&to_thread->sp, to_thread); #else rt_hw_context_switch_to((rt_ubase_t)&to_thread->sp); #endif /*RT_USING_SMP*/ /* never come back */ } ``` ### 執行 scheduler #### `rt_schedule(void)` ```c= void rt_schedule(void) { rt_base_t level; struct rt_thread *to_thread; struct rt_thread *current_thread; struct rt_cpu *pcpu; int cpu_id; /* disable interrupt */ level = rt_hw_interrupt_disable(); cpu_id = rt_hw_cpu_id(); pcpu = rt_cpu_index(cpu_id); current_thread = pcpu->current_thread; /* whether do switch in interrupt */ if (pcpu->irq_nest) { pcpu->irq_switch_flag = 1; rt_hw_interrupt_enable(level); goto __exit; } #ifdef RT_USING_SIGNALS if ((current_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND) { /* if current_thread signal is in pending */ if ((current_thread->stat & RT_THREAD_STAT_SIGNAL_MASK) & RT_THREAD_STAT_SIGNAL_PENDING) { rt_thread_resume(current_thread); } } #endif if (current_thread->scheduler_lock_nest == 1) /* whether lock scheduler */ { rt_ubase_t highest_ready_priority; if (rt_thread_ready_priority_group != 0 || pcpu->priority_group != 0) { to_thread = _get_highest_priority_thread(&highest_ready_priority); current_thread->oncpu = RT_CPU_DETACHED; if ((current_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_RUNNING) { if (current_thread->current_priority < highest_ready_priority) { to_thread = current_thread; } else if (current_thread->current_priority == highest_ready_priority && (current_thread->stat & RT_THREAD_STAT_YIELD_MASK) == 0) { to_thread = current_thread; } else { rt_schedule_insert_thread(current_thread); } current_thread->stat &= ~RT_THREAD_STAT_YIELD_MASK; } to_thread->oncpu = cpu_id; if (to_thread != current_thread) { /* if the destination thread is not the same as current thread */ pcpu->current_priority = (rt_uint8_t)highest_ready_priority; RT_OBJECT_HOOK_CALL(rt_scheduler_hook, (current_thread, to_thread)); rt_schedule_remove_thread(to_thread); to_thread->stat = RT_THREAD_RUNNING | (to_thread->stat & ~RT_THREAD_STAT_MASK); /* switch to new thread */ RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("[%d]switch to priority#%d " "thread:%.*s(sp:0x%08x), " "from thread:%.*s(sp: 0x%08x)\n", pcpu->irq_nest, highest_ready_priority, RT_NAME_MAX, to_thread->name, to_thread->sp, RT_NAME_MAX, current_thread->name, current_thread->sp)); #ifdef RT_USING_OVERFLOW_CHECK _rt_scheduler_stack_check(to_thread); #endif rt_hw_context_switch((rt_ubase_t)&current_thread->sp, (rt_ubase_t)&to_thread->sp, to_thread); } } } /* enable interrupt */ rt_hw_interrupt_enable(level); #ifdef RT_USING_SIGNALS /* check stat of thread for signal */ level = rt_hw_interrupt_disable(); if (current_thread->stat & RT_THREAD_STAT_SIGNAL_PENDING) { extern void rt_thread_handle_sig(rt_bool_t clean_state); current_thread->stat &= ~RT_THREAD_STAT_SIGNAL_PENDING; rt_hw_interrupt_enable(level); /* check signal status */ rt_thread_handle_sig(RT_TRUE); } else { rt_hw_interrupt_enable(level); } #endif ``` ### 切換 scheduler #### `rt_schedule(void)` :::info 這個函數用於把用戶提供的hook函數設置到系統調度器鉤子中,當系統進行上下文切換時,這個hook函數將會被系統調用。 ::: ```c= void rt_scheduler_sethook(void (*hook)(struct rt_thread *from, struct rt_thread *to)) { rt_scheduler_hook = hook; } ``` --- ## Timer :::success 檔案位置 : rt-thread/include/rtdef.h ::: :::info 某個時刻,開始是指從指定的某個事件,經過指定然後觸發一個事件 ![](https://i.imgur.com/R5W6IE9.png) - 當前系統經過的tick時間rt_tick(當定時器中斷來臨時,它將加1);即當前 tick 到達指定的 timer 時,會觸發該 timer 的 `timeout_func`,同時將該 timer 從鏈結移除 - 以上圖為例,當 `rt_tick` = 70 時,將會觸發 timer #1 的 `timeout_func`,並將 timer #1 移除 ![](https://i.imgur.com/5kRoiRF.png) - 新增一個 timer 時,會按照 timeout 的大小排列插入 - 若是想要新增一個 timer #4,且希望在 #1 #2之後觸發 我們可以將timeout 設為 330(rt_tick + 300) - 由於 timer 鏈需要由小到大排,所以將 timer #4 插在 #2 與 #3 之間 ::: ### 初始化、建立 timer - 在建立一個 thread 時,`_rt_thread_init` 會呼叫 `rt_timer_init` 來初始化 timer ### 靜態記憶體管理 #### `rt_timer_init` ```c=155 /** * This function will initialize a timer, normally this function is used to * initialize a static timer object. * * @param timer the static timer object * @param name the name of timer * @param timeout the timeout function * @param parameter the parameter of timeout function * @param time the tick of timer * @param flag the flag of timer */ void rt_timer_init(rt_timer_t timer, const char *name, void (*timeout)(void *parameter), void *parameter, rt_tick_t time, rt_uint8_t flag) { /* timer check */ RT_ASSERT(timer != RT_NULL); /* timer object initialization */ rt_object_init((rt_object_t)timer, RT_Object_Class_Timer, name); _rt_timer_init(timer, timeout, parameter, time, flag); } RTM_EXPORT(rt_timer_init); ``` - 與 thread 類似,使用 `_rt_timer_init` 完成初始化 ```c=68 static void _rt_timer_init(rt_timer_t timer, void (*timeout)(void *parameter), void *parameter, rt_tick_t time, rt_uint8_t flag) { int i; /* set flag */ timer->parent.flag = flag; /* set deactivated */ timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; timer->timeout_func = timeout; timer->parameter = parameter; timer->timeout_tick = 0; timer->init_tick = time; /* initialize timer list */ for (i = 0; i < RT_TIMER_SKIP_LIST_LEVEL; i++) { rt_list_init(&(timer->row[i])); } } ``` - 設定 flag 為 decativated,設定 timeout_func、tick、timerlist --- ### 動態記憶體管理 #### `rt_timer_create` :::info 功能 : 建立 timer ::: ```c=214 /** * This function will create a timer * * @param name the name of timer * @param timeout the timeout function * @param parameter the parameter of timeout function * @param time the tick of timer * @param flag the flag of timer * * @return the created timer object */ rt_timer_t rt_timer_create(const char *name, void (*timeout)(void *parameter), void *parameter, rt_tick_t time, rt_uint8_t flag) { struct rt_timer *timer; /* allocate a object */ timer = (struct rt_timer *)rt_object_allocate(RT_Object_Class_Timer, name); if (timer == RT_NULL) { return RT_NULL; } _rt_timer_init(timer, timeout, parameter, time, flag); return timer; } RTM_EXPORT(rt_timer_create); ``` - 同樣也是透過 `_rt_timer_init` 完成動作 --- ### 刪除 timer #### `rt_timer_delete` :::info 功能 : 刪除 timer ::: ```c=246 /** * This function will delete a timer and release timer memory * * @param timer the timer to be deleted * * @return the operation status, RT_EOK on OK; RT_ERROR on error */ rt_err_t rt_timer_delete(rt_timer_t timer) { register rt_base_t level; /* timer check */ RT_ASSERT(timer != RT_NULL); RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer); RT_ASSERT(rt_object_is_systemobject(&timer->parent) == RT_FALSE); /* disable interrupt */ level = rt_hw_interrupt_disable(); _rt_timer_remove(timer); /* enable interrupt */ rt_hw_interrupt_enable(level); rt_object_delete((rt_object_t)timer); return RT_EOK; } RTM_EXPORT(rt_timer_delete); ``` --- #### `rt_timer_detach` :::info 功能 : 刪除 timer ::: ```c=183 /** * This function will detach a timer from timer management. * * @param timer the static timer object * * @return the operation status, RT_EOK on OK; RT_ERROR on error */ rt_err_t rt_timer_detach(rt_timer_t timer) { register rt_base_t level; /* timer check */ RT_ASSERT(timer != RT_NULL); RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer); RT_ASSERT(rt_object_is_systemobject(&timer->parent)); /* disable interrupt */ level = rt_hw_interrupt_disable(); _rt_timer_remove(timer); /* enable interrupt */ rt_hw_interrupt_enable(level); rt_object_detach((rt_object_t)timer); return RT_EOK; } RTM_EXPORT(rt_timer_detach); ``` --- #### `rt_timer_start` :::info 功能 : 啟動 timer ::: ```c=277 /** * This function will start the timer * * @param timer the timer to be started * * @return the operation status, RT_EOK on OK, -RT_ERROR on error */ rt_err_t rt_timer_start(rt_timer_t timer) { unsigned int row_lvl; rt_list_t *timer_list; register rt_base_t level; rt_list_t *row_head[RT_TIMER_SKIP_LIST_LEVEL]; unsigned int tst_nr; static unsigned int random_nr; /* timer check */ RT_ASSERT(timer != RT_NULL); RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer); /* stop timer firstly */ level = rt_hw_interrupt_disable(); /* remove timer from list */ _rt_timer_remove(timer); /* change status of timer */ timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; rt_hw_interrupt_enable(level); RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(timer->parent))); /* * get timeout tick, * the max timeout tick shall not great than RT_TICK_MAX/2 */ RT_ASSERT(timer->init_tick < RT_TICK_MAX / 2); timer->timeout_tick = rt_tick_get() + timer->init_tick; /* disable interrupt */ level = rt_hw_interrupt_disable(); #ifdef RT_USING_TIMER_SOFT if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER) { /* insert timer to soft timer list */ timer_list = rt_soft_timer_list; } else #endif { /* insert timer to system timer list */ timer_list = rt_timer_list; } row_head[0] = &timer_list[0]; for (row_lvl = 0; row_lvl < RT_TIMER_SKIP_LIST_LEVEL; row_lvl++) { for (; row_head[row_lvl] != timer_list[row_lvl].prev; row_head[row_lvl] = row_head[row_lvl]->next) { struct rt_timer *t; rt_list_t *p = row_head[row_lvl]->next; /* fix up the entry pointer */ t = rt_list_entry(p, struct rt_timer, row[row_lvl]); /* If we have two timers that timeout at the same time, it's * preferred that the timer inserted early get called early. * So insert the new timer to the end the the some-timeout timer * list. */ if ((t->timeout_tick - timer->timeout_tick) == 0) { continue; } else if ((t->timeout_tick - timer->timeout_tick) < RT_TICK_MAX / 2) { break; } } if (row_lvl != RT_TIMER_SKIP_LIST_LEVEL - 1) row_head[row_lvl + 1] = row_head[row_lvl] + 1; } /* Interestingly, this super simple timer insert counter works very very * well on distributing the list height uniformly. By means of "very very * well", I mean it beats the randomness of timer->timeout_tick very easily * (actually, the timeout_tick is not random and easy to be attacked). */ random_nr++; tst_nr = random_nr; rt_list_insert_after(row_head[RT_TIMER_SKIP_LIST_LEVEL - 1], &(timer->row[RT_TIMER_SKIP_LIST_LEVEL - 1])); for (row_lvl = 2; row_lvl <= RT_TIMER_SKIP_LIST_LEVEL; row_lvl++) { if (!(tst_nr & RT_TIMER_SKIP_LIST_MASK)) rt_list_insert_after(row_head[RT_TIMER_SKIP_LIST_LEVEL - row_lvl], &(timer->row[RT_TIMER_SKIP_LIST_LEVEL - row_lvl])); else break; /* Shift over the bits we have tested. Works well with 1 bit and 2 * bits. */ tst_nr >>= (RT_TIMER_SKIP_LIST_MASK + 1) >> 1; } timer->parent.flag |= RT_TIMER_FLAG_ACTIVATED; /* enable interrupt */ rt_hw_interrupt_enable(level); #ifdef RT_USING_TIMER_SOFT if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER) { /* check whether timer thread is ready */ if ((timer_thread.stat & RT_THREAD_STAT_MASK) != RT_THREAD_READY) { /* resume timer thread to check soft timer */ rt_thread_resume(&timer_thread); rt_schedule(); } } #endif return RT_EOK; } RTM_EXPORT(rt_timer_start); ``` --- #### `rt_timer_stop` :::info 功能 : 停止 timer ::: ```c=403 /** * This function will stop the timer * * @param timer the timer to be stopped * * @return the operation status, RT_EOK on OK, -RT_ERROR on error */ rt_err_t rt_timer_stop(rt_timer_t timer) { register rt_base_t level; /* timer check */ RT_ASSERT(timer != RT_NULL); RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer); if (!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)) return -RT_ERROR; RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(timer->parent))); /* disable interrupt */ level = rt_hw_interrupt_disable(); _rt_timer_remove(timer); /* enable interrupt */ rt_hw_interrupt_enable(level); /* change stat */ timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; return RT_EOK; } RTM_EXPORT(rt_timer_stop); ``` - 首先將 timer 從鏈結移出,再將 flag 設為 `RT_TIMER_FLAG_DEACTIVATED ` --- ### 控制 timer #### rt_timer_control :::info 功能 : 控制 timer ::: ```c=438 /** * This function will get or set some options of the timer * * @param timer the timer to be get or set * @param cmd the control command * @param arg the argument * * @return RT_EOK */ rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg) { /* timer check */ RT_ASSERT(timer != RT_NULL); RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer); switch (cmd) { case RT_TIMER_CTRL_GET_TIME: *(rt_tick_t *)arg = timer->init_tick; break; case RT_TIMER_CTRL_SET_TIME: timer->init_tick = *(rt_tick_t *)arg; break; case RT_TIMER_CTRL_SET_ONESHOT: timer->parent.flag &= ~RT_TIMER_FLAG_PERIODIC; break; case RT_TIMER_CTRL_SET_PERIODIC: timer->parent.flag |= RT_TIMER_FLAG_PERIODIC; break; } return RT_EOK; } RTM_EXPORT(rt_timer_control); ``` - 如果要設定 timer 為週期性的,添加 `RT_TIMER_FLAG_PERIODIC` --- ### 檢查 timer #### `rt_timer_check` :::info 功能 : 檢查 timer list ::: ```c=476 /** * This function will check timer list, if a timeout event happens, the * corresponding timeout function will be invoked. * * @note this function shall be invoked in operating system timer interrupt. */ void rt_timer_check(void) { struct rt_timer *t; rt_tick_t current_tick; register rt_base_t level; RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check enter\n")); current_tick = rt_tick_get(); /* disable interrupt */ level = rt_hw_interrupt_disable(); while (!rt_list_isempty(&rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1])) { t = rt_list_entry(rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next, struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]); /* * It supposes that the new tick shall less than the half duration of * tick max. */ if ((current_tick - t->timeout_tick) < RT_TICK_MAX / 2) { RT_OBJECT_HOOK_CALL(rt_timer_timeout_hook, (t)); /* remove timer from timer list firstly */ _rt_timer_remove(t); /* call timeout function */ t->timeout_func(t->parameter); /* re-get tick */ current_tick = rt_tick_get(); RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick)); if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) && (t->parent.flag & RT_TIMER_FLAG_ACTIVATED)) { /* start it */ t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; rt_timer_start(t); } else { /* stop timer */ t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; } } else break; } /* enable interrupt */ rt_hw_interrupt_enable(level); RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check leave\n")); } ``` --- ## memHeap :::info - 實體記憶體管理 - 和Memory Pool不可同時並用 - 可以根据用户的需求分配任意大小的記憶體 - 小記憶體動態管理 初始時,它是一塊大的內存。當需要分配記憶體時,將從這個大的內存塊上分割出相匹配的記憶體大小,然後把分割出來的空閒內存塊還回給管理系統。每個內存塊都包含一個管理用的數據頭,通過這個頭把使用塊與空閒塊用雙向鍊結的方式鏈接起來,如圖所示 1. magic – 變數(或稱為幻數),它會被初始化成0x1ea0(即英文單詞heap),用於標記這個內存塊是一個內存管理用的內存數據塊; 2. used - 指示出當前內存塊是否已經分配。 ![](https://i.imgur.com/G3fKTQk.png) ::: ### 初始化系统記憶體空間 #### `rt_system_heap_init(void* begin_addr, void* end_addr)` :::info |功能 |初始化系统記憶體空間| |-|-| |begin_addr |堆疊記憶體起始位址| |end_addr |堆疊記憶體结束位址| |函數返回|無| ::: ### 分配系统記憶體 #### ` rt_malloc(rt_size_t nbytes)` :::info |功能 |分配系统記憶體| |-|-| |nbytes |申请的記憶體大小| |函數返回|成功>返回分配的記憶體位址,失敗>返回RT_NULL| ::: ### 重分配系统記憶體 #### `rt_realloc(void *rmem, rt_size_t newsize)` :::info |功能 |重分配系统記憶體| |-|-| |rmem |指向已分配的記憶體| |newsize |重新分配的内存大小| |函數返回|返回重新分配的記憶體位址| ::: ### 分配多系统記憶體 #### `rt_calloc(rt_size_t count, rt_size_t size)` :::info 從記憶體堆中分配連續記憶體位址的多個記憶體 |功能 |分配多系统記憶體| |-|-| |count |記憶體數量| |size |記憶體大小| |函數返回|返回第一个記憶體的位址,並且將所有分配的記憶體初始化成零| ::: ### 釋放系统記憶體 #### `void rt_free (void *ptr)` :::info 從記憶體堆中分配連續記憶體位址的多個記憶體 |功能 |釋放系统記憶體| |-|-| |ptr| 等待釋放的記憶體指標| |函數返回|無| ::: --- ## memPool :::info - 虛擬記憶體管理 - 預先規劃一定數量的記憶體區塊,使得整個程式可以在執行期規劃 (allocate)、使用 (access)、歸還 (free) 記憶體區塊,加速記憶體的分配與釋放速度 - 分配記憶體:如下圖所示:先取出一塊記憶體空間,切割成大小相同的區塊利用鏈結連接,每次分配取出一個區塊給使用者 ![](https://i.imgur.com/ENzAc81.png) - 虛擬記憶體function ![](https://i.imgur.com/94QFGti.png) ::: ### 初始化Memory Pool #### `rt_mp_init` :::info |功能 |初始化Memory Pool| |-|-| |mp |記憶體對象| |name |記憶體名| |start |記憶體的起始位置| |size |記憶體數據區域大小| |block_size |記憶體容量| ::: ```c= /** * This function will initialize a memory pool object, normally which is used * for static object. * * @param mp the memory pool object * @param name the name of memory pool * @param start the star address of memory pool * @param size the total size of memory pool * @param block_size the size for each block * * @return RT_EOK */ rt_err_t rt_mp_init(struct rt_mempool *mp, const char *name, void *start, rt_size_t size, rt_size_t block_size) { rt_uint8_t *block_ptr; register rt_size_t offset; /* parameter check */ RT_ASSERT(mp != RT_NULL); RT_ASSERT(name != RT_NULL); RT_ASSERT(start != RT_NULL); RT_ASSERT(size > 0 && block_size > 0); /* initialize object */ rt_object_init(&(mp->parent), RT_Object_Class_MemPool, name); /* initialize memory pool */ mp->start_address = start; mp->size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE); /* align the block size */ block_size = RT_ALIGN(block_size, RT_ALIGN_SIZE); mp->block_size = block_size; /* align to align size byte */ mp->block_total_count = mp->size / (mp->block_size + sizeof(rt_uint8_t *)); mp->block_free_count = mp->block_total_count; /* initialize suspended thread list */ rt_list_init(&(mp->suspend_thread)); /* initialize free block list */ block_ptr = (rt_uint8_t *)mp->start_address; for (offset = 0; offset < mp->block_total_count; offset ++) { *(rt_uint8_t **)(block_ptr + offset * (block_size + sizeof(rt_uint8_t *))) = (rt_uint8_t *)(block_ptr + (offset + 1) * (block_size + sizeof(rt_uint8_t *))); } *(rt_uint8_t **)(block_ptr + (offset - 1) * (block_size + sizeof(rt_uint8_t *))) = RT_NULL; mp->block_list = block_ptr; return RT_EOK; } RTM_EXPORT(rt_mp_init); ``` ### 建立記憶體空間 #### `rt_mp_create` :::info 使用該函數可以創建一個與需求的記憶體空間大小、數目相匹配的記憶體空間,創建記憶體空間時,需要給記憶體空間指定一個名稱。然後CPU從系統中申請一個記憶體池對象,然後從記憶體堆中分配一塊由塊數目和塊大小計算得來的記憶體緩衝區,接著初始化記憶體空間,並將申請成功的記憶體緩衝區劃分成可用於分配的空閒。 |功能 |建立記憶體空間| |-|-| |name |記憶體空間名稱| |block_count|記憶體數量| |block_size |記憶體容量| ::: ```c= rt_mp_t rt_mp_create(const char *name, rt_size_t block_count, rt_size_t block_size) { rt_uint8_t *block_ptr; struct rt_mempool *mp; register rt_size_t offset; RT_DEBUG_NOT_IN_INTERRUPT; /* parameter check */ RT_ASSERT(name != RT_NULL); RT_ASSERT(block_count > 0 && block_size > 0); /* allocate object */ mp = (struct rt_mempool *)rt_object_allocate(RT_Object_Class_MemPool, name); /* allocate object failed */ if (mp == RT_NULL) return RT_NULL; /* initialize memory pool */ block_size = RT_ALIGN(block_size, RT_ALIGN_SIZE); mp->block_size = block_size; mp->size = (block_size + sizeof(rt_uint8_t *)) * block_count; /* allocate memory */ mp->start_address = rt_malloc((block_size + sizeof(rt_uint8_t *)) * block_count); if (mp->start_address == RT_NULL) { /* no memory, delete memory pool object */ rt_object_delete(&(mp->parent)); return RT_NULL; } mp->block_total_count = block_count; mp->block_free_count = mp->block_total_count; /* initialize suspended thread list */ rt_list_init(&(mp->suspend_thread)); /* initialize free block list */ block_ptr = (rt_uint8_t *)mp->start_address; for (offset = 0; offset < mp->block_total_count; offset ++) { *(rt_uint8_t **)(block_ptr + offset * (block_size + sizeof(rt_uint8_t *))) = block_ptr + (offset + 1) * (block_size + sizeof(rt_uint8_t *)); } *(rt_uint8_t **)(block_ptr + (offset - 1) * (block_size + sizeof(rt_uint8_t *))) = RT_NULL; mp->block_list = block_ptr; return mp; } RTM_EXPORT(rt_mp_create); ``` ### 删除記憶體(動態) #### `rt_mp_delete(rt_mp_t mp)` :::info 刪除記憶體空間時,會首先喚醒等待在該記憶體空間對像上的所有線程(返回-RT_ERROR),然 後再釋放已從內存堆上分配的記憶體空間數據存放區域,然後刪除記憶體空間對象。 |功能 |删除記憶體| |-|-| |mp |欲刪除的記憶體對象| ::: ### 删除記憶體(靜態) #### `rt_mp_detach(rt_mp_t mp)` :::info 脫離記憶體空間將把記憶體空間對像從內核對像管理器中刪除。脫離記憶體空間使用下面的函數接口 |功能 |删除記憶體| |-|-| |mp |返回的記憶體對象| ::: ### 分配記憶體 #### `rt_mp_alloc (rt_mp_t mp, rt_int32_t time)` :::info 如果記憶體空間中有可用的空間,則從空閒塊鍊錶上取下一個空間,減少空閒塊數目並返回這個記憶體空間;如果記憶體空間中已經沒有空閒記憶體空間,則判斷超時時間設置:若超時時間設置為零,則立刻返回空記憶體空間;若等待時間大於零,則把當前線程掛起在該記憶體空間對像上,直到記憶體空間中有可用的自由記憶體空間,或等待時間到達。 |功能 |分配記憶體| |-|-| |mp |記憶體對象| |time|超時時間| ::: ### 釋放記憶體 #### `rt_mp_free (void *block);` :::info |功能 |釋放記憶體| |-|-| |block |記憶體位置| ::: --- ## IPC (行程間通訊 Inter-Process Communication) :::info * 兩個行程或執行緒間傳送資料或訊號的技術或方法 * 多個行程溝通的方式,透過共享的記憶體來完成;而如果此記憶體沒有排他性,這個記憶體有可能會不同步。 ![](https://i.imgur.com/tHXhIfS.png) * 同一時間只允許一個行程去訪問這塊記憶體,避免數據出現不同步的情況 ::: ### 中斷 #### `rt_hw_interrupt_disable(void)` :::info - 使用時機 確保當前記憶體不會被搶占,除非這個行程主動放棄了處理器控制權 |功能|中斷| |-|-| |函數返回|呼叫此函數前的中斷狀態| ::: ### 恢復中斷 #### `rt_hw_interrupt_enable(rt_base_t level)` :::info - 功能 恢復調用rt_hw_interrupt_disable()函數前的中斷狀態 |功能|恢復中斷| |-|-| |level|前一次rt_hw_interrupt_disable返回的中斷狀態| |函數返回|呼叫此函數前的中斷狀態| ::: ### 信號 :::info - 信號量是一種輕型的用於解決線程間同步問題的內核對象,線程可以獲取或釋放它,從而達到同步或互斥的目的。信號量就像一把鑰匙,把一段臨界區給鎖住,只允許有鑰匙的線程進行訪問:線程拿到了鑰匙,才允許它進入臨界區;而離開後把鑰匙傳遞給排隊在後面的等待線程,讓後續線程依次進入臨界區。 - 臨界區段(Critical section)指的是一個存取共用資源(例如:共用裝置或是共用記憶體)的程式片段 ![](https://i.imgur.com/ctgeczk.png) ::: ### 信号量控制块 ```c= struct rt_semaphore { struct rt_ipc_object parent;/*继承自ipc_object类*/ rt_uint16_t value; /* 信号量的值 */ }; /* rt_sem_t是指向semaphore结构体的指针类型 */ typedef struct rt_semaphore* rt_sem_t; rt_semaphore对象从rt_ipc_object中派生,由IPC容器所管理。信号量的最大值是 65535。 ``` ### 創建信號 #### `rt_sem_create (const char* name, rt_uint32_t value, rt_uint8_t flag)` :::info - 功能 當調用這個函數時,系統將先分配一個semaphore對象,並初始化這個對象,然後初始化IPC對像以及與semaphore相關的部分。在創建信號量指定的參數中,信號量標誌參數決定了當信號量不可用時,多個線程等待的排隊方式。當選擇FIFO方式時,那麼等待線程隊列將按照先進先出的方式排隊,先進入的線程將先獲得等待的信號量;當選擇PRIO(優先級等待)方式時,等待線程隊列將按照優先級進行排隊,優先級高的等待線程將先獲得等待的信號量。 |功能|創建信號| |-|-| |name|信號量名稱| |value|信號量初始值| |flag|信號量標記可是用以下兩種| |函數返回|建成功返回創建的信號量指標;否則返回RT_NULL| #define RT_IPC_FLAG_FIFO 0x00 /* IPC参数采用FIFO方式*/ #define RT_IPC_FLAG_PRIO 0x01 /* IPC参数采用优先级方式*/ ::: ### 删除信號 #### `rt_sem_delete (rt_sem_t sem)` :::info - 功能 系統不再使用信號量時,可通過刪除信號量以釋放系統資源。 |功能|删除信號| |-|-| |sem|rt_sem_create創建處理的信號量物件| |函數返回|RT_EOK| ::: ### 初始化信號 #### `rt_sem_init (rt_sem_t sem, const char* name, rt_uint32_t value, rt_uint8_t flag)` :::info - 功能 對於靜態信號量對象,它的內存空間在編譯時期就被編譯器分配出來,放在數據段或ZI段上,此時使用信號量就不再需要使用rt_sem_create接口來創建它而只需在使用前對它進行初始化即可 |功能|初始化信號| |-|-| |sem|信號量物件| |name|信號量名稱| |value|信號量初始值| |flag|信號量標記可是用以下兩種| |函數返回|RT_EOK| ::: --- ## 期末報告 ### 文件系统 :::info - DFS簡介 DFS 是 RT-Thread 提供的虛擬文件系統組件,全稱爲 Device File System,即設備虛擬文件系統,文件系統的名稱使用類似 UNIX 文件、文件夾的風格,目錄結構如下圖所示 ![](https://i.imgur.com/mcx8WXA.png) - DFS架構 DFS 的層次架構如下圖所示,主要分爲 POSIX 接口層、虛擬文件系統層和設備抽象層 ![](https://i.imgur.com/Ph0dKxG.png) 在 Unix 系統中,普通文件、設備文件、網絡文件描述符是同一種文件描述符。而在 RT-Thread 操作系統中,使用 DFS 來實現這種統一性。有了這種文件描述符的統一性,我們就可以使用 poll/select 接口來對這幾種描述符進行統一輪詢,爲實現程序功能帶來方便。 使用 poll/select 接口可以阻塞地同時探測一組支持非阻塞的 I/O 設備是否有事件發生(如可讀,可寫,有高優先級的錯誤輸出,出現錯誤等等),直至某一個設備觸發了事件或者超過了指定的等待時間。這種機制可以幫助調用者尋找當前就緒的設備,降低編程的複雜度。 虛擬文件系統層:支持多種類型的文件系統,如 FatFS、RomFS、DevFS 等,並提供普通文件、設備文件、網絡文件描述符的管理。 - 文件類型 |類型|描述| |-|-| |DevFS |設備文件系統,在 RT-Thread 操作系統中開啓該功能後,可以將系統中的設備在 /dev 文件夾下虛擬成文件,使得設備可以按照文件的操作方式使用 read、write 等接口進行操作。| |elmfat FS |專爲小型嵌入式設備開發的一個兼容微軟 FAT 格式的文件系統,採用 ANSI C 編寫,具有良好的硬件無關性以及可移植性,是 RT-Thread 中最常用的文件系統類型。| |Jffs2 |一種日誌閃存文件系統。主要用於 NOR 型閃存,基於 MTD 驅動層,特點是:可讀寫的、支持數據壓縮的、基於哈希表的日誌型文件系統,並提供了崩潰 / 掉電安全保護,提供寫平衡支持等。| |NFS |網絡文件系統(Network File System)是一項在不同機器、不同操作系統之間通過網絡共享文件的技術。在操作系統的開發調試階段,可以利用該技術在主機上建立基於 NFS 的根文件系統,掛載到嵌入式設備上,可以很方便地修改根|文件系統的內容。 |RamFS |內存文件系統,它不能格式化,可以同時創建多個,在創建時可以指定其最大能使用的內存大小,優點是讀寫速度很快,但存在掉電丟失的風險。| |RomFS |一種簡單的、緊湊的、只讀的文件系統,不支持動態擦寫保存,按順序存放數據,因而支持應用程序以 XIP(execute In Place,片內運行) 方式運行,在系統運行時, 節省 RAM 空間。| |UFFS |超低功耗的閃存文件系統(Ultra-low-cost Flash File System)的簡稱。它是國人開發的、專爲嵌入式設備等小內存環境中使用 Nand Flash 的開源文件系統。與嵌入式中常使用的 Yaffs 文件系統相比具有資源佔用少、啓動速度快、免費等優勢。| ::: ### 創建文件 #### `int open(const char *pathname, int oflag, int mode)` :::info - 參數 |功能|創建文件| |-|-| |pathname|文件名稱| |oflag|打開文件的方式| |返回值|成功時打開文件的描述符序號,否则返回負數| ::: ```c= #include <rtthread.h> #include <dfs_posix.h> /* 當需要使用文件操作時,需要包含這個頭文件 */ /* 假設文件操作是在一個線程中完成*/ void file_thread() { int fd, size; char s[] = "RT-Thread Programmer!\n", buffer[80]; /* 打開/text.txt 作寫入,如果該文件不存在則建立該文件*/ fd = open("/text.txt", O_WRONLY | O_CREAT); if (fd >= 0) { write(fd, s, sizeof(s)); close(fd); } /* 打開/text.txt 準備作讀取動作*/ fd = open("/text.txt", O_RDONLY); if (fd >= 0) { size=read(fd, buffer, sizeof(buffer)); close(fd); } rt_kprintf("%s", buffer); } ``` ### 關閉文件 #### `int close(int fd)` :::info - 參數 |功能|關閉文件| |-|-| |fd|open()函数所返回的文件描述字| |返回值|無| ::: ### 讀取文件 #### `read(int fd, void *buf, size_t count)` :::info - 參數 |功能|讀取文件| |-|-| |fd|文件描述词| |buf|內存指標| |count|欲讀取的字節數量| |返回值|無| ::: ### 寫入文件 #### `write(int fd, const void *buf, size_t count)` :::info - 參數 |功能|寫入文件| |-|-| |fd|文件描述词| |buf|內存指標| |count|欲寫入的字節數量| |返回值|無| ::: 範例 ```c= /* * 代碼清單:文件讀寫例子 * 這個例子演示瞭如何讀寫一個文件,特別是寫的時候應該如何操作。 */ #include <rtthread.h> #include <dfs_posix.h> /* 當需要使用文件操作時,需要包含這個頭文件 */ #define TEST_FN "/test.dat" /* 測試用的數據和緩衝 */ static char test_data[120], buffer[120]; /* 文件讀寫測試 */ void readwrite(const char* filename) { int fd; int index, length; /* 只寫 & 創建 打開 */ fd = open(TEST_FN, O_WRONLY | O_CREAT | O_TRUNC, 0); if (fd < 0) { rt_kprintf("open file for write failed\n"); return; } /* 準備寫入數據 */ for (index = 0; index < sizeof(test_data); index ++) { test_data[index] = index + 27; } /* 寫入數據 */ length = write(fd, test_data, sizeof(test_data)); if (length != sizeof(test_data)) { rt_kprintf("write data failed\n"); close(fd); return; } /* 關閉文件 */ close(fd); /* 只寫並在末尾添加打開 */ fd = open(TEST_FN, O_WRONLY | O_CREAT | O_APPEND, 0); if (fd < 0) { rt_kprintf("open file for append write failed\n"); return; } length = write(fd, test_data, sizeof(test_data)); if (length != sizeof(test_data)) { rt_kprintf("append write data failed\n"); close(fd); return; } /* 關閉文件 */ close(fd); /* 只讀打開進行數據校驗 */ fd = open(TEST_FN, O_RDONLY, 0); if (fd < 0) { rt_kprintf("check: open file for read failed\n"); return; } /* 讀取數據(應該為第一次寫入的數據) */ length = read(fd, buffer, sizeof(buffer)); if (length != sizeof(buffer)) { rt_kprintf("check: read file failed\n"); close(fd); return; } /* 檢查數據是否正確 */ for (index = 0; index < sizeof(test_data); index ++) { if (test_data[index] != buffer[index]) { rt_kprintf("check: check data failed at %d\n", index); close(fd); return; } } /* 讀取數據(應該為第二次寫入的數據) */ length = read(fd, buffer, sizeof(buffer)); if (length != sizeof(buffer)) { rt_kprintf("check: read file failed\n"); close(fd); return; } /* 檢查數據是否正確 */ for (index = 0; index < sizeof(test_data); index ++) { if (test_data[index] != buffer[index]) { rt_kprintf("check: check data failed at %d\n", index); close(fd); return; } } /* 檢查數據完畢,關閉文件 */ close(fd); /* 打印結果 */ rt_kprintf("read/write done.\n"); } #ifdef RT_USING_FINSH #include <finsh.h> /* 輸出函數到finsh shell 命令行中 */ FINSH_FUNCTION_EXPORT(readwrite, perform file read and write test); #endif ``` ### 建立目錄 #### `int mkdir(const char *path, mode_t mode)` :::info - 參數 |功能|寫入文件| |-|-| |path|目錄名稱| |mode|目錄模式| |返回值|成功返回0,失败返回-1| ::: 範例 ```c= void file_thread(void* parameter) { int ret; /* 創建目錄*/ ret = mkdir("/web", 0x777); if(ret < 0) { /* 創建目錄失敗*/ rt_kprintf("mkdir error!\n"); } else { /* 創建目錄成功*/ rt_kprintf("mkdir ok!\n"); } } ``` ### 打開目錄 #### `opendir(const char* name)` :::info - 參數 |功能|寫入文件| |-|-| |name|目錄路徑名稱| |返回值|成功回傳目錄指標,失败回傳RT_NULL| ::: 範例 ```c= #include <dfs_posix.h> void dir_operation(void* parameter) { int result; DIR *dirp; /* 打開/web 目錄*/ dirp = opendir("/web"); if(dirp == RT_NULL) { rt_kprintf("open directory error!\n"); } else { /* 在這兒進行讀取目錄相關操作*/ /* ...... */ /* 關閉目錄 */ closedir(dirp); } } ``` ### 讀取目錄 #### `readdir(DIR *d)` :::info - 參數 |功能|寫入文件| |-|-| |d|目錄路徑名稱| |返回值|成功回傳目錄結構指標,失败回傳RT_NULL| ::: 範例 ```c= void dir_operation(void* parameter) { int result; DIR *dirp; struct dirent *d; /* 打開/web 目錄*/ dirp = opendir("/web"); if(dirp == RT_NULL) { rt_kprintf("open directory error!\n"); } else { /* 讀取目錄*/ while ((d = readdir(dirp)) != RT_NULL) { rt_kprintf("found %s\n", d->d_name); } /* 關閉目錄 */ closedir(dirp); } } ``` ### 關閉目錄 #### `closedir(DIR *d)` :::info - 參數 |功能|寫入文件| |-|-| |d|目錄路徑名稱| |返回值|成功回傳0,-1| :::