日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Rtthread线程源码分析

發布時間:2024/3/26 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Rtthread线程源码分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Rtthread線程源碼分析

/*** 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;//1. 創建一個RT_Object_Class_Thread類型的objectd對象thread = (struct rt_thread *)rt_object_allocate(RT_Object_Class_Thread,name);if (thread == RT_NULL)return RT_NULL;//2. 申請分配線程棧空間stack_start = (void *)RT_KERNEL_MALLOC(stack_size);if (stack_start == RT_NULL){/* allocate stack failure *///失敗需要先刪除該object并釋放內存rt_object_delete((rt_object_t)thread);return RT_NULL;}//3. 調用_rt_thread_init_rt_thread_init(thread,name,entry,parameter,stack_start,stack_size,priority,tick);return thread; }static 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) {/* init thread list */rt_list_init(&(thread->tlist));// 1. 指定線程入口函數和參數thread->entry = (void *)entry;thread->parameter = parameter;/* stack init *///2. 線程結構體初始化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 *)rt_thread_exit); #else //走else// 3. 調用rt_hw_stack_init 初始化棧,棧頂的值為 【棧首地址 + 棧大小 - 4】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 *)rt_thread_exit); #endif/* priority init */RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX);//初始化thread優先級成員thread->init_priority = priority;thread->current_priority = priority;thread->number_mask = 0; #if RT_THREAD_PRIORITY_MAX > 32thread->number = 0;thread->high_mask = 0; #endif/* tick init */thread->init_tick = tick;thread->remaining_tick = tick;/* error and flags */thread->error = RT_EOK;thread->stat = RT_THREAD_INIT;/* initialize cleanup function and user data */thread->cleanup = 0;thread->user_data = 0;/* initialize thread timer *///初始化線程timerrt_timer_init(&(thread->thread_timer),thread->name,rt_thread_timeout,thread,0,RT_TIMER_FLAG_ONE_SHOT);RT_OBJECT_HOOK_CALL(rt_thread_inited_hook, (thread));return RT_EOK; } rt_uint8_t *rt_hw_stack_init(void *tentry,void *parameter,rt_uint8_t *stack_addr,void *texit) {struct stack_frame *stack_frame;rt_uint8_t *stk;unsigned long i;stk = stack_addr + sizeof(rt_uint32_t);//傳進來的stack_addr 減去了4,所以這里加上4stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8);//向下8對齊,考慮到64bit平臺stk -= sizeof(struct stack_frame);//偏移到stack_frame的首地址stack_frame = (struct stack_frame *)stk;/* init all register */for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++){((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef;}//這些寄存器是線程調度時自動加載到寄存器中去的,剩下的r4-r11需要手動加載stack_frame->exception_stack_frame.r0 = (unsigned long)parameter; /* r0 : argument */stack_frame->exception_stack_frame.r1 = 0; /* r1 */stack_frame->exception_stack_frame.r2 = 0; /* r2 */stack_frame->exception_stack_frame.r3 = 0; /* r3 */stack_frame->exception_stack_frame.r12 = 0; /* r12 *//*線程函數退出時會執行,退出時會將該函數當作返回的地址*/stack_frame->exception_stack_frame.lr = (unsigned long)texit; /* lr */stack_frame->exception_stack_frame.pc = (unsigned long)tentry; /* entry point, pc */stack_frame->exception_stack_frame.psr = 0x01000000L; /* PSR XPSR bit24 為1,使用thumb指令集*/#if USE_FPUstack_frame->flag = 0; #endif /* USE_FPU *//* return task's current stack address */return stk; }

棧初始化后的布局

rt_thread_startup

rt_thread_startup函數主要作用是將當前init完成的線程從SUSPEND狀態切換到READY狀態,
將該thread從tlist鏈表中移除,插入到就緒鏈表。

