;/*; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);; * r0 --> from; * r1 --> to; */rt_hw_context_switch_interruptEXPORT rt_hw_context_switch_interruptrt_hw_context_switch PROCEXPORT rt_hw_context_switch
; set rt_thread_switch_interrupt_flag to 1LDR r2, =rt_thread_switch_interrupt_flagLDR r3, [r2]CMP r3, #1BEQ _reswitchMOV r3, #1STR r3, [r2]LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_threadSTR r0, [r2]_reswitchLDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_threadSTR r1, [r2]LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch)LDR r1, =NVIC_PENDSVSETSTR r1, [r0]BX LRENDP; r0 --> swith from thread stack; r1 --> swith to thread stack; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stackPendSV_Handler PROCEXPORT PendSV_Handler; disable interrupt to protect context switchMRS r2, PRIMASKCPSID I; get rt_thread_switch_interrupt_flagLDR r0, =rt_thread_switch_interrupt_flagLDR r1, [r0]CBZ r1, pendsv_exit ; pendsv already handled; clear rt_thread_switch_interrupt_flag to 0MOV r1, #0x00STR r1, [r0]LDR r0, =rt_interrupt_from_threadLDR r1, [r0]CBZ r1, swtich_to_thread ; skip register save at the first timeMRS r1, psp ; get from thread stack pointerSTMFD r1!, {r4 - r11} ; push r4 - r11 registerLDR r0, [r0]STR r1, [r0] ; update from thread stack pointerswtich_to_threadLDR r1, =rt_interrupt_to_threadLDR r1, [r1]LDR r1, [r1] ; load thread stack pointerLDMFD r1!, {r4 - r11} ; pop r4 - r11 registerMSR psp, r1 ; update stack pointerpendsv_exit; restore interruptMSR PRIMASK, r2ORR lr, lr, #0x04BX lrENDP
rt_thread_switch_interrupt_flag 这个变量有历史原因,也有cortex-m3上的特殊意义:rt_thread_switch_interrupt_flag 通常会做为中断服务例程中触发了线程上下文切换的标志。因为RT-thread支持中断嵌套,所以在最后一个中断服务例程退出时,将检查这个变量。如果置1,那么进行线程上下文切换,否则返回被中断的线程。cortex-m3上,因为pendsv的特殊存在,所以上下文切换过程是先触发一个pendsv异常,然后再进行切换。pendsv的优先级被设置成最低,那么在中断服务例程中如果需要进行上下文切换,也可以去触发一个pendsv异常,并且这个pendsv异常总会在所有中断服务例程都处理完以后被处理。既然都是pendsv异常切换,所以每次切换 rt_thread_switch_interrupt_flag 这个变量都会被置位。但是cortex-m3的中断处理是复杂的,当一个pendsv被处理时,有可能一个新的中断到来,这个中断优先级会比pendsv异常优先级要高,所以处理器会自动抢占pendsv的上下文,去服务高优先级的中断。根据被抢占时刻的不同, rt_thread_switch_interrupt_flag 变量用于记录是否完成了上下文的切换(其实也意味着pendsv一次处理完全完成)。
那么在cortex-m3上这个标志仅仅是用作记录?即便没有这个标志,高优先级中断结束后,pendsv也能继续完成上下文切换吧?
,---. Rogerz Zhang ( @ @ ) Human, not octopus ).-.( Chase what you love. Let the rest go. '/|||\` Share > Google+ | Note > Tumblr | Random > twitter 微博 '|` AsciiArt < Shimrod(hh)

PendSV_Handler PROC
EXPORT PendSV_Handler
; disable interrupt to protect context switch
MRS r2, PRIMASK
CPSID I
模拟器测试了一下。在PendSV的处理代码之后再次添加触发PendSV异常的代码矮油,既然看那个 flag 的作用,就看它在哪里被读取了,哪里被写入了就好了么~ grep 了一下,它只有在 libcpu 里才出现,可见其完全是体系相关的(或者是很底层的)。对于 cortex-m3 (小弟暂时只熟悉这个架构),对它的读取在 prife 在第一帖里基本已经都引用了,即跳过取 rt_interrupt_from_thread 的过程,并且在 PendSV 里直接退出。然后对那个 flag 修改的地方只有一处,即在 rt_hw_context_switch_to 里把它设置为1了。而 rt_hw_context_switch_to 是在做第一次进程切换的时候使用的,这时候显然没有 rt_interrupt_from_thread,而且这时候系统很干净, SP 神马的都已经在外面设置好了(rt_system_scheduler_start 函数),所以这时候既不用取旧的线程,也不用进行线程的上下文切换~
熊大说还有历史遗留的作用,别的体系架构还不熟悉还没有来得及看。--Cheers,
Grissiom
矮油,既然看那个 flag 的作用,就看它在哪里被读取了,哪里被写入了就好了么~ grep 了一下,它只有在 libcpu 里才出现,可见其完全是体系相关的(或者是很底层的)。对于 cortex-m3 (小弟暂时只熟悉这个架构),对它的读取在 prife 在第一帖里基本已经都引用了,即跳过取 rt_interrupt_from_thread 的过程,并且在 PendSV 里直接退出。然后对那个 flag 修改的地方只有一处,即在 rt_hw_context_switch_to 里把它设置为1了。而 rt_hw_context_switch_to 是在做第一次进程切换的时候使用的,这时候显然没有 rt_interrupt_from_thread,而且这时候系统很干净, SP 神马的都已经在外面设置好了(rt_system_scheduler_start 函数),所以这时候既不用取旧的线程,也不用进行线程的上下文切换~

之所以提这个问题,是因为仿真了多次,发现每次在PendSV的处理函数中,rt_thread_switch_interrupt_flag 都是1,也就是说这个变量似乎从来没有在PendSV Handler中起过作用。所以我是想知道为什么需要这个变量。另外,又仔细考虑了一下,我觉得PendSV异常在硬件入栈期间如果被抢占的话,应该是有问题的。第一次被更高优先级的中断抢占的PendSV异常,硬件会自动为其设置悬起位,那么就是说,在更高级的中断中再执行Scheduler函数时,调用context_switch,它的结束会第二次触发PendSV异常,可是在硬件的中断状态寄存器中,PendSV的悬起位已经为1,那么再次悬起又有什么意义呢? 所以我觉得bernard说会执行两次PendSV的处理函数是不可能的。
反证法:如果真的可以执行两次的话,如果PendSV被抢占多次,岂不是要在最后一个中断返回之后,执行多次PendSV的处理函数? 但是硬件中断状态寄存器中对于PendSV的悬起位只有一个bit。我觉得正常的执行流程应该如下图。不过尚缺少实验证明。因为这种在PendSV响应的硬件入栈8个寄存器的过程中出现高优先级中断抢占的情况不好复现。所以上面只是单纯的理论分析。
在 2011年12月29日 下午5:50,Grissiom <chaos....@gmail.com>写道:
矮油,既然看那个 flag 的作用,就看它在哪里被读取了,哪里被写入了就好了么~ grep 了一下,它只有在 libcpu 里才出现,可见其完全是体系相关的(或者是很底层的)。对于 cortex-m3 (小弟暂时只熟悉这个架构),对它的读取在 prife 在第一帖里基本已经都引用了,即跳过取 rt_interrupt_from_thread 的过程,并且在 PendSV 里直接退出。然后对那个 flag 修改的地方只有一处,即在 rt_hw_context_switch_to 里把它设置为1了。而 rt_hw_context_switch_to 是在做第一次进程切换的时候使用的,这时候显然没有 rt_interrupt_from_thread,而且这时候系统很干净, SP 神马的都已经在外面设置好了(rt_system_scheduler_start 函数),所以这时候既不用取旧的线程,也不用进行线程的上下文切换~熊大说还有历史遗留的作用,别的体系架构还不熟悉还没有来得及看。--Cheers,
Grissiom
--
把有限的时间投入到无限的学习中去
只要是“硬件”入栈 PendSV,那么就说明有 schedule 发生了,这时候被换出的线程被保存在了 from_thread 那个变量里,to_thread 变量存储的是要换进来的线程,并且 flag = 1。如果在硬件入栈的时候发生中断,那么, cortex-m3 会在入栈之后执行高优先级的中断(必然不是 PendSV),而挂起 PendSV。假设在此中断例程中调用了 schedule,那么它看到 flag == 1 了,就不会再去保存旧的线程地址到 from_thread 了,原因很简单,旧的线程始终没变~然后 PendSV 里对 flag 做的跳转保证了 PendSV 只执行一次。
再有,就算是在 cortex-m3 里 PendSV 不会被引发好多次,也不能保证在别的体系结构里也有相同的结果。所以这个标志变量怎样都是有用的~
我的疑问主要是在 Cortex M3类硬件上,这个变量是否有意义。你可以从头看一下整个讨论的过程。请仔细看一下我画的图。
而在cortex-m3上,rt_hw_context_switch和rt_hw_context_switch_interrupt是同一个函数。反汇编成伪代码的话基本上就是后者,加上一句set PENDSVSET_BIT,以便在中断处理结束时调用PendSV Handler。
从这里看,Grissiom有一句说的是对的,在中断中再次发生schedule的话,无需重复设置rt_interrupt_from_thread。然后看PendSV Handler,反汇编成伪代码的话
disable interrupt;
if (rt_thread_switch_interrupt_flag == 0) goto pendsv_exit;
/* 如果此时被中断,会使下一个PendSV handler进来时看到rt_thread_switch_interrupt_flag == 0
* 因为在schedule中rt_thread_switch_interrupt_flag 被置为1,执行结束后又被下一句置为0
* 这种情况下,该schedule实际上被跳过了*/
rt_thread_switch_interrupt_flag = 0;if (rt_interrupt_from_thread == 0)
goto switch_to_threadsave rt_interrupt_from_thread current context
switch_to_thread: load rt_interrupt_to_thread context
pendsv_exit: enable interrupt
我猜一进入PendSV handler,PENDSVSET_BIT应该自动被清了。
然后开始判断rt_thread_switch_interrupt_flag,如果为0,说明有另外一个PendSV handler正在执行,此时直接退出,不进行context switch,否则,清 rt_thread_switch_interrupt_flag,开始context switch。
此过程中,如果PENDSVSET_BIT和rt_thread_switch_interrupt_flag再次被rt_hw_context_switch_interrupt置位的话,在当前PendSV handler执行结束后,将执行第二次PendSV handler,即switch到新的thread,这种情况下无需保存from_thread,因为已经保存过了。
实际上rt_hw_context_switch_interrupt里先置rt_thread_switch_interrupt_flag,后置PENDSVSET_BIT,所以进PendSV handler时,rt_thread_switch_interrupt_flag始终为1。
碰到rt_thread_switch_interrupt_flag为0,当且仅当上面注释里的情况发生,此时第二次switch会被跳过。goto pendsv_exit
save rt_interrupt_from_thread current contextswitch_to_thread:load rt_interrupt_to_thread contextpendsv_exit:enable interrupt我猜一进入PendSV handler,PENDSVSET_BIT应该自动被清了。然后开始判断rt_thread_switch_interrupt_flag,如果为0,说明有另外一个PendSV handler正在执行,此时直接退出,不进行context switch,否则,清 rt_thread_switch_interrupt_flag,开始context switch。
此过程中,如果PENDSVSET_BIT和rt_thread_switch_interrupt_flag再次被rt_hw_context_switch_interrupt置位的话,在当前PendSV handler执行结束后,将执行第二次PendSV handler,即switch到新的thread。rt_hw_context_switch_interrupt如果看到rt_thread_switch_interrupt_flag为1的话,说明还有另外一个PendSV handler没被执行,所以就跳过修改rt_interrupt_from_thread。
�ҵ�ͼ�أ�
; r0 --> swith from thread stack
; r1 --> swith to thread stack
; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
PendSV_Handler PROC
EXPORT PendSV_Handler
; disable interrupt to protect context switch
// �����Ѿ����� handler ״̬��������λ�ᱻӲ���Զ����
MRS r2, PRIMASK
// ����жϹر�֮ǰ���ж�Դҧס�����źŲ��ţ����жϾͻ������ϴη�����̷��غ��ٴα���Ϊ����״̬
CPSID I
; get rt_thread_switch_interrupt_flag
LDR r0, =rt_thread_switch_interrupt_flag
LDR r1, [r0]
CBZ r1, pendsv_exit ; pendsv already handled
�� 2011��12��29�� ����9:09�������� <wuyan...@gmail.com>д ����
��ij�жϵķ�����̿�ʼִ ��ʱ���ͳƴ��жϽ����ˡ���Ծ��״̬������������λ�ᱻӲ���Զ������ͼ7.10��ʾ����һ���жϻ�Ծ��ֱ����������ִ���� �ϣ����ҷ��أ����Ϊ�ж��˳����ھ�����ϸ���ۣ����ܶԸ��жϵ�������������Ӧ����ʵ���Ȼ���������ڵõ���Ӧʱ��������Ӳ ���Զ������������־λ���жϷ������Ҳ������ִ�й���а��Լ���Ӧ���ж���������ʹ��ʱҪע�������롰��ѭ����������ע����
����ж�Դҧס�����źŲ��ţ����жϾͻ������ϴη�����̷��غ��ٴα���Ϊ����״̬����ͼ7.11��ʾ����һ����CM3�ʹ�ͳ�� ARM7TDMI����ͬ�ġ�
�� 2011��12��29�� ����9:01��bernard <bernar...@gmail.com>д ����
���ȵ����۰���˵˵pendsv���ж��Ŷӵ����⡣
�����У�pendsv�����ǽ��뵽pendsv������̡����̡����йر��жϡ���cortex-m3�ϣ�Ӳ��ѹջһЩ�Ĵ� ������ô�������̷Ŵ�
Ӳ��ѹջ�Ĵ����� ��Ȼ��ر��жϡ�
��������֮�䣬�����и����ȼ��жϴ�������ô�Ʊ�Ҫ��������ȼ��жϷ�����̣���������������д�����pendsv�쳣�� ����µ�pendsv�쳣�Ǵ���pending״̬���Ƕ������STM32��ʵ�ʲ����ǣ��Ŷӣ����߰���gzhuli��˵ ������pending����
�� 2011��12��29�� ����8:48��rogerz <rogerz...@gmail.com>д ����
˵���ˣ�����һ�¡���
2011/12/29 rogerz <rogerz...@gmail.com>
2011/12/29 prife <gop...@gmail.com>
�ҵ�������Ҫ���� Cortex M3��Ӳ���ϣ���������Ƿ������塣����Դ�ͷ��һ��������۵Ĺ�̡�����ϸ��һ���һ���ͼ��
��ij������(v850)�У������������ô�õ�
void rt_hw_context_switch(rt_uint32_t from, rt_uint32_t to){rt_interrupt_from_thread = from;rt_interrupt_to_thread = to;asm("INT #0");}
void rt_hw_context_switch_interrupt(rt_uint32_t from, rt_uint32_t to){if (rt_thread_switch_interrupt_flag != 1){rt_thread_switch_interrupt_flag = 1;rt_interrupt_from_thread = from;}rt_interrupt_to_thread = to;}
����cortex-m3�ϣ�rt_hw_context_switch��rt_hw_context_switch_interrupt��ͬһ���������α����Ļ����Ͼ��Ǻ��ߣ�����һ��set PENDSVSET_BIT���Ա����жϴ������ʱ����PendSV Handler���������Grissiom��һ��˵���ǶԵģ����ж����ٴη���schedule�Ļ��������ظ�����rt_interrupt_from_thread��Ȼ��PendSV Handler��������α����Ļ�
disable interrupt;if (rt_thread_switch_interrupt_flag == 0)goto pendsv_exit;
/* ����ʱ���жϣ���ʹ��һ��PendSV handler����ʱ����rt_thread_switch_interrupt_flag == 0* ��Ϊ��schedule��rt_thread_switch_interrupt_flag ����Ϊ1��ִ�н�����ֱ���һ����Ϊ0* ��������£���scheduleʵ���ϱ������
*/rt_thread_switch_interrupt_flag = 0;if (rt_interrupt_from_thread == 0)
goto pendsv_exit
save rt_interrupt_from_thread current contextswitch_to_thread:load rt_interrupt_to_thread contextpendsv_exit:enable interrupt
�Ҳ�һ����PendSV handler��PENDSVSET_BITӦ���Զ������ˡ�Ȼ��ʼ�ж�rt_thread_switch_interrupt_flag�����Ϊ0��˵��������һ��PendSV handler����ִ�У���ʱֱ���˳���������context switch�������� rt_thread_switch_interrupt_flag����ʼcontext switch���˹���У����PENDSVSET_BIT��rt_thread_switch_interrupt_flag�ٴα�rt_hw_context_switch_interrupt��λ�Ļ����ڵ�ǰPendSV handlerִ�н����ִ�еڶ���PendSV handler����switch���µ�thread��rt_hw_context_switch_interrupt���rt_thread_switch_interrupt_flagΪ1�Ļ���˵����������һ��PendSV handlerû��ִ�У����Ծ������rt_interrupt_from_thread��ʵ����rt_hw_context_switch_interrupt������rt_thread_switch_interrupt_flag������PENDSVSET_BIT�����Խ�PendSV handlerʱ��rt_thread_switch_interrupt_flagʼ��Ϊ1������rt_thread_switch_interrupt_flagΪ0�����ҽ�������ע�������������ʱ�ڶ���switch�ᱻ���,---. Rogerz Zhang
( @ @ ) Human, not octopus ).-.( Chase what you love. Let the rest go.
'/|||\` Share > Google+ | Note > Tumblr | Random > twitter �� '|` AsciiArt < Shimrod(hh)
--
������
--
������
你们的图都这么帅
都是用啥画的?
在 2011年12月29日 下午9:24,MingBai <mbb...@gmail.com>写道:你们的图都这么帅
都是用啥画的?
我用smartdraw2010画的。 我觉得还是权威指南的图画的好,不知道译者用啥画的。visio么?