-
主动调度与上下文切换
在学习极客时间刘超《趣谈Linux操作系统》 16 节时,讲到了主动调度, 通过__schedule() 函数让出cpu三个步骤:
1. 取出任务队列;
2. 从队列取下一个任务;
3. 进行上下文切换;
其中第三步中上下文切换中 调用switch_to函数, 通过调用switch_to_asm函数完成栈顶执政寄存器的交换。 代码如下:
/arch/x86/include/asm/switch_to.h
#define switch_to(prev, next, last) \
do { \
prepare_switch_to(next); \
\
((last) = __switch_to_asm((prev), (next))); \
} while (0)
/arch/x86/entry/entry_64.S
ENTRY(__switch_to_asm)
UNWIND_HINT_FUNC
。。。
/* switch stack */
movq %rsp, TASK_threadsp(%rdi)
movq TASK_threadsp(%rsi), %rsp
。。。。
END(__switch_to_asm)
其中 %rdi代表第一个参数, %rsi代表第二个参数, 分别代表 prev task, next task
将当前栈顶指针放入prev task_struct 结构 thread_struct的 sp0 中。 将next_task栈顶 指做为当前栈顶指针,完成切换。
关于 TASK_threadsp,涉及以下几个文件:(当然一开始的时候正是因为找不到才有了有序寻找答案的过程)
- 编译相关
1 /Kbuild
...
#####
# Generate asm-offsets.h
offsets-file := include/generated/asm-offsets.h
always += $(offsets-file)
targets += arch/$(SRCARCH)/kernel/asm-offsets.s
arch/$(SRCARCH)/kernel/asm-offsets.s: $(timeconst-file) $(bounds-file)
$(offsets-file): arch/$(SRCARCH)/kernel/asm-offsets.s FORCE
$(call filechk,offsets,__ASM_OFFSETS_H__)
...
2. /scripts/Makefile.lib
...
# ASM offsets
# ---------------------------------------------------------------------------
# Default sed regexp - multiline due to syntax constraints
#
# Use [:space:] because LLVM's integrated assembler inserts <tab> around
# the .ascii directive whereas GCC keeps the <space> as-is.
define sed-offsets
's:^[[:space:]]*\.ascii[[:space:]]*"\(.*\)".*:\1:; \
/^->/{s:->#\(.*\):/* \1 */:; \
s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \
s:->::; p;}'
endef
# Use filechk to avoid rebuilds when a header changes, but the resulting file
# does not
define filechk_offsets
echo "#ifndef $2"; \
echo "#define $2"; \
echo "/*"; \
echo " * DO NOT MODIFY."; \
echo " *"; \
echo " * This file was generated by Kbuild"; \
echo " */"; \
echo ""; \
sed -ne $(sed-offsets) < $<; \
echo ""; \
echo "#endif"
endef
...
-
代码相关
/include/linux/kbuild.h
#define DEFINE(sym, val) \
asm volatile("\n.ascii \"->" #sym " %0 " #val "\"" : : "i" (val))
#define OFFSET(sym, str, mem) \
DEFINE(sym, offsetof(struct str, mem))
...
/arch/x86/kernel/asm-offsets.c
static void __used common(void)
{
...
OFFSET(TASK_threadsp, task_struct, thread.sp);
...
//生成的头文件
/include/generated/asm-offsets.h
#ifndef __ASM_OFFSETS_H__
#define __ASM_OFFSETS_H__
/*
* DO NOT MODIFY.
*
* This file was generated by Kbuild
*/
#define TASK_threadsp 4824 /* offsetof(struct task_struct, thread.sp) */
-
整体处理流程:
asm-offsets.c 转化为asm-offsets.s通过Makefile.lib 的filechk_offsets ,sed-offsets 将其生成宏定义, 这样汇编语言也可以方便的获得相关结构结构体的偏移了。
下面写个demo验证一下
- Makefile:
offsets-file := asm-offsets.h
define sed-yo
"/^->/{s:->#\(.*\):/* \1 */:; \
s:^->\([^ ]*\) [\$$#]*\([-0-9]*\) \(.*\):#define \1 \2 /* \3 */:; \
s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \
s:->::; p;}"
endef
define sed-y
's:^[[:space:]]*\.ascii[[:space:]]*"\(.*\)".*:\1:; \
/^->/{s:->#\(.*\):/* \1 */:; \
s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \
s:->::; p;}'
endef
define cmd_offsets
(set -e; \
echo "#ifndef __ASM_OFFSETS_H__"; \
echo "#define __ASM_OFFSETS_H__"; \
echo "/*"; \
echo " * DO NOT MODIFY."; \
echo " *"; \
echo " * This file was generated by Kbuild"; \
echo " *"; \
echo " */"; \
echo ""; \
sed -ne $(sed-y) $<; \
echo ""; \
echo "#endif" ) > $@
endef
asm-offsets.s: asm-offsets.c
gcc -S $<
$(offsets-file): asm-offsets.s
@$(cmd_offsets)
- asm-offsets.c
#include "kbuild.h"
#include <stddef.h>
struct thread_struct1 {
int sp;
};
struct task_struct1 {
struct thread_struct1 thread;
};
#define __used __attribute__((__used__))
static void __used common(void){
BLANK();
COMMENT("TASK_threadsp1");
OFFSET(TASK_threadsp1, task_struct1, thread.sp);
BLANK();
}
- asm-offsets.h
[root@centosgpt generate]# cat asm-offsets.h
#ifndef __ASM_OFFSETS_H__
#define __ASM_OFFSETS_H__
/*
* DO NOT MODIFY.
*
* This file was generated by Kbuild
*
*/
/* TASK_threadsp1 */
#define TASK_threadsp1 0 /* offsetof(struct task_struct1, thread.sp) */
#endif
asm-offsets.h 文件生成了。
Be First to Comment