/*** 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 > 32thread->number = thread->current_priority >> 3; /* 5bit */thread->number_mask = 1L << thread->number;thread->high_mask = 1L << (thread->current_priority & 0x07); /* 3bit */ #elsethread->number_mask = 1L << thread->current_priority;//計算當前number_mask #endifRT_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; //將init狀態切換到SUSPEND狀態/* then resume it */rt_thread_resume(thread); //調用resume將該thread切換到ready狀態if (rt_thread_self() != RT_NULL)//開第一個系統線程的時候不會走這里{/* do a scheduling */rt_schedule();}return RT_EOK; } /*** 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 *///將該tlist從thread中移除rt_list_remove(&(thread->tlist));rt_timer_stop(&thread->thread_timer);/* enable interrupt */rt_hw_interrupt_enable(temp);/* insert to schedule ready list *///將該線程插入ready list,將tlist掛載到rt_thread_priority_table中去rt_schedule_insert_thread(thread);RT_OBJECT_HOOK_CALL(rt_thread_resume_hook, (thread));return RT_EOK; }/*** @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;register rt_ubase_t highest_ready_priority;#if RT_THREAD_PRIORITY_MAX > 32register rt_ubase_t number;number = __rt_ffs(rt_thread_ready_priority_group) - 1;highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1; #else//快速查找最高優先級線程,時間復雜度固定的,RTOS系統關鍵部分highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1; #endif/* get switch to thread */to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,struct rt_thread,tlist);rt_current_thread = to_thread;/* switch to new thread *///線程調度實現:rt_hw_context_switch_to((rt_uint32_t)&to_thread->sp);/* never come back */ } /** void rt_hw_context_switch_to(rt_uint32 to);* r0 --> to*/ .global rt_hw_context_switch_to .type rt_hw_context_switch_to, %function rt_hw_context_switch_to://將rt_hw_context_switch_to的參數(rt_uint32_t)&to_thread->sp sp的地址保存到rt_interrupt_to_threadLDR r1, =rt_interrupt_to_threadSTR r0, [r1]#if defined (__VFP_FP__) && !defined(__SOFTFP__)/* CLEAR CONTROL.FPCA */MRS r2, CONTROL /* read */BIC r2, #0x04 /* modify */MSR CONTROL, r2 /* write-back */ #endif/* set from thread to 0 *///第一次切換線程,無需保存上文,rt_interrupt_from_thread寫0LDR r1, =rt_interrupt_from_threadMOV r0, #0x0STR r0, [r1]/* set interrupt flag to 1 *///將rt_thread_switch_interrupt_flag 置1LDR r1, =rt_thread_switch_interrupt_flagMOV r0, #1STR r0, [r1]/* set the PendSV and SysTick exception priority *///將systick和pendsv優先級都設置為最低LDR r0, =NVIC_SYSPRI2LDR r1, =NVIC_PENDSV_PRILDR.W r2, [r0,#0x00] /* read */ORR r1,r1,r2 /* modify */STR r1, [r0] /* write-back *///寫28bit 置1將懸起Pendsv中斷,如果當前沒有其他中斷發生,那么將進入pendsv handlerLDR r0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */LDR r1, =NVIC_PENDSVSETSTR r1, [r0]/* restore MSP */LDR r0, =SCB_VTOR //獲取SCB_VTOR寄存器的地址LDR r0, [r0] //獲取SCB_VTOR寄存器的值,該值保存向量表的地址LDR r0, [r0] //獲取向量表偏移為0的值,即為MSP指針(啟動文件中向量表的排布)NOPMSR msp, r0 //復位MSP/* enable interrupts at processor level */CPSIE F //使能中斷和異常CPSIE I/* never reach here! */

懸起一個pendsv異常后,在沒有其他中斷或者異常發生的時候,就會進入pendsv中切換上下文:

