forktest failed
This commit is contained in:
parent
9cc6b83453
commit
294e926e52
16
.vscode/c_cpp_properties.json
vendored
Normal file
16
.vscode/c_cpp_properties.json
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Linux",
|
||||||
|
"includePath": [
|
||||||
|
"${workspaceFolder}/**"
|
||||||
|
],
|
||||||
|
"defines": ["LAB_MMAP"],
|
||||||
|
"compilerPath": "/usr/bin/gcc",
|
||||||
|
"cStandard": "gnu17",
|
||||||
|
"cppStandard": "gnu++17",
|
||||||
|
"intelliSenseMode": "linux-gcc-x64"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": 4
|
||||||
|
}
|
||||||
1
Makefile
1
Makefile
@ -188,6 +188,7 @@ UPROGS=\
|
|||||||
$U/_grind\
|
$U/_grind\
|
||||||
$U/_wc\
|
$U/_wc\
|
||||||
$U/_zombie\
|
$U/_zombie\
|
||||||
|
$U/_mmaptest\
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -187,3 +187,6 @@ void virtio_disk_intr(void);
|
|||||||
|
|
||||||
// number of elements in fixed-size array
|
// number of elements in fixed-size array
|
||||||
#define NELEM(x) (sizeof(x)/sizeof((x)[0]))
|
#define NELEM(x) (sizeof(x)/sizeof((x)[0]))
|
||||||
|
|
||||||
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||||
164
kernel/proc.c
164
kernel/proc.c
@ -5,6 +5,15 @@
|
|||||||
#include "spinlock.h"
|
#include "spinlock.h"
|
||||||
#include "proc.h"
|
#include "proc.h"
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
|
#include "fcntl.h"
|
||||||
|
#include "sleeplock.h"
|
||||||
|
#include "fs.h"
|
||||||
|
#include "file.h"
|
||||||
|
|
||||||
|
static struct vma vma_pool[NMAXVMA];
|
||||||
|
static struct spinlock lock_vma_pool;
|
||||||
|
uint64 do_munmap(uint64 addr, int length);
|
||||||
|
uint64 do_mmap(struct proc* p, int length, int prot, int flags, int fd);
|
||||||
|
|
||||||
struct cpu cpus[NCPU];
|
struct cpu cpus[NCPU];
|
||||||
|
|
||||||
@ -33,7 +42,7 @@ void
|
|||||||
proc_mapstacks(pagetable_t kpgtbl)
|
proc_mapstacks(pagetable_t kpgtbl)
|
||||||
{
|
{
|
||||||
struct proc *p;
|
struct proc *p;
|
||||||
|
initlock(&lock_vma_pool, "vma_pool");
|
||||||
for(p = proc; p < &proc[NPROC]; p++) {
|
for(p = proc; p < &proc[NPROC]; p++) {
|
||||||
char *pa = kalloc();
|
char *pa = kalloc();
|
||||||
if(pa == 0)
|
if(pa == 0)
|
||||||
@ -318,6 +327,30 @@ fork(void)
|
|||||||
np->parent = p;
|
np->parent = p;
|
||||||
release(&wait_lock);
|
release(&wait_lock);
|
||||||
|
|
||||||
|
acquire(&np->lock);
|
||||||
|
for (int i = 0; i < NMAXVMA; ++ i) {
|
||||||
|
if (p->map_region[i]) {
|
||||||
|
struct vma* newvma = 0;
|
||||||
|
acquire(&lock_vma_pool);
|
||||||
|
for (int i = 0; i < NMAXVMA; ++ i) {
|
||||||
|
if (vma_pool[i].length == 0) {
|
||||||
|
newvma = &vma_pool[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!newvma || newvma->length)
|
||||||
|
panic("mmap: vma pool run out");
|
||||||
|
newvma->f = filedup(p->map_region[i]->f);
|
||||||
|
newvma->addr = p->map_region[i]->addr;
|
||||||
|
newvma->prot = p->map_region[i]->prot;
|
||||||
|
newvma->length = p->map_region[i]->length;
|
||||||
|
newvma->flag = p->map_region[i]->flag;
|
||||||
|
release(&lock_vma_pool);
|
||||||
|
np->map_region[i] = newvma;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
release(&np->lock);
|
||||||
|
|
||||||
acquire(&np->lock);
|
acquire(&np->lock);
|
||||||
np->state = RUNNABLE;
|
np->state = RUNNABLE;
|
||||||
release(&np->lock);
|
release(&np->lock);
|
||||||
@ -351,6 +384,13 @@ exit(int status)
|
|||||||
if(p == initproc)
|
if(p == initproc)
|
||||||
panic("init exiting");
|
panic("init exiting");
|
||||||
|
|
||||||
|
// clear mmaps
|
||||||
|
for (int i = 0; i < NMAXVMA; ++ i) {
|
||||||
|
if (p->map_region[i]) {
|
||||||
|
do_munmap(p->map_region[i]->addr, p->map_region[i]->length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Close all open files.
|
// Close all open files.
|
||||||
for(int fd = 0; fd < NOFILE; fd++){
|
for(int fd = 0; fd < NOFILE; fd++){
|
||||||
if(p->ofile[fd]){
|
if(p->ofile[fd]){
|
||||||
@ -681,3 +721,125 @@ procdump(void)
|
|||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64 do_mmap(struct proc* p, int length, int prot, int flags, int fd)
|
||||||
|
{
|
||||||
|
uint64 addr;
|
||||||
|
struct vma* newvma = 0;
|
||||||
|
if (fd < 0 || fd > NOFILE || p->ofile[fd] == 0){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!p->ofile[fd]->writable && (prot & PROT_WRITE) && (flags != MAP_PRIVATE)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// find vacant addr space
|
||||||
|
addr = MMAP_START;
|
||||||
|
for (int i = 0; i < NMAXVMA; ++ i) {
|
||||||
|
// in case some va has been occupied by some other vma but not accessed
|
||||||
|
if (p->map_region[i]) {
|
||||||
|
int _tmp = PGROUNDUP(p->map_region[i]->addr + length);
|
||||||
|
addr = _tmp > addr ? _tmp : addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
acquire(&lock_vma_pool);
|
||||||
|
for (int i = 0; i < NMAXVMA; ++ i) {
|
||||||
|
if (vma_pool[i].length == 0) {
|
||||||
|
newvma = &vma_pool[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!newvma || newvma->length)
|
||||||
|
panic("mmap: vma pool run out");
|
||||||
|
newvma->f = p->ofile[fd];
|
||||||
|
newvma->addr = addr;
|
||||||
|
newvma->prot = prot;
|
||||||
|
newvma->length = length;
|
||||||
|
newvma->flag = flags;
|
||||||
|
release(&lock_vma_pool);
|
||||||
|
|
||||||
|
filedup(newvma->f);
|
||||||
|
for (int i = 0; i < NMAXVMA; ++ i) {
|
||||||
|
if (p->map_region[i] == 0) {
|
||||||
|
p->map_region[i] = newvma;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// void *mmap(void *addr, int length, int prot, int flags, int fd, int offset);
|
||||||
|
// int munmap(void *addr, int length);
|
||||||
|
uint64 sys_mmap(void)
|
||||||
|
{
|
||||||
|
uint64 addr;
|
||||||
|
int length, prot, flags, fd, offset;
|
||||||
|
argaddr(0, &addr);
|
||||||
|
argint(1, &length);
|
||||||
|
argint(2, &prot);
|
||||||
|
argint(3, &flags);
|
||||||
|
argint(4, &fd);
|
||||||
|
argint(5, &offset);
|
||||||
|
// some preliminary check
|
||||||
|
if (addr != 0 || offset != 0) panic("Unsupported non-zero value for arg addr and off");
|
||||||
|
return do_mmap(myproc(), length, prot, flags, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64 do_munmap(uint64 addr, int length)
|
||||||
|
{
|
||||||
|
struct vma* vma0 = 0;
|
||||||
|
struct proc* p = myproc();
|
||||||
|
int imap = 0;
|
||||||
|
for (int i = 0; i < NMAXVMA; ++ i) {
|
||||||
|
if(p->map_region[i]
|
||||||
|
&& p->map_region[i]->addr <= addr
|
||||||
|
&& addr < p->map_region[i]->addr + p->map_region[i]->length) {
|
||||||
|
vma0 = p->map_region[i];
|
||||||
|
imap = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (vma0 == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// remove all relavant pages
|
||||||
|
// by reading the test code, no need to worry about non-aligned unmap
|
||||||
|
// or those unmaps which would break a vma into parts
|
||||||
|
uint64 vma_end = PGROUNDUP(vma0->addr + vma0->length);
|
||||||
|
uint64 free_start = MAX(PGROUNDDOWN(addr), vma0->addr);
|
||||||
|
uint64 free_end = MIN(PGROUNDUP(addr + length), vma_end);
|
||||||
|
for (uint64 va0 = free_start; va0 < free_end; va0 += PGSIZE) {
|
||||||
|
if (vma0->flag == MAP_SHARED) {
|
||||||
|
begin_op();
|
||||||
|
ilock(vma0->f->ip);
|
||||||
|
writei(vma0->f->ip, 1, va0, va0 - addr, PGSIZE); // ? no sure if to write whole page
|
||||||
|
iunlock(vma0->f->ip);
|
||||||
|
end_op();
|
||||||
|
}
|
||||||
|
if (walkaddr(p->pagetable, va0))
|
||||||
|
uvmunmap(p->pagetable, va0, 1, 1);
|
||||||
|
}
|
||||||
|
if (free_start <= vma0->addr && free_end >= vma_end) {
|
||||||
|
// all released
|
||||||
|
fileclose(vma0->f);
|
||||||
|
memset(vma0, 0, sizeof(struct vma));
|
||||||
|
p->map_region[imap] = 0;
|
||||||
|
} else if (free_end >= vma_end) {
|
||||||
|
vma0->length = free_start - vma0->addr;
|
||||||
|
} else if (free_start <= vma0->addr) {
|
||||||
|
vma0->length -= free_end - vma0->addr;
|
||||||
|
vma0->addr = free_end;
|
||||||
|
} else {
|
||||||
|
panic("unsupported unmap type");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64 sys_munmap(void)
|
||||||
|
{
|
||||||
|
uint64 addr;
|
||||||
|
int length;
|
||||||
|
argaddr(0, &addr);
|
||||||
|
argint(1, &length);
|
||||||
|
return do_munmap(addr, length);
|
||||||
|
}
|
||||||
@ -81,6 +81,17 @@ struct trapframe {
|
|||||||
|
|
||||||
enum procstate { UNUSED, USED, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };
|
enum procstate { UNUSED, USED, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };
|
||||||
|
|
||||||
|
struct vma {
|
||||||
|
uint64 addr;
|
||||||
|
uint length;
|
||||||
|
uint prot;
|
||||||
|
uint flag;
|
||||||
|
struct file* f;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NMAXVMA 20
|
||||||
|
#define MMAP_START (0x40000000)
|
||||||
|
|
||||||
// Per-process state
|
// Per-process state
|
||||||
struct proc {
|
struct proc {
|
||||||
struct spinlock lock;
|
struct spinlock lock;
|
||||||
@ -103,5 +114,6 @@ struct proc {
|
|||||||
struct context context; // swtch() here to run process
|
struct context context; // swtch() here to run process
|
||||||
struct file *ofile[NOFILE]; // Open files
|
struct file *ofile[NOFILE]; // Open files
|
||||||
struct inode *cwd; // Current directory
|
struct inode *cwd; // Current directory
|
||||||
|
struct vma* map_region[NMAXVMA];
|
||||||
char name[16]; // Process name (debugging)
|
char name[16]; // Process name (debugging)
|
||||||
};
|
};
|
||||||
|
|||||||
@ -101,6 +101,8 @@ extern uint64 sys_unlink(void);
|
|||||||
extern uint64 sys_link(void);
|
extern uint64 sys_link(void);
|
||||||
extern uint64 sys_mkdir(void);
|
extern uint64 sys_mkdir(void);
|
||||||
extern uint64 sys_close(void);
|
extern uint64 sys_close(void);
|
||||||
|
extern uint64 sys_mmap(void);
|
||||||
|
extern uint64 sys_munmap(void);
|
||||||
|
|
||||||
// An array mapping syscall numbers from syscall.h
|
// An array mapping syscall numbers from syscall.h
|
||||||
// to the function that handles the system call.
|
// to the function that handles the system call.
|
||||||
@ -126,6 +128,8 @@ static uint64 (*syscalls[])(void) = {
|
|||||||
[SYS_link] sys_link,
|
[SYS_link] sys_link,
|
||||||
[SYS_mkdir] sys_mkdir,
|
[SYS_mkdir] sys_mkdir,
|
||||||
[SYS_close] sys_close,
|
[SYS_close] sys_close,
|
||||||
|
[SYS_mmap] sys_mmap,
|
||||||
|
[SYS_munmap] sys_munmap,
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@ -20,3 +20,5 @@
|
|||||||
#define SYS_link 19
|
#define SYS_link 19
|
||||||
#define SYS_mkdir 20
|
#define SYS_mkdir 20
|
||||||
#define SYS_close 21
|
#define SYS_close 21
|
||||||
|
#define SYS_mmap 22
|
||||||
|
#define SYS_munmap 23
|
||||||
|
|||||||
@ -5,6 +5,10 @@
|
|||||||
#include "spinlock.h"
|
#include "spinlock.h"
|
||||||
#include "proc.h"
|
#include "proc.h"
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
|
#include "fcntl.h"
|
||||||
|
#include "sleeplock.h"
|
||||||
|
#include "fs.h"
|
||||||
|
#include "file.h"
|
||||||
|
|
||||||
struct spinlock tickslock;
|
struct spinlock tickslock;
|
||||||
uint ticks;
|
uint ticks;
|
||||||
@ -65,6 +69,28 @@ usertrap(void)
|
|||||||
intr_on();
|
intr_on();
|
||||||
|
|
||||||
syscall();
|
syscall();
|
||||||
|
} else if(r_scause() == 13){
|
||||||
|
int va0 = r_stval();
|
||||||
|
struct vma* vma0 = 0;
|
||||||
|
if (va0 < MMAP_START) panic("unknown page fault");
|
||||||
|
for (int i = 0; i < NMAXVMA; ++ i) {
|
||||||
|
if(p->map_region[i]
|
||||||
|
&& p->map_region[i]->addr <= va0
|
||||||
|
&& va0 < p->map_region[i]->addr + p->map_region[i]->length) {
|
||||||
|
vma0 = p->map_region[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint64 phy_addr = (uint64)kalloc();
|
||||||
|
uint pgflag = PTE_U | (vma0->prot << 1);
|
||||||
|
// save some code... there is PTE_R/W/X = PROT_READ/WRITE/EXEC << 1
|
||||||
|
mappages(p->pagetable, va0, PGSIZE, phy_addr, pgflag);
|
||||||
|
memset((void*)phy_addr, 0, PGSIZE);
|
||||||
|
begin_op();
|
||||||
|
ilock(vma0->f->ip);
|
||||||
|
readi(vma0->f->ip, 0, phy_addr, va0 - vma0->addr, PGSIZE);
|
||||||
|
iunlock(vma0->f->ip);
|
||||||
|
end_op();
|
||||||
} else if((which_dev = devintr()) != 0){
|
} else if((which_dev = devintr()) != 0){
|
||||||
// ok
|
// ok
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -179,8 +179,10 @@ uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free)
|
|||||||
for(a = va; a < va + npages*PGSIZE; a += PGSIZE){
|
for(a = va; a < va + npages*PGSIZE; a += PGSIZE){
|
||||||
if((pte = walk(pagetable, a, 0)) == 0)
|
if((pte = walk(pagetable, a, 0)) == 0)
|
||||||
panic("uvmunmap: walk");
|
panic("uvmunmap: walk");
|
||||||
if((*pte & PTE_V) == 0)
|
if((*pte & PTE_V) == 0){
|
||||||
|
printf("%p\n", va);
|
||||||
panic("uvmunmap: not mapped");
|
panic("uvmunmap: not mapped");
|
||||||
|
}
|
||||||
if(PTE_FLAGS(*pte) == PTE_V)
|
if(PTE_FLAGS(*pte) == PTE_V)
|
||||||
panic("uvmunmap: not a leaf");
|
panic("uvmunmap: not a leaf");
|
||||||
if(do_free){
|
if(do_free){
|
||||||
|
|||||||
@ -22,6 +22,8 @@ int getpid(void);
|
|||||||
char* sbrk(int);
|
char* sbrk(int);
|
||||||
int sleep(int);
|
int sleep(int);
|
||||||
int uptime(void);
|
int uptime(void);
|
||||||
|
void *mmap(void *addr, int length, int prot, int flags, int fd, int offset);
|
||||||
|
int munmap(void *addr, int length);
|
||||||
|
|
||||||
// ulib.c
|
// ulib.c
|
||||||
int stat(const char*, struct stat*);
|
int stat(const char*, struct stat*);
|
||||||
|
|||||||
@ -36,3 +36,5 @@ entry("getpid");
|
|||||||
entry("sbrk");
|
entry("sbrk");
|
||||||
entry("sleep");
|
entry("sleep");
|
||||||
entry("uptime");
|
entry("uptime");
|
||||||
|
entry("mmap");
|
||||||
|
entry("munmap");
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user