新进程的加载与创建

1、实现fork系统调用

fork创建子进程。通过fork的返回值来判断是父进程还是子进程。

当fork()返回值会返回进程的id,当进程发现pid==0,就知道了自己是fork出来的子进程;而如果pid > 0,则知道了自己是父进程。

fork系统调用实现:

  1. 在系统调用表sys_table中添加系统调用接口
  2. 分配子进程运行所需的任务控制块task_t
  3. 初始化task_t:关键之处在于要让该结构体中的内容,除tss->eax以外,其它内核寄存器的值要与父进程中的相同,这样才能完整的复制父进程调用fork前的状态
  4. 需要单独为子进程分配相应的内容空间:即内核页表及相应的物理页。这样就可以使子进程拥有独立的运行内存空间。

2、实现exec系统调用

前面的fork只能实现从一个现有的进程克隆出一个子进程。因此下面实现加载全新应用程序的功能:exec()即创建一个独立编译的应用程序

1)建立独立的 不和操作系统代码文件一起编译的文件,比如建立main.c文件,添加main函数

int main (int argc, char **argv) {
    for (;;) {
        msleep(1000);
    }
}

2)添加main函数启动之前的C运行环境的代码,放在crt0.s和cstart.c中

_start:
# 设置各数据段的选择子,由于应用任务都是用tss恢复的,所以
# 实际不必设置,但为安全起见,还是设置一下
mov %ss, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs

# 进入主函数执行,注意此时栈没有变,参数仍然在其中
# 所以调用cstart时,仍然可以看到参数
jmp cstart
void cstart (int argc, char ** argv) {
    main(argc, argv);
}

3)告诉编译器应当将程序编译为在那个地方开始运行:通过链接脚本实现(使用0x81000000 )

4)修改工程cmakelist.txt文件,添加针对该应用程序的编译选项

project(shell LANGUAGES C)  

# 使用自定义的链接器
# 加入相应的库
set(LIBS_FLAGS "-L ${CMAKE_BINARY_DIR}/source/applib/ -lapp")
set(CMAKE_EXE_LINKER_FLAGS "-m elf_i386 -T ${PROJECT_SOURCE_DIR}/link.lds ${LIBS_FLAGS}")
set(CMAKE_C_LINK_EXECUTABLE "${LINKER_TOOL} <OBJECTS> ${CMAKE_EXE_LINKER_FLAGS} -o ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.elf")

include_directories(
${PROJECT_SOURCE_DIR}/../applib/
)

# 将所有的汇编、C文件加入工程
# 注意保证start.asm在最前头
file(GLOB C_LIST "*.c" "*.h" "*.S")
add_executable(${PROJECT_NAME} ${C_LIST})

# 不带调试信息的elf生成,何种更小,写入到image目录下
add_custom_command(TARGET ${PROJECT_NAME}
POST_BUILD
COMMAND ${OBJCOPY_TOOL} -S ${PROJECT_NAME}.elf ${CMAKE_SOURCE_DIR}/../../image/${PROJECT_NAME}.elf
COMMAND ${OBJDUMP_TOOL} -x -d -S -m i386 ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.elf > ${PROJECT_NAME}_dis.txt
COMMAND ${READELF_TOOL} -a ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.elf > ${PROJECT_NAME}_elf.txt

相关知识补充

添加虚拟文件访问接口

int sys_open(const char *name, int flags, ...);
int sys_read(int file, char *ptr, int len);
int sys_write(int file, char *ptr, int len);
int sys_lseek(int file, int ptr, int dir);
int sys_close(int file);

在这些接口中,只实现对5000扇区处的shell.elf加载。首先将shell.elf加载到内存,然后将直接从内存中直接进行elf文件解析

创建完成就是增加exec()系统调用,与实现fork()系统调用过程一样,其功能就是使用sys_exec加载应用程序

3、添加sys_yield()系统调用

功能:这个系统调用来实现进程主动放弃CPU并切换到其他进程运行过程。

首先,需要为系统调用预留接口并添加相应的ID,然后在库函数中实现该系统调用的接口。接着,需要处理系统调用的映射表,调用task.c中的函数实现进程主动放弃CPU的功能。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值