/* r0 --> switch from thread stack* r1 --> switch to thread stack* psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack*/ .global PendSV_Handler .type PendSV_Handler, %function PendSV_Handler:/* disable interrupt to protect context switch *///上下文切換之前先要禁用中斷,保證切換不被打斷MRS r2, PRIMASKCPSID I/* get rt_thread_switch_interrupt_flag *///判斷rt_thread_switch_interrupt_flag,為0則退出pendsv handlerLDR r0, =rt_thread_switch_interrupt_flagLDR r1, [r0]CBZ r1, pendsv_exit /* pendsv already handled *//* clear rt_thread_switch_interrupt_flag to 0 *///清理rt_thread_switch_interrupt_flag MOV r1, #0x00STR r1, [r0]//判斷是否需要保存上文,啟動第一個線程的時候不需要保存上文。LDR r0, =rt_interrupt_from_threadLDR r1, [r0]CBZ r1, switch_to_thread /* skip register save at the first time *///保存上文:獲取上文psp的值MRS r1, psp /* get from thread stack pointer */#if defined (__VFP_FP__) && !defined(__SOFTFP__)TST lr, #0x10 /* if(!EXC_RETURN[4]) */VSTMDBEQ r1!, {d8 - d15} /* push FPU register s16~s31 */ #endif//將R4-R11手動保存到棧中,其他寄存器都已經由硬件自動入棧保存了。//相當于: r1 -= 4*(11 - 4) for(i = 0; i < 11 - 4; i++) r4 -> r11 入棧STMFD r1!, {r4 - r11} /* push r4 - r11 register */#if defined (__VFP_FP__) && !defined(__SOFTFP__)MOV r4, #0x00 /* flag = 0 */TST lr, #0x10 /* if(!EXC_RETURN[4]) */MOVEQ r4, #0x01 /* flag = 1 */STMFD r1!, {r4} /* push flag */ #endif//更新棧變量的值為 當前棧指針指向的棧地址LDR r0, [r0]STR r1, [r0] /* update from thread stack pointer *///下文切換: switch_to_thread://獲取棧指針的值LDR r1, =rt_interrupt_to_threadLDR r1, [r1]LDR r1, [r1] /* load thread stack pointer */#if defined (__VFP_FP__) && !defined(__SOFTFP__)LDMFD r1!, {r3} /* pop flag */ #endif//手動將r4-r11出棧,寫入對應的寄存器中。LDMFD r1!, {r4 - r11} /* pop r4 - r11 register */#if defined (__VFP_FP__) && !defined(__SOFTFP__)CMP r3, #0 /* if(flag_r3 != 0) */VLDMIANE r1!, {d8 - d15} /* pop FPU register s16~s31 */ #endif//將r1(當前棧地址) 寫入psp, 在異常返回時硬件會主動Load r0 r1...這些寄存器MSR psp, r1 /* update stack pointer */#if defined (__VFP_FP__) && !defined(__SOFTFP__)ORR lr, lr, #0x10 /* lr |= (1 << 4), clean FPCA. */CMP r3, #0 /* if(flag_r3 != 0) */BICNE lr, lr, #0x10 /* lr &= ~(1 << 4), set FPCA. */ #endifpendsv_exit:/* restore interrupt */MSR PRIMASK, r2//在進入異常服務程序后,LR的值被自動更新為特殊的EXC_RETURN,這//是一個高28位全為1的值,只有[3:0]的值有特殊含義//bit2 == 1 從進程堆棧中做出棧操作,返回后使用PSPORR lr, lr, #0x04BX lr

到這里線程main線程就會開始啟動了,啟動之后,systick定時器會在各個線程時間片耗盡之后觸發pendsv切換
線程。

