Support exit status for exit/wait
One test case for returning a exit status Passes usertests, but haven't used it to simplify tests
This commit is contained in:
parent
035cca95fe
commit
7e6c37e67e
|
@ -82,7 +82,7 @@ void printfinit(void);
|
||||||
|
|
||||||
// proc.c
|
// proc.c
|
||||||
int cpuid(void);
|
int cpuid(void);
|
||||||
void exit(void);
|
void exit(int);
|
||||||
int fork(void);
|
int fork(void);
|
||||||
int growproc(int);
|
int growproc(int);
|
||||||
pagetable_t proc_pagetable(struct proc *);
|
pagetable_t proc_pagetable(struct proc *);
|
||||||
|
@ -97,7 +97,7 @@ void sched(void);
|
||||||
void setproc(struct proc*);
|
void setproc(struct proc*);
|
||||||
void sleep(void*, struct spinlock*);
|
void sleep(void*, struct spinlock*);
|
||||||
void userinit(void);
|
void userinit(void);
|
||||||
int wait(void);
|
int wait(uint64);
|
||||||
void wakeup(void*);
|
void wakeup(void*);
|
||||||
void yield(void);
|
void yield(void);
|
||||||
int either_copyout(int user_dst, uint64 dst, void *src, uint64 len);
|
int either_copyout(int user_dst, uint64 dst, void *src, uint64 len);
|
||||||
|
|
|
@ -141,6 +141,7 @@ freeproc(struct proc *p)
|
||||||
p->name[0] = 0;
|
p->name[0] = 0;
|
||||||
p->chan = 0;
|
p->chan = 0;
|
||||||
p->killed = 0;
|
p->killed = 0;
|
||||||
|
p->xstate = 0;
|
||||||
p->state = UNUSED;
|
p->state = UNUSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,7 +320,7 @@ reparent(struct proc *p, struct proc *parent) {
|
||||||
// An exited process remains in the zombie state
|
// An exited process remains in the zombie state
|
||||||
// until its parent calls wait().
|
// until its parent calls wait().
|
||||||
void
|
void
|
||||||
exit(void)
|
exit(int status)
|
||||||
{
|
{
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
|
|
||||||
|
@ -350,6 +351,7 @@ exit(void)
|
||||||
// Parent might be sleeping in wait().
|
// Parent might be sleeping in wait().
|
||||||
wakeup1(p->parent);
|
wakeup1(p->parent);
|
||||||
|
|
||||||
|
p->xstate = status;
|
||||||
p->state = ZOMBIE;
|
p->state = ZOMBIE;
|
||||||
|
|
||||||
release(&p->parent->lock);
|
release(&p->parent->lock);
|
||||||
|
@ -362,7 +364,7 @@ exit(void)
|
||||||
// Wait for a child process to exit and return its pid.
|
// Wait for a child process to exit and return its pid.
|
||||||
// Return -1 if this process has no children.
|
// Return -1 if this process has no children.
|
||||||
int
|
int
|
||||||
wait(void)
|
wait(uint64 addr)
|
||||||
{
|
{
|
||||||
struct proc *np;
|
struct proc *np;
|
||||||
int havekids, pid;
|
int havekids, pid;
|
||||||
|
@ -387,6 +389,12 @@ wait(void)
|
||||||
if(np->state == ZOMBIE){
|
if(np->state == ZOMBIE){
|
||||||
// Found one.
|
// Found one.
|
||||||
pid = np->pid;
|
pid = np->pid;
|
||||||
|
if(addr != 0 && copyout(p->pagetable, addr, (char *)&np->xstate,
|
||||||
|
sizeof(np->xstate)) < 0) {
|
||||||
|
release(&np->lock);
|
||||||
|
release(&p->lock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
freeproc(np);
|
freeproc(np);
|
||||||
release(&np->lock);
|
release(&np->lock);
|
||||||
release(&p->lock);
|
release(&p->lock);
|
||||||
|
|
|
@ -91,6 +91,7 @@ struct proc {
|
||||||
struct proc *parent; // Parent process
|
struct proc *parent; // Parent process
|
||||||
void *chan; // If non-zero, sleeping on chan
|
void *chan; // If non-zero, sleeping on chan
|
||||||
int killed; // If non-zero, have been killed
|
int killed; // If non-zero, have been killed
|
||||||
|
int xstate; // Exit status to be returned to parent's wait
|
||||||
int pid; // Process ID
|
int pid; // Process ID
|
||||||
|
|
||||||
// these are private to the process, so p->lock need not be held.
|
// these are private to the process, so p->lock need not be held.
|
||||||
|
|
|
@ -246,6 +246,7 @@ create(char *path, short type, short major, short minor)
|
||||||
|
|
||||||
if((dp = nameiparent(path, name)) == 0)
|
if((dp = nameiparent(path, name)) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ilock(dp);
|
ilock(dp);
|
||||||
|
|
||||||
if((ip = dirlookup(dp, name, 0)) != 0){
|
if((ip = dirlookup(dp, name, 0)) != 0){
|
||||||
|
@ -289,8 +290,9 @@ sys_open(void)
|
||||||
int fd, omode;
|
int fd, omode;
|
||||||
struct file *f;
|
struct file *f;
|
||||||
struct inode *ip;
|
struct inode *ip;
|
||||||
|
int n;
|
||||||
|
|
||||||
if(argstr(0, path, MAXPATH) < 0 || argint(1, &omode) < 0)
|
if((n = argstr(0, path, MAXPATH)) < 0 || argint(1, &omode) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
begin_op();
|
begin_op();
|
||||||
|
|
|
@ -10,7 +10,10 @@
|
||||||
uint64
|
uint64
|
||||||
sys_exit(void)
|
sys_exit(void)
|
||||||
{
|
{
|
||||||
exit();
|
int n;
|
||||||
|
if(argint(0, &n) < 0)
|
||||||
|
return -1;
|
||||||
|
exit(n);
|
||||||
return 0; // not reached
|
return 0; // not reached
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +32,10 @@ sys_fork(void)
|
||||||
uint64
|
uint64
|
||||||
sys_wait(void)
|
sys_wait(void)
|
||||||
{
|
{
|
||||||
return wait();
|
uint64 p;
|
||||||
|
if(argaddr(0, &p) < 0)
|
||||||
|
return -1;
|
||||||
|
return wait(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64
|
uint64
|
||||||
|
|
|
@ -54,7 +54,7 @@ usertrap(void)
|
||||||
// system call
|
// system call
|
||||||
|
|
||||||
if(p->killed)
|
if(p->killed)
|
||||||
exit();
|
exit(-1);
|
||||||
|
|
||||||
// sepc points to the ecall instruction,
|
// sepc points to the ecall instruction,
|
||||||
// but we want to return to the next instruction.
|
// but we want to return to the next instruction.
|
||||||
|
@ -74,7 +74,7 @@ usertrap(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(p->killed)
|
if(p->killed)
|
||||||
exit();
|
exit(-1);
|
||||||
|
|
||||||
// give up the CPU if this is a timer interrupt.
|
// give up the CPU if this is a timer interrupt.
|
||||||
if(which_dev == 2)
|
if(which_dev == 2)
|
||||||
|
|
10
user/cat.c
10
user/cat.c
|
@ -12,12 +12,12 @@ cat(int fd)
|
||||||
while((n = read(fd, buf, sizeof(buf))) > 0) {
|
while((n = read(fd, buf, sizeof(buf))) > 0) {
|
||||||
if (write(1, buf, n) != n) {
|
if (write(1, buf, n) != n) {
|
||||||
printf("cat: write error\n");
|
printf("cat: write error\n");
|
||||||
exit();
|
exit(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(n < 0){
|
if(n < 0){
|
||||||
printf("cat: read error\n");
|
printf("cat: read error\n");
|
||||||
exit();
|
exit(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,16 +28,16 @@ main(int argc, char *argv[])
|
||||||
|
|
||||||
if(argc <= 1){
|
if(argc <= 1){
|
||||||
cat(0);
|
cat(0);
|
||||||
exit();
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 1; i < argc; i++){
|
for(i = 1; i < argc; i++){
|
||||||
if((fd = open(argv[i], 0)) < 0){
|
if((fd = open(argv[i], 0)) < 0){
|
||||||
printf("cat: cannot open %s\n", argv[i]);
|
printf("cat: cannot open %s\n", argv[i]);
|
||||||
exit();
|
exit(-1);
|
||||||
}
|
}
|
||||||
cat(fd);
|
cat(fd);
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
exit();
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,5 +15,5 @@ main(int argc, char *argv[])
|
||||||
write(1, "\n", 1);
|
write(1, "\n", 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exit();
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,24 +25,24 @@ forktest(void)
|
||||||
if(pid < 0)
|
if(pid < 0)
|
||||||
break;
|
break;
|
||||||
if(pid == 0)
|
if(pid == 0)
|
||||||
exit();
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(n == N){
|
if(n == N){
|
||||||
print("fork claimed to work N times!\n");
|
print("fork claimed to work N times!\n");
|
||||||
exit();
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(; n > 0; n--){
|
for(; n > 0; n--){
|
||||||
if(wait() < 0){
|
if(wait(0) < 0){
|
||||||
print("wait stopped early\n");
|
print("wait stopped early\n");
|
||||||
exit();
|
exit(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(wait() != -1){
|
if(wait(0) != -1){
|
||||||
print("wait got too many\n");
|
print("wait got too many\n");
|
||||||
exit();
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
print("fork test OK\n");
|
print("fork test OK\n");
|
||||||
|
@ -52,5 +52,5 @@ int
|
||||||
main(void)
|
main(void)
|
||||||
{
|
{
|
||||||
forktest();
|
forktest();
|
||||||
exit();
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,24 +41,24 @@ main(int argc, char *argv[])
|
||||||
|
|
||||||
if(argc <= 1){
|
if(argc <= 1){
|
||||||
fprintf(2, "usage: grep pattern [file ...]\n");
|
fprintf(2, "usage: grep pattern [file ...]\n");
|
||||||
exit();
|
exit(-1);
|
||||||
}
|
}
|
||||||
pattern = argv[1];
|
pattern = argv[1];
|
||||||
|
|
||||||
if(argc <= 2){
|
if(argc <= 2){
|
||||||
grep(pattern, 0);
|
grep(pattern, 0);
|
||||||
exit();
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 2; i < argc; i++){
|
for(i = 2; i < argc; i++){
|
||||||
if((fd = open(argv[i], 0)) < 0){
|
if((fd = open(argv[i], 0)) < 0){
|
||||||
printf("grep: cannot open %s\n", argv[i]);
|
printf("grep: cannot open %s\n", argv[i]);
|
||||||
exit();
|
exit(-1);
|
||||||
}
|
}
|
||||||
grep(pattern, fd);
|
grep(pattern, fd);
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
exit();
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Regexp matcher from Kernighan & Pike,
|
// Regexp matcher from Kernighan & Pike,
|
||||||
|
|
|
@ -24,14 +24,14 @@ main(void)
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if(pid < 0){
|
if(pid < 0){
|
||||||
printf("init: fork failed\n");
|
printf("init: fork failed\n");
|
||||||
exit();
|
exit(-1);
|
||||||
}
|
}
|
||||||
if(pid == 0){
|
if(pid == 0){
|
||||||
exec("sh", argv);
|
exec("sh", argv);
|
||||||
printf("init: exec sh failed\n");
|
printf("init: exec sh failed\n");
|
||||||
exit();
|
exit(-1);
|
||||||
}
|
}
|
||||||
while((wpid=wait()) >= 0 && wpid != pid){
|
while((wpid=wait(0)) >= 0 && wpid != pid){
|
||||||
//printf("zombie!\n");
|
//printf("zombie!\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,9 @@ main(int argc, char **argv)
|
||||||
|
|
||||||
if(argc < 2){
|
if(argc < 2){
|
||||||
fprintf(2, "usage: kill pid...\n");
|
fprintf(2, "usage: kill pid...\n");
|
||||||
exit();
|
exit(-1);
|
||||||
}
|
}
|
||||||
for(i=1; i<argc; i++)
|
for(i=1; i<argc; i++)
|
||||||
kill(atoi(argv[i]));
|
kill(atoi(argv[i]));
|
||||||
exit();
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,9 @@ main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
if(argc != 3){
|
if(argc != 3){
|
||||||
fprintf(2, "Usage: ln old new\n");
|
fprintf(2, "Usage: ln old new\n");
|
||||||
exit();
|
exit(-1);
|
||||||
}
|
}
|
||||||
if(link(argv[1], argv[2]) < 0)
|
if(link(argv[1], argv[2]) < 0)
|
||||||
fprintf(2, "link %s %s: failed\n", argv[1], argv[2]);
|
fprintf(2, "link %s %s: failed\n", argv[1], argv[2]);
|
||||||
exit();
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,9 +77,9 @@ main(int argc, char *argv[])
|
||||||
|
|
||||||
if(argc < 2){
|
if(argc < 2){
|
||||||
ls(".");
|
ls(".");
|
||||||
exit();
|
exit(0);
|
||||||
}
|
}
|
||||||
for(i=1; i<argc; i++)
|
for(i=1; i<argc; i++)
|
||||||
ls(argv[i]);
|
ls(argv[i]);
|
||||||
exit();
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ main(int argc, char *argv[])
|
||||||
|
|
||||||
if(argc < 2){
|
if(argc < 2){
|
||||||
fprintf(2, "Usage: mkdir files...\n");
|
fprintf(2, "Usage: mkdir files...\n");
|
||||||
exit();
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 1; i < argc; i++){
|
for(i = 1; i < argc; i++){
|
||||||
|
@ -19,5 +19,5 @@ main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exit();
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ main(int argc, char *argv[])
|
||||||
|
|
||||||
if(argc < 2){
|
if(argc < 2){
|
||||||
fprintf(2, "Usage: rm files...\n");
|
fprintf(2, "Usage: rm files...\n");
|
||||||
exit();
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 1; i < argc; i++){
|
for(i = 1; i < argc; i++){
|
||||||
|
@ -19,5 +19,5 @@ main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exit();
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
20
user/sh.c
20
user/sh.c
|
@ -65,7 +65,7 @@ runcmd(struct cmd *cmd)
|
||||||
struct redircmd *rcmd;
|
struct redircmd *rcmd;
|
||||||
|
|
||||||
if(cmd == 0)
|
if(cmd == 0)
|
||||||
exit();
|
exit(-1);
|
||||||
|
|
||||||
switch(cmd->type){
|
switch(cmd->type){
|
||||||
default:
|
default:
|
||||||
|
@ -74,7 +74,7 @@ runcmd(struct cmd *cmd)
|
||||||
case EXEC:
|
case EXEC:
|
||||||
ecmd = (struct execcmd*)cmd;
|
ecmd = (struct execcmd*)cmd;
|
||||||
if(ecmd->argv[0] == 0)
|
if(ecmd->argv[0] == 0)
|
||||||
exit();
|
exit(-1);
|
||||||
exec(ecmd->argv[0], ecmd->argv);
|
exec(ecmd->argv[0], ecmd->argv);
|
||||||
fprintf(2, "exec %s failed\n", ecmd->argv[0]);
|
fprintf(2, "exec %s failed\n", ecmd->argv[0]);
|
||||||
break;
|
break;
|
||||||
|
@ -84,7 +84,7 @@ runcmd(struct cmd *cmd)
|
||||||
close(rcmd->fd);
|
close(rcmd->fd);
|
||||||
if(open(rcmd->file, rcmd->mode) < 0){
|
if(open(rcmd->file, rcmd->mode) < 0){
|
||||||
fprintf(2, "open %s failed\n", rcmd->file);
|
fprintf(2, "open %s failed\n", rcmd->file);
|
||||||
exit();
|
exit(-1);
|
||||||
}
|
}
|
||||||
runcmd(rcmd->cmd);
|
runcmd(rcmd->cmd);
|
||||||
break;
|
break;
|
||||||
|
@ -93,7 +93,7 @@ runcmd(struct cmd *cmd)
|
||||||
lcmd = (struct listcmd*)cmd;
|
lcmd = (struct listcmd*)cmd;
|
||||||
if(fork1() == 0)
|
if(fork1() == 0)
|
||||||
runcmd(lcmd->left);
|
runcmd(lcmd->left);
|
||||||
wait();
|
wait(0);
|
||||||
runcmd(lcmd->right);
|
runcmd(lcmd->right);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -117,8 +117,8 @@ runcmd(struct cmd *cmd)
|
||||||
}
|
}
|
||||||
close(p[0]);
|
close(p[0]);
|
||||||
close(p[1]);
|
close(p[1]);
|
||||||
wait();
|
wait(0);
|
||||||
wait();
|
wait(0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BACK:
|
case BACK:
|
||||||
|
@ -127,7 +127,7 @@ runcmd(struct cmd *cmd)
|
||||||
runcmd(bcmd->cmd);
|
runcmd(bcmd->cmd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
exit();
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -166,16 +166,16 @@ main(void)
|
||||||
}
|
}
|
||||||
if(fork1() == 0)
|
if(fork1() == 0)
|
||||||
runcmd(parsecmd(buf));
|
runcmd(parsecmd(buf));
|
||||||
wait();
|
wait(0);
|
||||||
}
|
}
|
||||||
exit();
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
panic(char *s)
|
panic(char *s)
|
||||||
{
|
{
|
||||||
fprintf(2, "%s\n", s);
|
fprintf(2, "%s\n", s);
|
||||||
exit();
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
@ -43,7 +43,7 @@ main(int argc, char *argv[])
|
||||||
read(fd, data, sizeof(data));
|
read(fd, data, sizeof(data));
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
wait();
|
wait(0);
|
||||||
|
|
||||||
exit();
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@ struct rtcdate;
|
||||||
|
|
||||||
// system calls
|
// system calls
|
||||||
int fork(void);
|
int fork(void);
|
||||||
int exit(void) __attribute__((noreturn));
|
int exit(int) __attribute__((noreturn));
|
||||||
int wait(void);
|
int wait(int*);
|
||||||
int pipe(int*);
|
int pipe(int*);
|
||||||
int write(int, const void*, int);
|
int write(int, const void*, int);
|
||||||
int read(int, void*, int);
|
int read(int, void*, int);
|
||||||
|
|
483
user/usertests.c
483
user/usertests.c
File diff suppressed because it is too large
Load diff
|
@ -27,7 +27,7 @@ wc(int fd, char *name)
|
||||||
}
|
}
|
||||||
if(n < 0){
|
if(n < 0){
|
||||||
printf("wc: read error\n");
|
printf("wc: read error\n");
|
||||||
exit();
|
exit(-1);
|
||||||
}
|
}
|
||||||
printf("%d %d %d %s\n", l, w, c, name);
|
printf("%d %d %d %s\n", l, w, c, name);
|
||||||
}
|
}
|
||||||
|
@ -39,16 +39,16 @@ main(int argc, char *argv[])
|
||||||
|
|
||||||
if(argc <= 1){
|
if(argc <= 1){
|
||||||
wc(0, "");
|
wc(0, "");
|
||||||
exit();
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 1; i < argc; i++){
|
for(i = 1; i < argc; i++){
|
||||||
if((fd = open(argv[i], 0)) < 0){
|
if((fd = open(argv[i], 0)) < 0){
|
||||||
printf("wc: cannot open %s\n", argv[i]);
|
printf("wc: cannot open %s\n", argv[i]);
|
||||||
exit();
|
exit(-1);
|
||||||
}
|
}
|
||||||
wc(fd, argv[i]);
|
wc(fd, argv[i]);
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
exit();
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,5 +10,5 @@ main(void)
|
||||||
{
|
{
|
||||||
if(fork() > 0)
|
if(fork() > 0)
|
||||||
sleep(5); // Let child exit before parent.
|
sleep(5); // Let child exit before parent.
|
||||||
exit();
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue