OK6410A 开发板 (八) 21 linux-5.11 OK6410A schedule 的 __switch_to 部分

  • schedule

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


  • __switch_to
// 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.h
struct 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 : pc
cp15 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 <semaphore.h>

#include <pthread.h>
#include <stdio.h>

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:2222
second,range:1
third,range:3333
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值