void SysTick_Handler(void) {/* enter interrupt */rt_interrupt_enter();rt_tick_increase();/* leave interrupt */rt_interrupt_leave(); } /*** This function will notify kernel there is one tick passed. Normally,* this function is invoked by clock ISR.*/ void rt_tick_increase(void) {struct rt_thread *thread;/* increase the global tick */++ rt_tick;//計時器+1 單位ms/* check time slice */thread = rt_thread_self();//獲取當前線程-- thread->remaining_tick;//線程時間片-1if (thread->remaining_tick == 0)//時間片耗盡{/* change to initialized tick */thread->remaining_tick = thread->init_tick;//時間片重新賦值/* yield */rt_thread_yield();//線程掛起}/* check timer */rt_timer_check(); } /*** This function will let current thread yield processor, and scheduler will* choose a highest thread to run. After yield processor, the current thread* is still in READY state.** @return RT_EOK*/ rt_err_t rt_thread_yield(void) {register rt_base_t level;struct rt_thread *thread;/* disable interrupt */level = rt_hw_interrupt_disable();/* set to current thread */thread = rt_current_thread;/* if the thread stat is READY and on ready queue list */if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY &&thread->tlist.next != thread->tlist.prev)//線程時ready狀態并且掛載在就緒表中{/* remove thread from thread list */rt_list_remove(&(thread->tlist));/* put thread to end of ready queue */rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),&(thread->tlist));//將當前線程插入末尾/* enable interrupt */rt_hw_interrupt_enable(level);rt_schedule();//開啟線程調度return RT_EOK;}/* enable interrupt */rt_hw_interrupt_enable(level);return RT_EOK; }/*** This function will perform one schedule. It will select one thread* with the highest priority level, then switch to it.*/ void rt_schedule(void) {rt_base_t level;struct rt_thread *to_thread;struct rt_thread *from_thread;/* disable interrupt */level = rt_hw_interrupt_disable();/* check the scheduler is enabled or not */if (rt_scheduler_lock_nest == 0)//rt_scheduler_lock_nest 用來鎖住rt_schedule,確保有些場景不能被打斷{register rt_ubase_t highest_ready_priority;#if RT_THREAD_PRIORITY_MAX <= 32//獲取就緒表中優先級最高的線程下標highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1; #elseregister rt_ubase_t number;number = __rt_ffs(rt_thread_ready_priority_group) - 1;highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1; #endif/* get switch to thread *///獲取將要切換的線程實例to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,struct rt_thread,tlist);/* if the destination thread is not the same as current thread */if (to_thread != rt_current_thread){rt_current_priority = (rt_uint8_t)highest_ready_priority;from_thread = rt_current_thread;rt_current_thread = to_thread;RT_OBJECT_HOOK_CALL(rt_scheduler_hook, (from_thread, to_thread));/* switch to new thread */RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,("[%d]switch to priority#%d ""thread:%.*s(sp:0x%p), ""from thread:%.*s(sp: 0x%p)\n",rt_interrupt_nest, highest_ready_priority,RT_NAME_MAX, to_thread->name, to_thread->sp,RT_NAME_MAX, from_thread->name, from_thread->sp));#ifdef RT_USING_OVERFLOW_CHECK_rt_scheduler_stack_check(to_thread); #endifif (rt_interrupt_nest == 0){rt_hw_context_switch((rt_ubase_t)&from_thread->sp,(rt_ubase_t)&to_thread->sp);/* enable interrupt */rt_hw_interrupt_enable(level);return ;}else{RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("switch in interrupt\n"));rt_hw_context_switch_interrupt((rt_ubase_t)&from_thread->sp,(rt_ubase_t)&to_thread->sp);}}}/* enable interrupt */rt_hw_interrupt_enable(level); } /** void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);* r0 --> from* r1 --> to*/ .global rt_hw_context_switch_interrupt .type rt_hw_context_switch_interrupt, %function .global rt_hw_context_switch .type rt_hw_context_switch, %functionrt_hw_context_switch_interrupt: rt_hw_context_switch:/* set rt_thread_switch_interrupt_flag to 1 */LDR r2, =rt_thread_switch_interrupt_flagLDR r3, [r2]CMP r3, #1BEQ _reswitch //判斷rt_thread_switch_interrupt_flag是否為1,為1說明上一次線程切換沒有完成,跳轉到_reswitch MOV r3, #1 //rt_thread_switch_interrupt_flag 為0,將其置1STR r3, [r2]LDR r2, =rt_interrupt_from_thread /* set rt_interrupt_from_thread */STR r0, [r2] //將上文中的棧指針的地址保存到rt_interrupt_from_thread _reswitch:LDR r2, =rt_interrupt_to_thread /* set rt_interrupt_to_thread */STR r1, [r2] //將下文中的棧指針地址保存到rt_interrupt_to_thread LDR r0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */LDR r1, =NVIC_PENDSVSET STR r1, [r0] //懸起pendsvBX LR //異常返回

線程退出

當線程函數退出時會將lr的值load到pc中,因為在初始化線程棧時,LR的值我們設置的是rt_thread_exit,所以
線程函數退出時會call這個函數。

void rt_thread_exit(void) {struct rt_thread *thread;register rt_base_t level;/* get current thread */thread = rt_current_thread;//獲取當前退出的線程/* 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;//設置線程狀態為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);//將系統線程從object管理系統中移除}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); }

線程分離/刪除

線程分離和線程刪除函數差別如下:
線程分離函數可以將靜態線程從object中移除,線程刪除函數則只能將動態分配的線程移除到僵尸線程表中

/*** 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));//這個判斷不對,RT_ASSERT宏默認關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);//棧中分配的線程直接從object管理表中移除}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; }/*** 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; } #endif

線程定時

/*** 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;/* disable interrupt */temp = rt_hw_interrupt_disable();/* set to current thread */thread = rt_current_thread;RT_ASSERT(thread != RT_NULL);RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);/* 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; } /*** 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 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));if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_READY){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 stat */rt_schedule_remove_thread(thread);//將該線程從就緒表中移除thread->stat = RT_THREAD_SUSPEND | (thread->stat & ~RT_THREAD_STAT_MASK);//將狀態設置為RT_THREAD_SUSPEND /* 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; } /*** This function will control thread behaviors according to control command.** @param thread the specified thread to be controlled* @param cmd the control command, which includes* RT_THREAD_CTRL_CHANGE_PRIORITY for changing priority level of thread;* RT_THREAD_CTRL_STARTUP for starting a thread;* RT_THREAD_CTRL_CLOSE for delete a thread;* RT_THREAD_CTRL_BIND_CPU for bind the thread to a CPU.* @param arg the argument of control command** @return RT_EOK*/ rt_err_t rt_thread_control(rt_thread_t thread, int cmd, void *arg) {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);switch (cmd){case RT_THREAD_CTRL_CHANGE_PRIORITY: //改變線程優先級/* disable interrupt */temp = rt_hw_interrupt_disable();/* for ready thread, change queue */if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY) //線程在就緒表中{/* remove thread from schedule queue first */rt_schedule_remove_thread(thread); //先將該線程移除/* change thread priority */thread->current_priority = *(rt_uint8_t *)arg; //修改線程優先級/* recalculate priority attribute */ #if RT_THREAD_PRIORITY_MAX > 32thread->number = thread->current_priority >> 3; /* 5bit */thread->number_mask = 1 << thread->number;thread->high_mask = 1 << (thread->current_priority & 0x07); /* 3bit */ #elsethread->number_mask = 1 << thread->current_priority;//設置優先級mask #endif/* insert thread to schedule queue again */rt_schedule_insert_thread(thread);//修改好優先級后重新插入線程表}else //線程未在就緒表中{thread->current_priority = *(rt_uint8_t *)arg;/* recalculate priority attribute */ #if RT_THREAD_PRIORITY_MAX > 32thread->number = thread->current_priority >> 3; /* 5bit */thread->number_mask = 1 << thread->number;thread->high_mask = 1 << (thread->current_priority & 0x07); /* 3bit */ #elsethread->number_mask = 1 << thread->current_priority; #endif}/* enable interrupt */rt_hw_interrupt_enable(temp);break;case RT_THREAD_CTRL_STARTUP://啟動線程return rt_thread_startup(thread);case RT_THREAD_CTRL_CLOSE://關閉線程/分離線程if (rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE)//靜態線程使用detech{return rt_thread_detach(thread);} #ifdef RT_USING_HEAPelse //動態線程使用delete{return rt_thread_delete(thread);} #endifdefault:break;}return RT_EOK; } /*** This function will lock the thread scheduler.*/ //該函數會使rt_scheduler_lock_nest ++,從而鎖住scheduler,確保在解鎖之前當前代碼段不會被scheduler中斷執行 void rt_enter_critical(void) {register rt_base_t level;/* disable interrupt */level = rt_hw_interrupt_disable();/** the maximal number of nest is RT_UINT16_MAX, which is big* enough and does not check here*/rt_scheduler_lock_nest ++;/* enable interrupt */rt_hw_interrupt_enable(level); }/*** This function will unlock the thread scheduler.*/ void rt_exit_critical(void) {register rt_base_t level;/* disable interrupt */level = rt_hw_interrupt_disable();rt_scheduler_lock_nest --;if (rt_scheduler_lock_nest <= 0){rt_scheduler_lock_nest = 0;/* enable interrupt */rt_hw_interrupt_enable(level);if (rt_current_thread){/* if scheduler is started, do a schedule *///這里因為如果線程systic timer超時了,本來需要做rt_schedule,但是因為rt_schedule被鎖住,而沒有做//所以會在解鎖后做一次,如果該線程確實超時,那么就會執行shedule,線程時間片還沒耗盡的話,因為它的優先級是排在//最前的,所以rt_schedule中會有判斷當前from和to的線程是一致的,就不會切換。rt_schedule();}}else{/* enable interrupt */rt_hw_interrupt_enable(level);} } /*** This function is the timeout function for thread, normally which is invoked* when thread is timeout to wait some resource.** @param parameter the parameter of thread timeout function*/ void rt_thread_timeout(void *parameter) {struct rt_thread *thread;thread = (struct rt_thread *)parameter;/* thread check */RT_ASSERT(thread != RT_NULL);RT_ASSERT((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND);RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);/* set error number */thread->error = -RT_ETIMEOUT;/* remove from suspend list */rt_list_remove(&(thread->tlist));//do nothing/* insert to schedule ready list */rt_schedule_insert_thread(thread);//將線程插入到就緒表/* do schedule */rt_schedule(); }/*** This function will find the specified thread.** @param name the name of thread finding** @return the found thread** @note please don't invoke this function in interrupt status.*/ rt_thread_t rt_thread_find(char *name) {return (rt_thread_t)rt_object_find(name, RT_Object_Class_Thread); }

Rtthread thread 內部timer作用:

thread結構體中包含一個timer成員:

struct rt_timer thread_timer; /**< built-in thread timer */

在init_thread函數里面會對其進行初始化:

/* initialize thread timer */rt_timer_init(&(thread->thread_timer),thread->name,rt_thread_timeout,thread,0,RT_TIMER_FLAG_ONE_SHOT);

這里設置的超時回調函數為rt_thread_timeout,初始超時時間為0,RT_TIMER_FLAG_ONE_SHOT
為單次定時事件。
再看看rt_thread_timeout實現:
定時時間超時的時候會調用該函數,函數參數為該線程的信息。
主要做了如下操作:
1.設置thread->error 為 -RT_ETIMEOUT
2.移除當前線程節點
3.將該線程再次插入到就緒列表
4.執行線程調度

void rt_thread_timeout(void *parameter) {struct rt_thread *thread;thread = (struct rt_thread *)parameter;/* thread check */RT_ASSERT(thread != RT_NULL);RT_ASSERT((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND);RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);/* set error number */thread->error = -RT_ETIMEOUT;///* remove from suspend list */rt_list_remove(&(thread->tlist));/* insert to schedule ready list */rt_schedule_insert_thread(thread);/* do schedule */rt_schedule(); }

那么什么時候會執行上述超時函數呢?
答案是在調用rt_thread_delay(rt_tick_t tick)的時候,rt_thread_delay會調用rt_thread_sleep
調用rt_thread_sleep的時候,函數執行下面的動作:
1.先調用rt_thread_suspend(thread)將當前線程休眠,移出就緒表。
2.調用rt_timer_control設置定時時間(休眠時間)。
3.調用rt_timer_start開啟定時。
4.因為當前線程已經休眠,所以需要調用rt_schedule()調度到新的線程執行。
5.將thread->error = RT_EOK

rt_err_t rt_thread_delay(rt_tick_t tick) {return rt_thread_sleep(tick); } rt_err_t rt_thread_sleep(rt_tick_t tick) {register rt_base_t temp;struct rt_thread *thread;/* disable interrupt */temp = rt_hw_interrupt_disable();/* set to current thread */thread = rt_current_thread;RT_ASSERT(thread != RT_NULL);RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);/* 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; }

這樣當線程delay或者休眠時就會讓出cpu,并在休眠時間到達目標值時通過rt_thread_timeout執行新的
調度。
rt_tick_increase函數會在systick中斷中被調用,每次調用都會調用timer模塊的rt_timer_check函數檢查
是否有新的超時事件.
當線程被調用detech或者delete的時候,線程的detech/delete函數也會分別調用線程timer的detech/delete,
將該timer從object中移除。

總結

以上是生活随笔為你收集整理的Rtthread线程源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 亚洲成av人在线观看 | 亚洲欧美视频在线播放 | av影视在线观看 | av福利站 | 日本欧美www | 97人人模人人爽人人少妇 | 丝袜黄色片 | 一区二区三区av夏目彩春 | 西西人体做爰大胆gogo直播 | 欧美精品韩国精品 | 亚洲性免费 | 国产精品短视频 | 精品久久久久成人码免费动漫 | www.一区二区三区四区 | 激情第四色 | 成人亚洲精品久久久久软件 | 毛片2| 日本aⅴ视频 | 欧美三级a做爰在线观看 | 亚洲欧美激情在线观看 | 黄色伊人 | 韩国av电影在线观看 | 免费久久久久久 | 在线国产区 | 久久久久久久久久久网站 | 欧美黄色一级生活片 | 亚洲精品aaa | 欧美久久久久久久 | 噜噜噜av| 亚洲免费a| 国产crm系统91在线 | 精品久久免费视频 | 国产久久精品 | www.av视频在线观看 | 精品欧美乱码久久久久久 | 人妻少妇精品无码专区久久 | 欧美性猛交 | 亚洲精品在线网站 | 亚洲色图图片区 | www.男人的天堂.com | 深夜视频在线观看 | 日欧视频 | 中国黄色三级 | 国产伦精品一区二区三区视频孕妇 | 午夜在线精品偷拍 | 蜜臀99久久精品久久久久久软件 | 天天艹天天| 日日爱669 | 农民工hdxxxx性中国 | 国产精品操 | 青青艹在线视频 | 国产免费又黄又爽又色毛 | 夜夜春影院 | 欧美精品网站 | 亚洲一一在线 | 国产三级在线免费 | 成人精品视频 | 九九热视频在线播放 | 亚洲国产成人精品久久 | 国产精品日韩专区 | 欧美我不卡 | 国产在线观看一区二区三区 | 女人张开双腿让男人捅 | 免费三片60分钟 | 雪白的扔子视频大全在线观看 | 中文字幕免费视频观看 | 丰满双乳秘书被老板狂揉捏 | 国产黄色成人 | 日本后进式猛烈xx00动态图 | 国产91网 | 国产一区二区三区四区在线观看 | 久久久综合色 | 日日干日日草 | 4444亚洲人成无码网在线观看 | 日韩午夜在线观看 | free欧美性69护士呻吟 | 超碰人体 | 99在线精品视频免费观看20 | 一级淫片a | 华丽的外出在线 | 5级黄色片 | 青娱乐超碰 | 色哟哟日韩精品 | 在线观看免费看片 | 97久久精品| 亚洲播放| 欧美精产国品一二三区 | 一级全黄少妇性色生活片 | 国产精品jizz在线观看无码 | 日韩欧美一区视频 | 免费毛片一区二区三区久久久 | 丁香六月久久 | 扒开女人屁股进去 | 麻豆视频官网 | 那里可以看毛片 | 国产裸体永久免费视频网站 | 女上男下动态图 | 91一区二区三区四区 | 欧美被狂躁喷白浆精品 |