输入 sleep 命令后,命令行会 ”暂停“ 一段时间 (10个ticks,ticks由内核定义),然后输出"(nothing happens for a little while)"。
调用系统调用 sleep(int)
#include "kernel/types.h"
#include "user.h"
int main(int argc,char* argv[]){
if(argc != 2){
printf("Sleep needs one argument!\n"); //检查参数数量是否正确
exit(-1);
}
int ticks = atoi(argv[1]); //将字符串参数转为整数
sleep(ticks); //使用系统调用sleep
printf("(nothing happens for a little while)\n");
exit(0); //确保进程退出
}
父进程向子进程发送 ping, 子进程接收并打印后向父进程打印 pong,父进程接受并打印
使用 pipe(int *)
创建无名管道在父子进程中通信
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int main(int argc, char **argv)
{
//无名管道为半双工通道:可以接受和发送信息,但在同一时间只能接受或发送信息
int fd1[2]; //父进程向子进程发送通道
int fd2[2]; //子进程向父进程发送通道
pipe(fd1); //创建管道
pipe(fd2); //创建管道
if(fork() == 0) //子进程
{
close(fd1[1]); //该通道子进程只读,关闭写端,下同
close(fd2[0]); //该通道子进程只写,关闭读端,下同
char buf[32];
int pi = read(fd1[0], buf, 32 * sizeof(char)); //读入最多32字节的数据,返回值为实际读到数据大小,下同
buf[pi] = '\0'; //置字符串末尾下一个字符为'\0',便于打印
printf("%d: received %s\n", getpid(), buf);
write(fd2[1], "pong", 4 * sizeof(char)); //写入"pong"字符串,大小为4 * sizeof(char)
exit(0);
}
else //父进程
{
close(fd1[0]);
close(fd2[1]);
write(fd1[1], "ping", 4 * sizeof(char));
char buf[32];
int pi = read(fd2[0], buf, 32 * sizeof(char));
buf[pi] = '\0';
printf("%d: received %s\n", getpid(), buf);
wait(0); //等待子进程结束
exit(0);
}
}
在xv6上使用管道实现“质数筛选”, 输出2~35之间的而所有质数。
以管道为筛子, 将接收到的第一个数为本轮的基本质数并输出,然后继续循环接收整数,若该数为基数的倍数则丢弃,否则放入数组,并在接收结束后发送给子进程。
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
void get_prime(int fd[])
{
close(fd[1]); //本进程只读,关闭写端
int nums[35]; //储存未被筛掉的数
int cnt = 0; //记录筛选出的数字数量
int fir = 0; //本轮基本质数
int temp; //缓存读取到的数
int len = 0; //读取到的数据长度
len = read(fd[0], (void *)&fir, sizeof(int)); //读入基本质数
if(fir == 0) exit(0); //没有读到基本质数,程序结束
printf("prime %d\n", fir);
//read the remain num
while(len > 0) //循环读入数字直到读取完毕
{
len = read(fd[0], &temp, sizeof(int));
if(len > 0)
{
if(temp%fir != 0) //读入数字不为基本质数的倍数,放入数组
{
nums[cnt++] = temp;
}
}
}
close(fd[0]); //关闭读端,释放文件描述符,防止递归深度过大将文件描述符消耗完,下同
int m_fd[2]; //本轮父子进程通信管道
pipe(m_fd);
if(fork() != 0)
{
close(m_fd[0]);
write(m_fd[1], &nums, cnt * sizeof(int)); //父进程发送数据给子进程
close(m_fd[1]);
wait(0); //等待子进程结束
exit(0);
}
else
{
get_prime(m_fd); //子进程嵌套进行质数筛选
}
}
int main(int argc, char *argv[])
{
int nums[34];
int i;
for(i = 2; i < 36; ++i)
{
nums[i - 2] = i;
}
int fd[2];
pipe(fd);
if(fork() != 0)
{
close(fd[0]);
write(fd[1], &nums, 34 * sizeof(int));
close(fd[1]);
wait(0);
exit(0);
}
else
{
get_prime(fd);
}
return 0;
}
在xv6上实现用户程序find,即在目录树中查找名称与字符串匹配的所有文件,输出文件的相对路径。该程序的 命令格式为“find path file_name” 。
类似ls实现,搜索本文件夹下所有文件,若名字相同则输出,若为文件夹则递归地进行搜索
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"
char*
fmtname(char *path) // 从字符串 "a/b/c/d" 中获取 字符串 "d",基本原理为从后往前找到第一个'/'
{
static char buf[DIRSIZ+1];
char *p;
// Find first character after last slash.
for(p=path+strlen(path); p >= path && *p != '/'; p--)
;
p++;
// Return blank-padded name.
if(strlen(p) >= DIRSIZ)
return p;
memmove(buf, p, strlen(p));
buf[strlen(p)] = '\0';
return buf;
}
void cmp(char *a, char *b) //比较两个文件名是否相同并打印路径
{
if(!strcmp(fmtname(a), b))
printf("%s\n", a);
}
void
find(char *path, char *target)
{
char buf[512], *p;
int fd;
struct dirent de;
struct stat st;
if((fd = open(path, 0)) < 0){ //根据路径打开文件
fprintf(2, "find: cannot open %s\n", path);
return;
}
if(fstat(fd, &st) < 0){ //获取文件参数
fprintf(2, "find: cannot stat %s\n", path);
close(fd);
return;
}
switch(st.type){
case T_FILE://该文件为文件时
cmp(path, target);
break;
case T_DIR: //该文件为文件夹时
if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){
printf("find: path too long\n");
break;
}
strcpy(buf, path);
p = buf+strlen(buf);
*p++ = '/';
while(read(fd, &de, sizeof(de)) == sizeof(de)){
//若文件夹下文件数量为0,1或者该文件夹名字为"."或".."则不进入,防止套娃
if(de.inum == 0 || de.inum == 1 || strcmp(de.name, ".")==0 || strcmp(de.name, "..")==0)
continue;
memmove(p, de.name, strlen(de.name)); //将文件名追加到路径,递归find
p[strlen(de.name)] = '\0';
find(buf, target);
}
break;
}
close(fd);
}
int
main(int argc, char *argv[])
{
if(argc < 3){
printf("Please input the right arg!\n");
exit(0);
}
find(argv[1], argv[2]);
exit(0);
}
在xv6上实现用户程序xargs,即从标准输入中读取行并 为每行运行一次 指定的命令,且将该行作为命令的参数提供。
循环地从标准输出读取数据,并以’\n’为为分割, 将每一行输出作为xargs 后命令的参数并执行
#include "kernel/types.h"
#include "user/user.h"
int main(int argc, char *argv[])
{
int i;
int j = 0;
char *pi_buf[32]; //储存所有参数的字符串指针数组
char total_buf[256]; //储存所有输入的缓存区
char *buf = total_buf; //指向当前处理到的缓存区位置
char *pi; //指向当前处理字符串的开头
pi = buf;
for(i = 1; i < argc; ++i) //首先载入 xargs 后指令自带的参数
{
pi_buf[j++] = argv[i];
}
int len;
int sum = 0;
while((len = read(0, buf, 32)) > 0)//循环读入标准输入 0
{
sum += len; //当标准输入长度大于256时退出
if(sum > 256)
{
printf("the args is too long!\n");
exit(0);
}
for(i = 0; i < len; ++i) //处理该轮读入的数据
{
if(buf[i] == ' ')//读到了一个字符串的结尾
{
buf[i] = 0; //手动将字符串结尾置为'\0': c风格字符串以'\0’为结尾
pi_buf[j++] = pi; //在参数数组中加入新的参数字符串
pi = &buf[i+1]; //pi指向下一个字符串的开头(如果有的话)
}
else if(buf[i] == '\n') //读到了一行的结尾
{
buf[i] = 0;
pi_buf[j++] = pi;
pi = &buf[i + 1];
//上同读到字符串结尾的操作
//将参数列表尾置0, exec要求参数列表第一个为指令本身,列表尾为0,即{cmd,arg1,arg2,..,0}
pi_buf[j] = 0;
if(fork() == 0) //启动子进程执行命令
{
exec(argv[1], pi_buf);
exit(0);
}
else
{
//处理完标准输出的一行,将参数列表置回初始状态
//{cmd, arg1, arg2, extern_arg1, extern_arg1,.. , 0} -> {cmd, arg1, arg2, }
j = argc - 1;
wait(0);
}
}
}
//当前缓冲区处理位置更新
buf = buf + len;
}
exit(0);
return 0;
}