Attempt to clean up newproc somewhat.
Also remove all calls to memcpy in favor of memmove, which has defined semantics when the ranges overlap. The fact that memcpy was working in console.c to scroll the screen is not guaranteed by all implementations.
This commit is contained in:
parent
65bd8e139a
commit
856e1fc1ad
|
@ -58,7 +58,7 @@ real_cons_putc(int c)
|
||||||
|
|
||||||
if((ind / 80) >= 24){
|
if((ind / 80) >= 24){
|
||||||
// scroll up
|
// scroll up
|
||||||
memcpy(crt, crt + 80, sizeof(crt[0]) * (23 * 80));
|
memmove(crt, crt + 80, sizeof(crt[0]) * (23 * 80));
|
||||||
ind -= 80;
|
ind -= 80;
|
||||||
memset(crt + ind, 0, sizeof(crt[0]) * ((24 * 80) - ind));
|
memset(crt + ind, 0, sizeof(crt[0]) * ((24 * 80) - ind));
|
||||||
}
|
}
|
||||||
|
|
4
defs.h
4
defs.h
|
@ -12,7 +12,7 @@ void cons_putc(int);
|
||||||
struct proc;
|
struct proc;
|
||||||
struct jmpbuf;
|
struct jmpbuf;
|
||||||
void setupsegs(struct proc *);
|
void setupsegs(struct proc *);
|
||||||
struct proc * newproc(void);
|
struct proc * copyproc(struct proc*);
|
||||||
struct spinlock;
|
struct spinlock;
|
||||||
void sleep(void *, struct spinlock *);
|
void sleep(void *, struct spinlock *);
|
||||||
void wakeup(void *);
|
void wakeup(void *);
|
||||||
|
@ -32,7 +32,6 @@ void tvinit(void);
|
||||||
void idtinit(void);
|
void idtinit(void);
|
||||||
|
|
||||||
// string.c
|
// string.c
|
||||||
void * memcpy(void *dst, void *src, unsigned n);
|
|
||||||
void * memset(void *dst, int c, unsigned n);
|
void * memset(void *dst, int c, unsigned n);
|
||||||
int memcmp(const void *v1, const void *v2, unsigned n);
|
int memcmp(const void *v1, const void *v2, unsigned n);
|
||||||
void *memmove(void *dst, const void *src, unsigned n);
|
void *memmove(void *dst, const void *src, unsigned n);
|
||||||
|
@ -92,3 +91,4 @@ void ide_init(void);
|
||||||
void ide_intr(void);
|
void ide_intr(void);
|
||||||
void* ide_start_read(uint32_t secno, void *dst, unsigned nsecs);
|
void* ide_start_read(uint32_t secno, void *dst, unsigned nsecs);
|
||||||
int ide_finish_read(void *);
|
int ide_finish_read(void *);
|
||||||
|
|
||||||
|
|
4
main.c
4
main.c
|
@ -81,7 +81,7 @@ main()
|
||||||
// become interruptable
|
// become interruptable
|
||||||
sti();
|
sti();
|
||||||
|
|
||||||
p = newproc();
|
p = copyproc(&proc[0]);
|
||||||
|
|
||||||
load_icode(p, _binary_usertests_start, (unsigned) _binary_usertests_size);
|
load_icode(p, _binary_usertests_start, (unsigned) _binary_usertests_size);
|
||||||
//load_icode(p, _binary_userfs_start, (unsigned) _binary_userfs_size);
|
//load_icode(p, _binary_userfs_start, (unsigned) _binary_userfs_size);
|
||||||
|
@ -122,7 +122,7 @@ load_icode(struct proc *p, uint8_t *binary, unsigned size)
|
||||||
panic("load_icode: icode wants to be above UTOP");
|
panic("load_icode: icode wants to be above UTOP");
|
||||||
|
|
||||||
// Load/clear the segment
|
// Load/clear the segment
|
||||||
memcpy(p->mem + ph->p_va, binary + ph->p_offset, ph->p_filesz);
|
memmove(p->mem + ph->p_va, binary + ph->p_offset, ph->p_filesz);
|
||||||
memset(p->mem + ph->p_va + ph->p_filesz, 0, ph->p_memsz - ph->p_filesz);
|
memset(p->mem + ph->p_va + ph->p_filesz, 0, ph->p_memsz - ph->p_filesz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
132
proc.c
132
proc.c
|
@ -13,6 +13,7 @@ struct proc proc[NPROC];
|
||||||
struct proc *curproc[NCPU];
|
struct proc *curproc[NCPU];
|
||||||
int next_pid = 1;
|
int next_pid = 1;
|
||||||
extern void forkret(void);
|
extern void forkret(void);
|
||||||
|
extern void forkret1(struct Trapframe*);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* set up a process's task state and segment descriptors
|
* set up a process's task state and segment descriptors
|
||||||
|
@ -42,84 +43,87 @@ setupsegs(struct proc *p)
|
||||||
p->gdt_pd.pd_base = (unsigned) p->gdt;
|
p->gdt_pd.pd_base = (unsigned) p->gdt;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void trapret();
|
// Look in the process table for an UNUSED proc.
|
||||||
|
// If found, change state to EMBRYO and return it.
|
||||||
/*
|
// Otherwise return 0.
|
||||||
* internal fork(). does not copy kernel stack; instead,
|
struct proc*
|
||||||
* sets up the stack to return as if from system call.
|
allocproc(void)
|
||||||
* caller must set state to RUNNABLE.
|
|
||||||
*/
|
|
||||||
struct proc *
|
|
||||||
newproc()
|
|
||||||
{
|
{
|
||||||
struct proc *np;
|
int i;
|
||||||
struct proc *op;
|
struct proc *p;
|
||||||
int fd;
|
|
||||||
|
for(i = 0; i < NPROC; i++){
|
||||||
acquire(&proc_table_lock);
|
p = &proc[i];
|
||||||
|
if(p->state == UNUSED){
|
||||||
for(np = &proc[1]; np < &proc[NPROC]; np++){
|
p->state = EMBRYO;
|
||||||
if(np->state == UNUSED){
|
return p;
|
||||||
np->state = EMBRYO;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(np >= &proc[NPROC]){
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new process copying p as the parent.
|
||||||
|
// Does not copy the kernel stack.
|
||||||
|
// Instead, sets up stack to return as if from system call.
|
||||||
|
// Caller must arrange for process to run (set state to RUNNABLE).
|
||||||
|
struct proc *
|
||||||
|
copyproc(struct proc* p)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct proc *np;
|
||||||
|
|
||||||
|
// Allocate process.
|
||||||
|
acquire(&proc_table_lock);
|
||||||
|
if((np = allocproc()) == 0){
|
||||||
release(&proc_table_lock);
|
release(&proc_table_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy from proc[0] if we're bootstrapping
|
|
||||||
op = curproc[cpu()];
|
|
||||||
if(op == 0)
|
|
||||||
op = &proc[0];
|
|
||||||
|
|
||||||
np->pid = next_pid++;
|
np->pid = next_pid++;
|
||||||
np->ppid = op->pid;
|
np->ppid = p->pid;
|
||||||
|
|
||||||
release(&proc_table_lock);
|
release(&proc_table_lock);
|
||||||
|
|
||||||
np->sz = op->sz;
|
// Copy process image memory.
|
||||||
np->mem = kalloc(op->sz);
|
np->sz = p->sz;
|
||||||
if(np->mem == 0)
|
np->mem = kalloc(np->sz);
|
||||||
return 0;
|
if(np->mem == 0){
|
||||||
memcpy(np->mem, op->mem, np->sz);
|
|
||||||
np->kstack = kalloc(KSTACKSIZE);
|
|
||||||
if(np->kstack == 0){
|
|
||||||
kfree(np->mem, op->sz);
|
|
||||||
np->state = UNUSED;
|
np->state = UNUSED;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
setupsegs(np);
|
memmove(np->mem, p->mem, np->sz);
|
||||||
|
|
||||||
// set up kernel stack to return to user space
|
|
||||||
np->tf = (struct Trapframe *) (np->kstack + KSTACKSIZE - sizeof(struct Trapframe));
|
|
||||||
*(np->tf) = *(op->tf);
|
|
||||||
np->tf->tf_regs.reg_eax = 0; // so fork() returns 0 in child
|
|
||||||
|
|
||||||
// Set up new jmpbuf to start executing forkret (see trapasm.S)
|
// Allocate kernel stack.
|
||||||
// with esp pointing at tf. Forkret will call forkret1 (below) to release
|
np->kstack = kalloc(KSTACKSIZE);
|
||||||
// the proc_table_lock and then jump into the usual trap return code.
|
if(np->kstack == 0){
|
||||||
|
kfree(np->mem, np->sz);
|
||||||
|
np->state = UNUSED;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize segment table.
|
||||||
|
setupsegs(np);
|
||||||
|
|
||||||
|
// Copy trapframe registers from parent.
|
||||||
|
np->tf = (struct Trapframe*)(np->kstack + KSTACKSIZE) - 1;
|
||||||
|
*np->tf = *p->tf;
|
||||||
|
|
||||||
|
// Clear %eax so that fork system call returns 0 in child.
|
||||||
|
np->tf->tf_regs.reg_eax = 0;
|
||||||
|
|
||||||
|
// Set up new jmpbuf to start executing at forkret (see below).
|
||||||
memset(&np->jmpbuf, 0, sizeof np->jmpbuf);
|
memset(&np->jmpbuf, 0, sizeof np->jmpbuf);
|
||||||
np->jmpbuf.jb_eip = (unsigned) forkret;
|
np->jmpbuf.jb_eip = (unsigned)forkret;
|
||||||
np->jmpbuf.jb_esp = (unsigned) np->tf - 4; // -4 for the %eip that isn't actually there
|
np->jmpbuf.jb_esp = (unsigned)np->tf;
|
||||||
|
|
||||||
// Copy file descriptors
|
// Copy file descriptors
|
||||||
for(fd = 0; fd < NOFILE; fd++){
|
for(i = 0; i < NOFILE; i++){
|
||||||
np->fds[fd] = op->fds[fd];
|
np->fds[i] = p->fds[i];
|
||||||
if(np->fds[fd])
|
if(np->fds[i])
|
||||||
fd_reference(np->fds[fd]);
|
fd_reference(np->fds[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return np;
|
return np;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
forkret1(void)
|
|
||||||
{
|
|
||||||
release(&proc_table_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Per-CPU process scheduler.
|
// Per-CPU process scheduler.
|
||||||
// Each CPU calls scheduler() after setting itself up.
|
// Each CPU calls scheduler() after setting itself up.
|
||||||
// Scheduler never returns. It loops, doing:
|
// Scheduler never returns. It loops, doing:
|
||||||
|
@ -199,7 +203,7 @@ sched(void)
|
||||||
|
|
||||||
// Give up the CPU for one scheduling round.
|
// Give up the CPU for one scheduling round.
|
||||||
void
|
void
|
||||||
yield()
|
yield(void)
|
||||||
{
|
{
|
||||||
struct proc *p;
|
struct proc *p;
|
||||||
|
|
||||||
|
@ -211,6 +215,18 @@ yield()
|
||||||
release(&proc_table_lock);
|
release(&proc_table_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A process's very first scheduling by scheduler()
|
||||||
|
// will longjmp here to do the first jump into user space.
|
||||||
|
void
|
||||||
|
forkret(void)
|
||||||
|
{
|
||||||
|
// Still holding proc_table_lock from scheduler.
|
||||||
|
release(&proc_table_lock);
|
||||||
|
|
||||||
|
// Jump into assembly, never to return.
|
||||||
|
forkret1(curproc[cpu()]->tf);
|
||||||
|
}
|
||||||
|
|
||||||
// Atomically release lock and sleep on chan.
|
// Atomically release lock and sleep on chan.
|
||||||
// Reacquires lock when reawakened.
|
// Reacquires lock when reawakened.
|
||||||
void
|
void
|
||||||
|
|
30
string.c
30
string.c
|
@ -1,18 +1,6 @@
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
|
|
||||||
void *
|
|
||||||
memcpy(void *dst, void *src, unsigned n)
|
|
||||||
{
|
|
||||||
char *d = (char *) dst;
|
|
||||||
char *s = (char *) src;
|
|
||||||
|
|
||||||
while(n-- > 0)
|
|
||||||
*d++ = *s++;
|
|
||||||
|
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *
|
void *
|
||||||
memset(void *dst, int c, unsigned n)
|
memset(void *dst, int c, unsigned n)
|
||||||
{
|
{
|
||||||
|
@ -69,3 +57,21 @@ strncmp(const char *p, const char *q, unsigned n)
|
||||||
else
|
else
|
||||||
return (int) ((unsigned char) *p - (unsigned char) *q);
|
return (int) ((unsigned char) *p - (unsigned char) *q);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Memcpy is deprecated and should NOT be called.
|
||||||
|
// Use memmove instead, which has defined semantics
|
||||||
|
// when the two memory ranges overlap.
|
||||||
|
// Memcpy is here only because gcc compiles some
|
||||||
|
// structure assignments into calls to memcpy.
|
||||||
|
void *
|
||||||
|
memcpy(void *dst, void *src, unsigned n)
|
||||||
|
{
|
||||||
|
char *d = (char *) dst;
|
||||||
|
char *s = (char *) src;
|
||||||
|
|
||||||
|
while(n-- > 0)
|
||||||
|
*d++ = *s++;
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
13
syscall.c
13
syscall.c
|
@ -30,7 +30,7 @@ fetchint(struct proc *p, unsigned addr, int *ip)
|
||||||
|
|
||||||
if(addr > p->sz - 4)
|
if(addr > p->sz - 4)
|
||||||
return -1;
|
return -1;
|
||||||
memcpy(ip, p->mem + addr, 4);
|
memmove(ip, p->mem + addr, 4);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ putint(struct proc *p, unsigned addr, int ip)
|
||||||
{
|
{
|
||||||
if(addr > p->sz - 4)
|
if(addr > p->sz - 4)
|
||||||
return -1;
|
return -1;
|
||||||
memcpy(p->mem + addr, &ip, 4);
|
memmove(p->mem + addr, &ip, 4);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,13 +150,10 @@ sys_fork(void)
|
||||||
{
|
{
|
||||||
struct proc *np;
|
struct proc *np;
|
||||||
|
|
||||||
np = newproc();
|
if((np = copyproc(curproc[cpu()])) == 0)
|
||||||
if(np){
|
|
||||||
np->state = RUNNABLE;
|
|
||||||
return np->pid;
|
|
||||||
} else {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
np->state = RUNNABLE;
|
||||||
|
return np->pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
Loading…
Reference in a new issue