xv6源码解析(二)——系统调用

01 系统调用

系统调用:提供了用户态陷入内核态的软中断,设置中断号为64,实现了自定义系统调用myalloc、myfree等

02 系统调用过程

03 常见命令系统调用解析

cat源码解析

//cat.c
#include "types.h"
#include "stat.h"
#include "user.h"

char buf[512];

void
cat(int fd)
{
  int n;

  while((n = read(fd, buf, sizeof(buf))) > 0)
    write(1, buf, n);
  if(n < 0){
    printf(1, "cat: read error\n");
    exit();
  }
}

int
main(int argc, char *argv[])
{
  int fd, i;

  if(argc <= 1){
    cat(0);
    exit();
  }

  for(i = 1; i < argc; i++){
    if((fd = open(argv[i], 0)) < 0){
      printf(1, "cat: cannot open %s\n", argv[i]);
      exit();
    }
    cat(fd);
    close(fd);
  }
  exit();
}

(1)open系统调用根据传入的参数创建文件描述符

(2)调用底层的read和write系统调用

(3)最后 close系统调用关闭文件描述符

补充

open系统调用 创建新的文件描述符

read系统调用 传入 fd、buf、buf的大小 返回read成功的字节数 read到最后一行 返回0

write系统调用 传入fd、buf、count(写入的字节数) 返回write的字节数

close系统调用 关闭文件描述符

参考链接

image-20221103094523441

image-20221103094553069

fork源码解析

一次调用,两次返回真的太牛逼了!!!!

fork函数是用于进程的创建,是linux编程中常用的一个系统调用类函数。fork会复制当前进程的几乎所有信息,包括可访问的内存资源。

fork调用一次,返回两次,这两个返回分别带回它们各自的返回值,其中在父进程中的返回值是子进程的PID,而子进程中的返回值则返回 0。因此,可以通过返回值来判定该进程是父进程还是子进程。还有一个很奇妙的是:fork函数将运行着的程序分成2个(几乎)完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的线程。这两个进程中的线程继续执行,就像是两个用户同时启动了该应用程序的两个副本。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-20RoYJcV-1668171510504)(https://image-1312312327.cos.ap-shanghai.myqcloud.com/20150412162157016)]

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>

int main(int argc, char* argv[])
{
	printf("=== process begin ===\n");
	pid_t pid = fork();
	if(pid == -1)
	{
		perror("fork err");
		return -1;	
	}
	if(pid == 0) /*子进程*/
	{
		printf("i am child: %d, may parent: %d\n", getpid(), getppid());	
        /*	test2
        while(1)
        {
            printf("fork process\n");
            sleep(1);
        }
        */
	}
	if(pid > 0)
	{
		printf("i am call: %d, child: %d, parent: %d\n", getpid(), pid, getppid());	
        /*	test1
        sleep(1);
        */
        /*	test2
        while(1)
        {
        	sleep(1);
        }
        */
	}
	printf("=== process end ===\n");
	return 0;
}

fork的整体流程

image-20221103103115970

image-20221103103131548

参考链接1

参考链接2

mkdir源码解析

#include "types.h"
#include "stat.h"
#include "user.h"

int
main(int argc, char *argv[])
{
  int i;

  if(argc < 2){
    printf(2, "Usage: mkdir files...\n");
    exit();
  }

  for(i = 1; i < argc; i++){
    if(mkdir(argv[i]) < 0){
      printf(2, "mkdir: %s failed to create\n", argv[i]);
      break;
    }
  }

  exit();
}

sleep源码解析

可以让进程阻塞、睡眠、等待

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"

int main(int argc, char **argv) {
    if (argc < 2) {
        printf("usage: sleep <ticks>\n");
    }
    sleep(atoi(argv[1]));
    exit(0);
}

pingpong源码解析

// pingpong.c
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"

int main(int argc, char **argv) {
	// 创建管道会得到一个长度为 2 的 int 数组
	// 其中 0 为用于从管道读取数据的文件描述符,1 为用于向管道写入数据的文件描述符
	int pp2c[2], pc2p[2];
	pipe(pp2c); // 创建用于 父进程 -> 子进程 的管道 parent->child
	pipe(pc2p); // 创建用于 子进程 -> 父进程 的管道
	
	if(fork() != 0) { // parent process
		write(pp2c[1], "!", 1); // 1. 父进程首先向发出该字节
		char buf;
		read(pc2p[0], &buf, 1); // 2. 父进程发送完成后,开始等待子进程的回复
		printf("%d: received pong\n", getpid()); // 5. 子进程收到数据,read 返回,输出 pong
		wait(0);
	} else { // child process  fork()返回0时 启动子进程
		char buf;
		read(pp2c[0], &buf, 1); // 3. 子进程读取管道,收到父进程发送的字节数据
		printf("%d: received ping\n", getpid());
		write(pc2p[1], &buf, 1); // 4. 子进程通过 子->父 管道,将字节送回父进程
	}
	exit(0);
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-特立独行的猪-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值