39
社区成员




1、通过chatgpt学习Linux系统架构和执行过程概览,学习了有关于Linux内核的关键以及进程的一些方式。
并行:并行是指多个进程或线程同时执行,每个进程独立运行,互不干扰。在并行处理中,多个任务被同时执行,有助于提高系统的整体性能。
单线程:单线程指的是程序内部只有一个执行流程。在单线程模型中,程序的各个部分顺序执行,适用于简单、顺序执行的任务。在Linux中,单线程通常适用于简单的代码或单一任务,它的优势在于简洁性和易于实现。
多线程:多线程是指在一个进程内创建多个并发执行的线程。不同线程可以共享进程的资源,可以更高效地完成复杂的任务。在Linux系统中,多线程通常适用于需要并发处理多个任务或需要利用多核处理器的情况。
https://chat.openai.com/c/59e97352-da20-4ba0-8ebf-275589ecc453
2、实验八
1)首先输入grep -r "schedule()" /home/shiyanlou/LinuxKernel/linux-3.18.6/kernel 在内核中搜索schedule()函数。
int Exec(int argc, char *argv[])
{
int pid;
pid = fork();
if (pid < 0)
{
fprintf(stderr,"Fork Failed!");
exit(-1);
}
else if (pid == 0)
{
printf("This is Child Process!\n");
execlp("/hello","hello",NULL);
}
else
{
printf("This is Parent Process!\n");
wait(NULL);
printf("Child Complete!\n");
}
}
并在int main 函数里头添加MenuConfig("Exec","exec from the process",Exec);保存之后输入make rootfs
3)之后和原来一样,首先cd LinuxKernel,gdb,之后在gdb中打断点,分别是b schedule、b context_switch、b pick_next_task、b switch_to
schedule:进程调度的主体函数
context_switch:实现进程切换的函数
pick_next_task:负责根据调度策略和调度算法选择下一个进程
switch_to:其中switch_to为宏定义,不能设置断点,需到context_switch函数中单步执行查看调用
感觉实验失败的原因应该是实验楼的平台出现了连接问题,在输入target remote:1234时就出现了超时的提醒。
4)分析switch_to的汇编代码
#define switch_to(prev, next, last)
do {
/*
* Context-switching clobbers all registers, so we clobber
* them explicitly, via unused output variables.
* (EAX and EBP is not listed because EBP is saved/restored
* explicitly for wchan access and EAX is the return value of
* __switch_to())
*/
unsigned long ebx, ecx, edx, esi, edi;
asm volatile("pushfl\n\t" /* 保存当前进程flags */
"pushl %%ebp\n\t" /* 当前进程堆栈基址压栈*/
"movl %%esp,%[prev_sp]\n\t" /*保存ESP,将当前堆栈栈顶保存起来*/
"movl %[next_sp],%%esp\n\t" /*更新ESP,将下一栈顶保存到ESP中*/
//完成内核堆栈的切换
"movl $1f,%[prev_ip]\n\t" /*保存当前进程EIP*/
"pushl %[next_ip]\n\t" /*将next进程起点压入堆栈,即next进程的栈顶为起点*/
//完成EIP的切换
__switch_canary
//next_ip一般是$1f,对于新创建的子进程时ret_from_fork
"jmp __switch_to\n" /*prev进程中,设置next进程堆栈*/
//jmp不同于call是通过寄存器传递参数
"1:\t" //next进程开始执行
"popl %%ebp\n\t"
"popfl\n"
/*输出变量定义*/
: [prev_sp] "=m" (prev->thread.sp), //[prev_sp]定义内核堆栈栈顶
[prev_ip] "=m" (prev->thread.ip), //[prev_ip]当前进程EIP
"=a" (last),
/* 要破坏的寄存器: */
"=b" (ebx), "=c" (ecx), "=d" (edx),
"=S" (esi), "=D" (edi)
__switch_canary_oparam
/* 输入变量: */
: [next_sp] "m" (next->thread.sp), //[next_sp]下一个内核堆栈栈顶
[next_ip] "m" (next->thread.ip),
//[next_ip]下一个进程执行起点,,一般是$1f,对于新创建的子进程是ret_from_fork
/* regparm parameters for __switch_to(): */
[prev] "a" (prev),
[next] "d" (next)
__switch_canary_iparam
: /* 重新加载段寄存器 */
"memory");
} while (0)
3、实验总结
本次实验主要是理解 Linux 系统中进程调度的时机,并在内核代码中搜索 schedule()函数,使用 gdb 跟踪分析 schedule()函数 。可以得出触发进程切换,让系统执行进程调度。可以通过创建新的进程、让一个进程休眠或者触发其他需要调度的事件来进行调度。负责将 CPU 控制权从当前进程切换到下一个即将执行的进程。这种切换涉及到保存当前进程的状态并加载新进程的状态,以确保进程的连续执行和正常运行。