下载最新menu,并在test.c中增加mkdir与mkdir-asm函数原型
rm menu -rf
git clone https://github.com/mengning/menu.git
cd menu
vim test.c
增加下面的代码:
int Mkdir(int argc,char *argv[]){
if(mkdir(argv[1],S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0)
printf("New dir successfully!\n");
else
printf("New dir failed!\n");
return 0;
}
int MkdirAsm(int argc,char *argv[]){
int intr;
mode_t mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
__asm__ __volatile__(
"int $0x80;\n\t"
: "=a" (intr)
: "a"(39),"b"(argv[1]),"c"(mode)
:"memory"
);
if(intr == 0)
printf("New dirasm successfully!\n");
else
printf("New dirasm failed!\n");
return 0;
}
有两点需要强调,这也是我实验过程中出现过问题,才改进之后的代码!
注意加头文件#include <sys/stat.h> #include <sys/types.h>
mkdir系统调用的结果是创建一个目录,而MenuOS并没有ls这个命令,所以为了验证我们添加mkdir和mkdir-asm命令成功,必须在函数中添加相应的判断与输出的语句,所以与上次实验代码相比,这里多了if与else语句和printf语句。否则我们无法验证在MenuOS中命令是否执行成功。
上面这个图我是先用mkdir创建了一个testdir目录,显示创建成功;随后我又用mkdir-asm又创建testdir这个目录,因为这个目录刚才已经用mkdir创建过,所以必然失败,这也变相说明上一步mkdir创建成功;随后我又用mkdir-asm创建了testdir1,显示创建成功。
下一步进行gdb调试:
cd ..
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S //启动并“冰冻”
gdb linux-3.18.6/vmlinux
target remote:1234 //连接到刚启动的虚拟机
上图为b start_kernel
之后的结果。
根据39号系统调用的内核函数sys_mkdir,执行b sys_mkdir
:
结果系统停在了启动的“半路上”。并不是像断sys_time那样。很显然,这说明在内核启动过程中,必然要调用sys_mkdir该系统调用(虽然我现在还不知道有哪些过程要调用它,但可以肯定的是一定有过程调用它!)。
还得出一条心得就是实验楼环境是真的不好用,每当我把当前界面换到启动的虚拟机,则必然造成死机。只有重新开始实验,这样造成的结果就是我还得重新下载menu,重新编写test.c。不仅如此,还无法实施对mkdi与mkdir-asm的跟踪,因为一切换到MenuOS就卡掉了,根本没法输入命令。
system_call到iret之间的简化后伪代码:
ENTRY(system_call)
SAVE_ALL
syscall_call:
call *sys_call_table(,%eax,4)
movl %eax,PT_EAX(%eax) //保存返回值
syscall_exit:
testl $_TIF_ALLWORK_MASK,%ecx //current—>work
jne syscall_exit_work
restore_all:
RESTORE_INT_REGS
irq_return:
INTERRUPT_PETURN
ENDPROC(system_call)
syscall_exit_work:
testl $_TIF_WORK_SYSCALLEXIT,%ecx
jz work_pending
END(syscall_exit_work)
work_pending:
testb $_TIF_NEED_RESCHED,%c1
jz work_notifysig
work_resched:
call schedule
jz restore_all
work_notifysig:
...
END(work_pending)
流程图:
简化后的伪代码中只留下了一部分重要代码。比如对系统调用结束时要做的工作,这里只留下了两个判断,一个是是否有需要处理的信号,如果有,那就跳到相应的处理入口地址;第二个是是否需要进程调用,如果有那就转去处理进程调用,如果没有就结束。其实我们浏览没有简化的代码会发现,在这个过程中还有判断是否发生异常及异常处理等代码。
共享资源之所以要防止并发访问,是因为如果多个执行线程同时访问和操作数据,就有可能发生各个线程之间相互覆盖共享数据的情况,造成被访问数据处于不一致状态。而访问和操作共享数据的代码段就被称为临界区。所以两个执行中的线程不可能处于同一个临界区中共同执行,一个临界区在执行完之前不可被打断。
互斥指散布在不同进程之间的若干程序片断,当某个进程运行其中一个程序片段时,其它进程就不能运行它们之中的任一程序片段,只能等到该进程运行完这个程序片段后才可以运行。
同步是散布在不同进程之间的若干程序片断,它们的运行必须严格按照规定的某种先后次序来运行,这种先后次序依赖于要完成的特定的任务。
如果有一个线程对共享的数据加锁,则其他的线程就不能再访问该共享数据,必须等解锁之后才能去访问。简而言之,对同一共享数据,特定时间内只有一个线程可以进入与该共享数据对应的临界区。
自旋锁最多只能被一个可执行线程持有,如果一个执行线程试图获得一个被已经持有的自旋锁,那么该线程就会一直进行忙循环——旋转——等待锁重新可用。要是锁未被争用,请求锁的执行线程便能立刻得到它们继续执行。在任意时间,自旋锁都可以防止多于一个的执行线程同时进入临界区。同一个锁可以用在多个位置。
BLK是一个全局自旋锁,使用它主要是为了方便Linux最初的SMP过度到细粒度加锁机制。
手机扫一扫
移动阅读更方便
你可能感兴趣的文章