本文共 5348 字,大约阅读时间需要 17 分钟。
schedule // kernel/sched/core.c __schedule // kernel/sched/core.c struct rq_flags rf; int cpu = smp_processor_id(); struct rq *rq = cpu_rq(cpu); struct task_struct *prev = rq->curr; rq_lock(rq, &rf); deactivate_task(rq, prev, DEQUEUE_SLEEP | DEQUEUE_NOCLOCK); struct task_struct *next = pick_next_task(rq, prev, &rf); // kernel/sched/core.c for_each_class(class) class->pick_next_task(rq); context_switch(rq, prev, next, &rf); // kernel/sched/core.c prepare_lock_switch(rq, next, rf); rq_unpin_lock(rq, rf); switch_to(prev, next, prev); // arch/arm/include/asm/switch_to.h __switch_to(prev,task_thread_info(prev), task_thread_info(next)); // arch/arm/kernel/entry-armv.S
// arch/arm/kernel/entry-armv.S/* * Register switch for ARMv3 and ARMv4 processors * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info * previous and next are guaranteed not to be the same. */ENTRY(__switch_to) UNWIND(.fnstart ) UNWIND(.cantunwind ) add ip, r1, #TI_CPU_SAVE // 24 cpu_context // 保存 r4-r10 // 保存 r11 // 保存 r13 // 保存 r14 ARM( stmia ip!, { r4 - sl, fp, sp, lr} ) @ Store most regs on stack // 保存到 task_thread_info(prev)->cpu_context (类型为struct cpu_context_save)中的成员中 // 此时已经开始 switch // switch_tls ldr r4, [r2, #TI_TP_VALUE] // 92 // tp_value // thread local Storage // c13,c0,3 ldr r5, [r2, #TI_TP_VALUE + 4] // 96 // user register // c13,c0,2 switch_tls r1, r4, r5, r3, r7 mov r5, r0 add r4, r2, #TI_CPU_SAVE // 24 cpu_context // atomic_notifier_call_chain ldr r0, =thread_notify_head mov r1, #THREAD_NOTIFY_SWITCH bl atomic_notifier_call_chain mov r0, r5 // r0 current task_struct // r4 task_thread_info(next)->cpu_context ARM( ldmia r4, { r4 - sl, fp, sp, pc} ) @ Load all regs saved previously // 将 task_thread_info(next)->cpu_context 中的成员 加载到 对应的寄存器中 // r4-r10 r11 r13 r14 r15 // switch 完毕 UNWIND(.fnend )ENDPROC(__switch_to)---#define switch_tls switch_tls_v6k // arch/arm/include/asm/tls.h // arm1176jzfs trm 手册 P262 // 读写这些 寄存器 除了存储不会产生其他效果 .macro switch_tls_v6k, base, tp, tpuser, tmp1, tmp2 mrc p15, 0, \tmp2, c13, c0, 2 @ get the user r/w register mcr p15, 0, \tp, c13, c0, 3 @ set TLS register // 将 task_thread_info(next) 中的 tp_value[0] 放到 c13,c0,3 (TLS register) mcr p15, 0, \tpuser, c13, c0, 2 @ and the user r/w register // 将 task_thread_info(next) 中的 tp_value[1] 放到 c13,c0,2 (user r/w register) str \tmp2, [\base, #TI_TP_VALUE + 4] @ save it // 存储到 task_thread_info(prev) 中的 tp_value[1]; .endm 问题 : 1.为什么 不保存 c13, c0, 3 (到 task_thread_info(prev) 中的 tp_value[0]) ??? 2.TLS 是干什么的---atomic_notifier_call_chain // kernel/notifier.c notifier_call_chain nb->notifier_call(nb, val, v); // contextidr_notifier // 本配置不会调用 任何 notifier_call---arch/arm/include/asm/thread_info.hstruct cpu_context_save { __u32 r4; __u32 r5; __u32 r6; __u32 r7; __u32 r8; __u32 r9; __u32 sl; __u32 fp; __u32 sp; __u32 pc; __u32 extra[2]; /* Xscale 'acc' register, etc */ };
有 switch 就有 store我们看 switch 之后,有哪些状态是跟当前进程密切相关的cpu寄存器 : r0 : current task_struct r1 : 不重要 r2 : current task_struct r3 : 不重要 r4 - r10 : 重要 r11 : fp r12 : 不重要 r13 : sp r14 : 不重要 r15 : pccp15 c13 寄存器 c13,c0,2 : thread_info 中的 user register c13,c0,3 : thread_info 中的 tp_value 看起来上面的状态在 switch 之前都得 被 保存起来 r0/r1/r2/r3/r12/r15 没保存 r4 - r11/r13/r14 保存了 (pc是用的lr) c13,c0,2 保存了
在哪一句切出: // 重点看 现在更改的 pc ARM( ldmia r4, { r4 - sl, fp, sp, pc} )切回的第一句: // 重点看 之前保存的 lr context_switch->barrier // ???
// g++ thread_local.c -o thread_local -std=c++11 -pthread// file thread_local.c// 对于关键字 thread_local 定义的 变量 range, 每创建一个 thread,就会新增一份 range 的实体#include#include #include pthread_t pthid1,pthid2;sem_t sem;thread_local int range = 1;static void * fun1(void *arg){ sem_wait(&sem); printf("second,range:%d\n",range); return NULL;}static void * fun2(void *arg){ range = 2222; printf("fist,range:%d\n",range); sem_post(&sem); return NULL;}int main(int argc, const char *argv[]){ range = 3333; sem_init(&sem, 0, 0); if(0 != pthread_create(&pthid1,NULL,fun1,NULL)){ perror("pthid1"); return -1; } if(0 != pthread_create(&pthid2,NULL,fun2,NULL)){ perror("pthid2"); return -1; } pthread_join(pthid1,NULL); pthread_join(pthid2,NULL); printf("third,range:%d\n",range); return 0;}/*fist,range:2222second,range:1third,range:3333*/
转载地址:http://ncigi.baihongyu.com/