• 基于xv6的类Uinx操作系统实现


    总结

    在这里插入图片描述

    01 低级

    1.1 添加简单程序

    app.c

    #include "types.h"
    #include "stat.h"
    #include "user.h"
    
    int main(int argc, char *argv[]) {
        printf(1, "Hello World\n");
        exit();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    UPROGS 中添加

    image-20221011192416325

    make 后生成

    image-20221011192506673

    运行结果

    image-20221011192624816

    1.2 系统调用示例

    查看pid

    image-20221011193106471

    1.3 系统调用getcpuid()

    • 编写 pcpuid.c 代码
    • 同样修改 Makefile,添加一行 pcpuid 即可, 系统启动以后直接输入 pcpuid 打印cpu号
    • 在 syscall.h 中添加一行系统调用号 22 号
    • 然后再增加用户态的进入接口,在 user.h 中添加一行 int getcpuid(void); (getcpuid函数在 pcpuid.c中调用了)
    • 在 usys.S 中加入一行 SYSCALL(getcpuid) 以定义用户态的入口。将系统调用号保存在eax寄存器中 触发软中断 int 0x40(int 64)进入内核的中断处理函数

    =====================================================================================================================================================================内核与应用层分割线

    • 在 syscall.c 中的分发函数表中添加 getcpuid 函数所对应的表项 [SYS_getcpuid] sys_getcpuid (以eax及系统调用号 在 syscalls[]系统调用表中找到需要执行的代码)
    • 然后修改 syscall.c,添加一行 sys_getcpuid 函数的声明 extern int sys_getcpuid(void);
    • 然后开始实现 sys_getcpuid 函数。在 sysproc.c 中添加 sys_getcpuid 的实现
    sys_getcpuid(void) {
      return getcpuid();
    }
    
    • 1
    • 2
    • 3
    • 在 proc.c 中实现内核态的 getcpuid 函数
    int getcpuid() {
      return cpunum();
    }
    
    • 1
    • 2
    • 3
    • 最后在defs.h中加入 getcpuid 用作内核态代码调用 getcpuid()时的函数原型 (为了让sysproc.c中的sys_getcpuid()可以调用proc.c中的getcpuid())

    运行结果

    image-20221012211425369

    1.4 观察调度过程

    #include "types.h"
    #include "stat.h"
    #include "user.h"
    
    int main(int argc, char *argv[]) {
        printf(1, "Hello World\n");
        int a;
        a = fork();
        a = fork();
        while(1) {
            a++;
        } 
        exit();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    实验结果:

    image-20221012213415509

    可以看出每次在不同的进程运行,说明时间片在轮转

    image-20221012213717132

    02 中级

    2.1 调整时间片长度

    运行结果

    cprintf(“slice left:%d ticks,%d %s %s”, p->slot, p->pid, state, p->name);

    输出4个参数 时间片剩余数 进程号 进程状态 进程名字

    image-20221013224300917

    2.2 信号量

    spinlock.c

    int sys_sem_create(void) {
        int n_sem, i;
        if(argint(0, &n_sem) < 0 )
            return -1;
        for(i = 0; i < SEM_MAX_NUM; i++) {
            acquire(&sems[i].lock);
            if(sems[i].allocated == 0) {
                sems[i].allocated = 1;
                sems[i].resource_count = n_sem;
                cprintf("create %d sem\n",i);
                release(&sems[i].lock);
                return i;
            }
            release(&sems[i].lock);
        }
        return -1;
     }
    
    
    int sys_sem_free(){
        int id;    
        if(argint(0,&id)<0)        
          return -1;
        acquire(&sems[id].lock);    
        if(sems[id].allocated == 1 && sems[id].resource_count > 0){        
            sems[id].allocated = 0;        
            cprintf("free %d sem\n", id);    
        }    
        release(&sems[id].lock);
        return 0;
    }
    
    int sys_sem_p()
    {       int id;
        if(argint(0, &id) < 0)
          return -1;
        acquire(&sems[id].lock);
        sems[id]. resource_count--;
        if(sems[id].resource_count<0)           //首次进入、或被唤醒时,资源不足
          sleep(&sems[id],&sems[id].lock);        //睡眠(会释放sems[id].lock才阻塞)
        release(&sems[id].lock);                                //解锁(唤醒到此处时,重新持有sems[id].lock)
        return 0;                                               //此时获得信号量资源
    }
    
    int sys_sem_v()
    {       int id;
        if(argint(0,&id)<0)
          return -1;
        acquire(&sems[id].lock);
        sems[id]. resource_count+=1;            //增1
        if(sems[id].resource_count<1)                   //有阻塞等待该资源的进程
          wakeup1p(&sems[id]);                    //唤醒等待该资源的1个进程
        release(&sems[id].lock);                                //释放锁
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    sh_rw_lock.c文件

    #include "types.h"
    #include "stat.h"
    #include "user.h"
    
    int main(){
    	int id=sem_create(1);
    	int pid = fork();
    	int i;
    	for(i=0;i<100000;i++){
    		sem_p(id);
    		sh_var_write(sh_var_read()+1);
    		sem_v(id);
    	}
    	if(pid >0){
    		wait();
    		sem_free(id);
    	}
    	printf(1,"sum=%d\n",sh_var_read());
    	exit();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    运行结果

    image-20221020193157565

    2.3 进程间通信

    2.3.1 共享内存

    sharemem.c

    #include "types.h"
    #include "defs.h"
    #include "param.h"
    #include "mmu.h"
    #include "proc.h"
    #include "spinlock.h"
    #include "memlayout.h"
    #define MAX_SHM_PGNUM (4) 	//每个共享内存最带4页内存
    
    struct sharemem
    {
        int refcount;     		//当前共享内存引用数,当引用数为0时才会真正回收
        int pagenum;		//占用的页数(0-4)
        void* physaddr[MAX_SHM_PGNUM];   		//对应每页的物理地址
    };
    struct spinlock shmlock;    			//用于互斥访问的锁
    struct sharemem shmtab[8];  			//整个系统最多8个共享内存
    
    void
    sharememinit()
    {
        initlock(&shmlock,"shmlock");   //初始化锁
        for (int i = 0; i < 8; i++)     //初始化shmtab
        {
            shmtab[i].refcount = 0;
        }
        
        cprintf("shm init finished.\n");
    }
    
    int
    shmkeyused(uint key, uint mask)
    {
        if(key<0 || 8<=key){
            return 0;
        }
        return (mask >> key) & 0x1;  //这里判断对应的系统共享内存区是否已经启用
    }
    
    
    int
    shmrm(int key)
    {
        if(key<0||8<=key){
            return -1;
        }
        //cprintf("shmrm: key is %d\n",key);
        struct sharemem* shmem = &shmtab[key];
        for(int i=0;i<shmem->pagenum;i++){
            kfree((char*)P2V(shmem->physaddr[i]));   		//逐个页帧回收
        }
        shmem->refcount = 0;
        return 0;
    }
    
    
    int
    shmadd(uint key, uint pagenum, void* physaddr[MAX_SHM_PGNUM])
    {
        if(key<0 || 8<=key || pagenum<0 || MAX_SHM_PGNUM < pagenum){
            return -1;
        }
        shmtab[key].refcount = 1;
        shmtab[key].pagenum = pagenum;
        for(int i = 0;i<pagenum;++i){
            shmtab[key].physaddr[i] = physaddr[i];
        }
        return 0;
    }
    
    int
    mapshm(pde_t *pgdir, uint oldshm, uint newshm, uint sz, void **physaddr)
    {
        uint a;
        if(oldshm & 0xFFF || newshm & 0xFFF || oldshm > KERNBASE || newshm < sz)
            return 0;  												//验证参数
        a=newshm;
        for (int i = 0;a<oldshm;a+=PGSIZE, i++) 					//逐页映射
        {
            mappages(pgdir,(char*)a,PGSIZE,(uint)physaddr[i],PTE_W|PTE_U);
        }
        return newshm;
    }
    
    int
    deallocshm(pde_t *pgdir, uint oldshm, uint newshm)
    {
    	pte_t *pte;
    	uint a, pa;
    	if(newshm <= oldshm)
    		return oldshm;
    	a = (uint)PGROUNDDOWN(newshm - PGSIZE);
    	for (; oldshm <= a; a-=PGSIZE)
    	{
    		pte = walkpgdir(pgdir,(char*)a,0);
    		if(pte && (*pte & PTE_P)!=0){
    			pa = PTE_ADDR(*pte);
    		if(pa == 0){
    			panic("kfree");
    		}
    		*pte = 0;
    		}
    	}
    	return newshm;
    }
    
    // 这个方法和allcouvm实现基本一样
    int
    allocshm(pde_t *pgdir, uint oldshm, uint newshm, uint sz,void *phyaddr[MAX_SHM_PGNUM])
    {
        char *mem;
        uint a;
        
        if(oldshm & 0xFFF || newshm & 0xFFF || oldshm > KERNBASE || newshm < sz)
            return 0;
        a = newshm;
        for (int i = 0; a < oldshm; a+=PGSIZE, i++)
        {
            mem = kalloc(); 		//分配物理页帧
            if(mem == 0){
                // cprintf("allocshm out of memory\n");
                deallocshm(pgdir,newshm,oldshm);
                return 0;
            }
            memset(mem,0,PGSIZE);
            mappages(pgdir,(char*)a,PGSIZE,(uint)V2P(mem),PTE_W|PTE_U);	//页表映射
            phyaddr[i] = (void *)V2P(mem);
            // cprintf("allocshm : %x\n",a);
        }
        return newshm;
    }
    
    
    void*
    shmgetat(uint key, uint num)
    {
        pde_t *pgdir;
        void *phyaddr[MAX_SHM_PGNUM];
        uint shm =0;
        if(key<0||8<=key||num<0||MAX_SHM_PGNUM<num) 	//校验参数
            return (void*)-1;
        acquire(&shmlock);
        pgdir = proc->pgdir;
    shm = proc->shm;
    
    // 情况1.如果当前进程已经映射了该key的共享内存,直接返回地址
        if(proc->shmkeymask>>key & 1){ 
            release(&shmlock);
            return proc->shmva[key];
    }
    
    // 情况2.如果系统还未创建此key对应的共享内存,则分配内存并映射
        if(shmtab[key].refcount == 0){
            shm = allocshm(pgdir, shm, shm - num * PGSIZE, proc->sz, phyaddr); 
    //新增的allocshm()分配内存并映射,其原理和allcouvm()相同
            if(shm == 0){
                release(&shmlock);
                return (void*)-1;
            }
            proc->shmva[key] = (void*)shm;
            shmadd(key, num, phyaddr);	//将新内存区信息填入shmtab[8]数组
        }else { 
    
    //情况3.如果未持有且已经系统中分配此key对应的共享内存,则直接映射
            for(int i = 0;i<num;i++)
            {
                phyaddr[i] = shmtab[key].physaddr[i];
            }
            num = shmtab[key].pagenum;
    		//mapshm方法新建映射
            if((shm = mapshm(pgdir,shm,shm-num*PGSIZE,proc->sz,phyaddr))==0){
                release(&shmlock);
                return (void*)-1;
            }
            proc->shmva[key] = (void*)shm;
            shmtab[key].refcount++;			//引用计数+1
        }
        proc->shm = shm;
        proc->shmkeymask |= 1<<key;
        release(&shmlock);
        return (void*)shm;
    }
    
    void
    shmaddcount(uint mask)
    {
    	acquire(&shmlock);
    	for (int key = 0; key < 8; key++)
    	{
    	if(shmkeyused(key,mask)){   //对目前进程所有引用的共享内存的引用数加1
    		shmtab[key].refcount++;   
    		}
    	}
    	release(&shmlock);
    }
    
    int
    shmrelease(pde_t *pgdir, uint shm, uint keymask)
    {
        //cprintf("shmrelease: shm is %x, keymask is %x.\n",shm, keymask);
        acquire(&shmlock);
        deallocshm(pgdir,shm,KERNBASE); 				//释放用户空间的内存
        for (int k = 0; k < 8; k++)
        {
            if(shmkeyused(k,keymask)){
                shmtab[k].refcount--;   				//引用数目减1
                if(shmtab[k].refcount==0){  			//若为0 ,即可以回收物理内存
                    shmrm(k);    
                }
            }
        }
        release(&shmlock);
        return 0;
    }
    
    int
    shmrefcount(uint key)
    {
        acquire(&shmlock);
        int count;
        count = (key<0||8<=key)? -1:shmtab[key].refcount;
        release(&shmlock);
        return count;
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226

    test.c

    #include "types.h"
    #include "stat.h"
    #include "user.h"
    #include "fs.h"
    int main(void)
    {
      char *shm;
      int pid = fork();
      if(pid == 0){
        sleep(1);
        shm = (char*)shmgetat(1,3);//key为1,大小为3页的共享内存
        printf(1,"child  process pid:%d shm is %s refcount of 1 is:%d\n", getpid(), shm, shmrefcount(1));
        strcpy(shm, "hello_world!");
        printf(1, "child  process pid:%d write %s into the shm\n", getpid(), shm);
      } else if (pid > 0) {
        shm = (char*)shmgetat(1,3);
        printf(1,"parent process pid:%d before wait() shm is %s refcount of 1 is:%d\n", getpid(), shm, shmrefcount(1));
        strcpy(shm, "share_memory!");
        printf(1,"parent process pid:%d write  %s into the shm\n", getpid(), shm);
        wait();
        printf(1,"parent process pid:%d after wait() shm is %s refcount of 1 is:%d\n", getpid(), shm, shmrefcount(1));
      }
      exit();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    image-20221020202119861

    2.3.2 消息队列

    messagequeue.c

    #include "types.h"
    #include "defs.h"
    #include "param.h"
    #include "mmu.h"
    #include "proc.h"
    #include "spinlock.h"
    
    struct msg {
        struct msg *next;
        long type;
        char *dataaddr;
        int  datasize;
    };
    
    struct mq {
        int key;
        int status;
        struct msg *msgs;
        int maxbytes;
        int curbytes;
        int refcount;
    };
    
    struct spinlock mqlock;
    struct mq mqs[MQMAX];
    struct proc* wqueue[NPROC];
    int wstart=0;
    
    struct proc* rqueue[NPROC];
    int rstart=0;
    
    void
    mqinit()
    {
        cprintf("mqinit.\n");
        initlock(&mqlock,"mqlock");
        for(int i =0;i<MQMAX;++i){
            mqs[i].status = 0;
        }
    }
    
    int findkey(int key)
    {
        int idx =-1;
        for(int i = 0;i<MQMAX;++i){
            if(mqs[i].status != 0 && mqs[i].key == key){
                idx = i;
                break;
            }
        }
        return idx;
    }
    
    int newmq(int key)
    {
        int idx =-1;
        for(int i=0;i<MQMAX;++i){
            if(mqs[i].status == 0){
                idx = i;
                break;
            }
        }
        if(idx == -1){
            cprintf("newmq failed: can not get idx.\n");
            return -1;
        }
        mqs[idx].key = key;
        mqs[idx].status = 1;
        mqs[idx].msgs = (struct msg*)kalloc();
        if(mqs[idx].msgs == 0){
            cprintf("newmq failed: can not alloc page.\n");
            return -1;
        }
        memset(mqs[idx].msgs,0,PGSIZE);
        mqs[idx].msgs -> next = 0;
        mqs[idx].msgs -> datasize = 0;
        mqs[idx].maxbytes = PGSIZE;
        mqs[idx].curbytes = 16;
        mqs[idx].refcount = 1;
        proc->mqmask |= 1 << idx;
        return idx;
    
    }
    
    int
    mqget(uint key)
    {
        acquire(&mqlock);
        int idx = findkey(key);
        if(idx != -1){
            if(!(proc->mqmask >> idx & 1)){
                proc->mqmask |= 1 << idx;
                mqs[idx].refcount++;
            }
            release(&mqlock);
            return idx;
        }
        idx = newmq(key);
        release(&mqlock);
        return idx;
    }
    int
    msgsnd(uint mqid, void* msg, int sz)
    {
        if(mqid<0 || MQMAX<=mqid || mqs[mqid].status == 0){
            return -1;
        }
    
        char *data = (char *)(*((int *) (msg + 4)));
        int  *type = (int *)msg;
    
        if(mqs[mqid].msgs == 0){
            cprintf("msgsnd failed: msgs == 0.\n");
            return -1;
        }
    
        acquire(&mqlock);
    
        while(1){
            if(mqs[mqid].curbytes + sz + 16 <= mqs[mqid].maxbytes){
                struct msg *m = mqs[mqid].msgs;
                while(m->next != 0){
                    m = m -> next;
                }
                m->next = (void *)m + m->datasize + 16;
                m = m -> next;
                m->type = *(type);
                m->next = 0;
                m->dataaddr = (void*)m + 16;
                m->datasize = sz;
                memmove(m->dataaddr, data, sz);
                mqs[mqid].curbytes += (sz+16);
    
                for(int i=0; i<rstart; i++)
                {
                    wakeup(rqueue[i]);
                }
                rstart = 0;
    
                release(&mqlock);
                return 0;
            } else {
                cprintf("msgsnd: can not alloc: pthread: %d sleep.\n",proc->pid);
                wqueue[wstart++] = proc;
    
                sleep(proc,&mqlock);
            }
            
        }
    
        return -1;
    }
    
    
    
    int reloc(int mqid)
    {
        struct msg *pages = mqs[mqid].msgs;
        struct msg *m  = pages;
        struct msg *t;
        struct msg *pre = pages;
        while (m != 0)
        {
            t = m->next;
            memmove(pages, m, m->datasize+16);
            pages->next = (struct msg *)((char *)pages + pages->datasize + 16);
            pages->dataaddr = ((char *)pages + 16);
            pre = pages;
            pages = pages->next;
            m = t;
        }
        pre->next = 0;
        return 0;
    }
    
    
    
    int
    msgrcv(uint mqid, void* msg, int sz)
    {
        if(mqid<0 || MQMAX<=mqid || mqs[mqid].status ==0){
            return -1;
        }
        int *type = msg;
        int *data = msg + 4;
        acquire(&mqlock);
        
        while(1){
            struct msg *m = mqs[mqid].msgs->next;
            struct msg *pre = mqs[mqid].msgs;
            while (m != 0)
            {
                if(m->type == *type){
                    memmove((char *)*data, m->dataaddr, sz);
                    pre->next = m->next;
                    mqs[mqid].curbytes -= (m->datasize + 16);
                    reloc(mqid);
    
                    for(int i=0; i<wstart; i++)
                    {
                        wakeup(wqueue[i]);
                    }
                    wstart = 0;
    
                    release(&mqlock);
                    return 0;
                }
                pre = m;
                m = m->next;
            }
            cprintf("msgrcv: can not read: pthread: %d sleep.\n",proc->pid);
            rqueue[rstart++] = proc;
            sleep(proc,&mqlock);
        }
        return -1;
    }
    
    void
    rmmq(int mqid)
    {
        kfree((char *)mqs[mqid].msgs);
        mqs[mqid].status = 0;
    }
    
    void
    releasemq2(int mask)
    {
        acquire(&mqlock);
        for(int id = 0;id<MQMAX;++id){
            if( mask >> id & 0x1){
                mqs[id].refcount--;
                if(mqs[id].refcount == 0){
                    rmmq(id);
                }
            }
        }
        release(&mqlock);
    }
    
    
    void
    releasemq(uint key)
    {
        //cprintf("releasemq: %d.\n",key);
      int idx= findkey(key);
      if (idx!=-1){
          acquire(&mqlock);
              mqs[idx].refcount--;   //引用数目减1
                if(mqs[idx].refcount == 0)  //引用数目为0时候需要回收物理内存
                    rmmq(idx);
           release(&mqlock);
         }
    }
    
    
    
    void
    addmqcount(uint mask)
    {
        acquire(&mqlock);
        for (int key = 0; key < MQMAX; key++)
        {
            if(mask >> key & 1){
                mqs[key].refcount++;
            }
        }
        release(&mqlock);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268

    msg_test.c

    #include "param.h"
    #include "types.h"
    #include "stat.h"
    #include "user.h"
    #include "fs.h"
    #include "fcntl.h"
    #include "syscall.h"
    #include "traps.h"
    #include "memlayout.h"
    
    
    struct msg{
      int type;
      char *dataaddr;
    }s1,s2,g;
    
    void msg_test()
    {
      int mqid = mqget(123);
      // int msg_len = 48;
      // s1.dataaddr = "total number:47 : hello, this is child process.";
      int pid = fork();
      if(pid == 0){
        s1.type = 1;
        s1.dataaddr = "This is the first message!";
        msgsnd(mqid, &s1, 27);
        s1.type = 2;
        s1.dataaddr = "Hello, another message comes!";
        msgsnd(mqid, &s1, 30);
        s1.type = 3;
        s1.dataaddr = "This is the third message, and this message has great many characters!";
        msgsnd(mqid, &s1, 70);
        // sleep(10);
        // for(int i=0; i<70; i++)
        // {
        //   s1.type = i;
        //   msgsnd(mqid, &s1, msg_len);
        // }
        printf(1,"all messages have been sent.\n");
      } else if (pid >0)
      {
        // sleep(10);     // sleep保证子进程消息写入
        // g.dataaddr = malloc(msg_len);
        // for(int i=0; i<70; i++)
        // {
        //   g.type = i;
        //   msgrcv(mqid, &g, msg_len);
        //   printf(1, "读取第%d个消息: %s\n", i, g.dataaddr);
    
        // }
        sleep(10);      // sleep保证子进程消息写入
        g.dataaddr = malloc(70);
        g.type = 2;
        msgrcv(mqid,&g, 30);
        printf(1, "receive the %dth message: %s\n", 2, g.dataaddr);
        g.type = 1;
        msgrcv(mqid,&g, 27);
        printf(1, "receive the %dth message: %s\n", 1, g.dataaddr);
        g.type = 3;
        msgrcv(mqid,&g, 70);
        printf(1, "receive the %dth message: %s\n", 3, g.dataaddr);
    
        wait();
    
      }
      exit();
    }
    
    
    int
    main(int argc, char *argv[])
    {
      // printf(1, "消息队列测试\n");
      msg_test();
      exit();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76

    运行结果

    image-20221021200348259

    2.4 内存管理

    2.4.1 实现myfree()和myalloc()系统调用\

    myalloc.c

    #include "types.h"
    #include "stat.h"
    #include "user.h"
    
    
    int
    main(int argc, char *argv[]) {
      // int pid = getpid();   
      // map(pid);
      
      char* m1 = (char*)myalloc(2 * 4096);
      char* m2 = (char*)myalloc(3 * 4096);
      char* m3 = (char*)myalloc(1 * 4096);
      char* m4 = (char*)myalloc(7 * 4096);
      char* m5 = (char*)myalloc(9 * 4096);
    
      m1[0] = 'h';
      m1[1] = '\0';
    
    
      printf(1,"m1:%s\n",m1);
      myfree(m2);
    
      //m2[1] = 'p';
    
      myfree(m4);
      
      // map(pid);
      sleep(5000);
      myfree(m1);
      myfree(m3);
      myfree(m5);
      // char *p=(char *)0x0000;
      // for(int i=0x0000;i<0x08;i++)
      //     *(p+i)='*';
    
      // printf(1,"This string shouldn't be modified!\n");
      // exit();
    
    
      exit();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    运行结果:

    image-20221021211837168

    遇见问题:

    image-20221021212021956

    解决:

    image-20221021212625546

    03 高级

    3.1 实现xv6内核线程

    创建线程的开销比创建进程要小,线程可以共享进程的主要资源,例如内存映像、打开的文件等。在xv6上实现线程所涉及的主要工作如下:

    • 实现clone系统调用,用于创建一个内核线程
    • 实现join系统调用,用于回收一个内核线程
    • 实现用户线程库,封装对线程的管理,而用户只需要知道接口即可
    • 提供测试样例,包括共享进程空间、多线程并行

    注意:建立在2.4.1基础上

    3.2 文件系统

    文件系统方面主要实现了三个功能

    • 为xv6文件系统增加文件读写权限控制
    • 实现恢复被删除的文件内容
    • 和设备有关的磁盘裸设备的读写

    3.3 虚拟内存

    实现的虚存交换机制比较简陋,换出的页帧内容保存到磁盘文件系统的普通文件数据区,而不是Linux那样使用独立的交换分区获得交换文件。换出的页帧所在盘块号直接保存在其pte的高位,其pte低12位仍用作标志用途。

  • 相关阅读:
    IPv6环境telnet报错:Permission denied
    Rust编程中的共享状态并发执行
    维格云门户入门教程
    5. Makefile项目管理
    FFmpeg开发笔记(五十七)使用Media3的Transformer加工视频文件
    【C++11】shared_ptr智能指针使用详解
    计算机毕业设计之java+ssm学术成果管理系统
    虚拟机--无法连接网络
    redis5.0配置一主两从三哨兵
    python如何筛选具有多列值相同的两个dataframe
  • 原文地址:https://blog.csdn.net/qq_41945053/article/details/127691780