๐ฉ๐ปโ๐ป GITHUB ๋ ํฌ์งํ ๋ฆฌ
๐ฉ๐ปโ๐ป GITHUB Extend File Descriptor ์ด์
๐ก ์ฌ๋ฌ๋ถ์ ํํ ์ค๊ฐ ๋ฆฌ๋ ์ค์
stdin
,stdout
๋ฅผ ๋ซ๋ ๊ธฐ๋ฅ๊ณผdup2
์์คํ ์ฝ์ ์ง์ํ๋๋ก ๋ง๋ค์ด๋ณด์ธ์.
ํ์ฌ ๊ตฌํ๋ ํํ ์ค์์๋ stdin
๊ณผ stdout
ํ์ผ ๋์คํฌ๋ฆฝํฐ๋ฅผ ๋ซ๋ ๊ฒ์ด ๊ธ์ง๋์ด์๋ค. ์ด๋ฒ Extend File Descriptor ๊ณผ์ ์์ ์ฌ๋ฌ๋ถ์ ํํ ์ค๊ฐ ๋ฆฌ๋
์ค์ฒ๋ผ ์ ์ ๊ฐ stdin
๊ณผ stdout
์ ๋ซ์ ์ ์๋๋ก ํด์ผํ๋ค. ์ฆ, ํ๋ก์ธ์ค๊ฐ stdin
๋ฅผ ๋ซ์ผ๋ฉด ์ ๋ input์ ์ฝ์ ์ ์๊ณ , stdout
์ ๋ซ์ผ๋ฉด ์ด๋ค ๊ฒ๋ ์ถ๋ ฅํ ์ ์๊ฒ ๋ง๋ค์ด์ผ ํ๋ค.
๋ํ dup2()
๋ผ๋ ์์คํ
์ฝ์ ๊ตฌํํด์ผ ํ๋๋ฐ, dup2()
์์คํ
์ฝ์ ์ธ์๋ก ๋ฐ์ oldfd ํ์ผ ๋์คํฌ๋ฆฝํฐ์ ๋ณต์ฌ๋ณธ์ ์์ฑํ๊ณ , ์ด ๋ณต์ฌ๋ณธ์ ํ์ผ๋์คํฌ๋ฆฝํฐ ๊ฐ์ ์ธ์๋ก ๋ฐ์ newfd ๊ฐ์ด ๋๊ฒ ํ๋ค. dup2()
์์คํ
์ฝ์ด ํ์ผ ๋์คํฌ๋ฆฝํฐ๋ฅผ ๋ณต์ฌํด์ ์ ํ์ผ ๋์คํฌ๋ฆฝํฐ๋ฅผ ์์ฑํ๋ ๋ฐ ์ฑ๊ณตํ๋ค๋ฉด newfd๋ฅผ ๋ฆฌํดํ๋ค. ๋ง์ฝ newfd ๊ฐ์ด ์ด์ ์ ์ด๋ฏธ ์ด๋ ค์์๋ค๋ฉด, newfd๋ ์ฌ์ฌ์ฉ๋๊ธฐ ์ ์ ์กฐ์ฉํ ๋ซํ๋ค.
์๋ ์ฌํญ๋ค์ ๊ธฐ์ตํด์ผํ๋ค.
dup2()
์ฝ์ ์คํจํ์ฌ 1์ ๋ฐํํ๊ณ , newfd ๋ ๋ซํ์ง ์๋๋ค.dup2()
๊ฐ ํ ์ผ์ ๋ฐ๋ก ์๊ณ (*์ด๋ฏธ ๊ฐ์ผ๋ฏ๋ก) newfd ๊ฐ์ ๋ฆฌํดํ๋ค.์ด ์์คํ ์ฝ๋ก๋ถํฐ ์ฑ๊ณต์ ์ผ๋ก ๊ฐ์ ๋ฐํ๋ฐ์ ํ์, oldfd์ newfd๋ ํธํํด์ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค. ์ด ๋์ ์๋ก ๋ค๋ฅธ ํ์ผ ๋์คํฌ๋ฆฝํฐ์ด๊ธดํ์ง๋ง, ๋๊ฐ์ ์ด๋ฆฐ ํ์ผ ๋์คํฌ๋ฆฝํฐ๋ฅผ ์๋ฏธํ๊ธฐ ๋๋ฌธ์ ๊ฐ์ file offset๊ณผ status flags ๋ฅผ ๊ณต์ ํ๊ณ ์๋ค. ์๋ฅผ ๋ค์ด ๋ง์ฝ์ ๋ค๋ฅธ ๋์คํฌ๋ฆฝํฐ๊ฐ seek ์ ์ฌ์ฉํด์ file offset์ด ์์ ๋์๋ค๋ฉด, ๋ค๋ฅธ ์คํฌ๋ฆฝํฐ์์๋ ์ด ๊ฐ์ ๋๊ฐ์ด ์์ ๋๋ค.
userprog/Make.var
๋ฅผ ์ด์ด๋ณด๋ฉด, ์๋ ์ธ ์ค์ด ์ฃผ์์ฒ๋ฆฌ ๋์ด์๋๋ฐ, ์ฃผ์์ ํด์ ํด์ฃผ๋ฉด dup2
TC ๋๊ฐ๊ฐ ์ถ๊ฐ๋๋ค.
#define STDIN 1
#define STDOUT 2
#define STDERR 3
#include <stdbool.h>
struct inode;
/* An open file. */
struct file {
struct inode *inode; /* File's inode. */
off_t pos; /* Current position. */
bool deny_write; /* Has file_deny_write() been called? */
/** Project 2-Extend File Descriptor */
int dup_count;
};
struct file *
file_open (struct inode *inode) {
struct file *file = calloc (1, sizeof *file);
if (inode != NULL && file != NULL) {
file->inode = inode;
file->pos = 0;
file->deny_write = false;
/** Project 2-Extend File Descriptor */
file->dup_count = 0;
return file;
} else {
inode_close (inode);
free (file);
return NULL;
}
}
t->fdt[0] = STDIN;
t->fdt[1] = STDOUT;
t->fdt[2] = STDERR;
void
syscall_init (void) {
write_msr(MSR_STAR, ((uint64_t)SEL_UCSEG - 0x10) << 48 |
((uint64_t)SEL_KCSEG) << 32);
write_msr(MSR_LSTAR, (uint64_t) syscall_entry);
/* The interrupt service rountine should not serve any interrupts
* until the syscall_entry swaps the userland stack to the kernel
* mode stack. Therefore, we masked the FLAG_FL. */
write_msr(MSR_SYSCALL_MASK,
FLAG_IF | FLAG_TF | FLAG_DF | FLAG_IOPL | FLAG_AC | FLAG_NT);
/** project2-System Call */
// read & write ์ฉ lock ์ด๊ธฐํ
lock_init(&filesys_lock);
}
/* The main system call interface */
void
syscall_handler (struct intr_frame *f UNUSED) {
// TODO: Your implementation goes here.
/** project2-System Call */
int sys_number = f->R.rax;
// Argument ์์
// %rdi %rsi %rdx %r10 %r8 %r9
switch (sys_number) {
case SYS_HALT:
halt();
break;
case SYS_EXIT:
exit(f->R.rdi);
break;
case SYS_FORK:
f->R.rax = fork(f->R.rdi);
break;
case SYS_EXEC:
f->R.rax = exec(f->R.rdi);
break;
case SYS_WAIT:
f->R.rax = process_wait(f->R.rdi);
break;
case SYS_CREATE:
f->R.rax = create(f->R.rdi, f->R.rsi);
break;
case SYS_REMOVE:
f->R.rax = remove(f->R.rdi);
break;
case SYS_OPEN:
f->R.rax = open(f->R.rdi);
break;
case SYS_FILESIZE:
f->R.rax = filesize(f->R.rdi);
break;
case SYS_READ:
f->R.rax = read(f->R.rdi, f->R.rsi, f->R.rdx);
break;
case SYS_WRITE:
f->R.rax = write(f->R.rdi, f->R.rsi, f->R.rdx);
break;
case SYS_SEEK:
seek(f->R.rdi, f->R.rsi);
break;
case SYS_TELL:
f->R.rax = tell(f->R.rdi);
break;
case SYS_CLOSE:
close(f->R.rdi);
break;
case SYS_DUP2:
f->R.rax = dup2(f->R.rdi, f->R.rsi);
break;
default:
exit(-1);
}
}
/** Project 2-Extend File Descriptor */
int dup2(int oldfd, int newfd);
/** Project 2-Extend File Descriptor */
int dup2(int oldfd, int newfd) {
if (oldfd < 0 || newfd < 0)
return -1;
struct file *oldfile = process_get_file(oldfd);
if (oldfile == NULL)
return -1;
if (oldfd == newfd)
return newfd;
struct file *newfile = process_get_file(newfd);
if (oldfile == newfile)
return newfd;
close(newfd);
newfd = process_insert_file(newfd, oldfile);
return newfd;
}
/** Project 2-Extend File Descriptor */
process_insert_file(int fd, struct file *f);
/** Project 2-Extend File Descriptor */
process_insert_file(int fd, struct file *f) {
struct thread *curr = thread_current();
struct file **fdt = curr->fdt;
if (fd < 0 || fd >= FDCOUNT_LIMIT)
return -1;
if (f > STDERR)
f->dup_count++;
fdt[fd] = f;
return fd;
}
/** Project 2-Extend File Descriptor */
int
read(int fd, void *buffer, unsigned length)
{
struct thread *curr = thread_current();
check_address(buffer);
struct file *file = process_get_file(fd);
if (file == STDIN) {
int i = 0;
char c;
unsigned char *buf = buffer;
for (; i < length; i++) {
c = input_getc();
*buf++ = c;
if (c == '\0')
break;
}
return i;
}
if (file == NULL || file == STDOUT || file == STDERR) // ๋น ํ์ผ, stdout, stderr๋ฅผ ์ฝ์ผ๋ ค๊ณ ํ ๊ฒฝ์ฐ
return -1;
off_t bytes = -1;
lock_acquire(&filesys_lock);
bytes = file_read(file, buffer, length);
lock_release(&filesys_lock);
return bytes;
}
/** Project 2-Extend File Descriptor */
int
write(int fd, const void *buffer, unsigned length)
{
check_address(buffer);
struct thread *curr = thread_current();
off_t bytes = -1;
struct file *file = process_get_file(fd);
if (file == STDIN || file == NULL)
return -1;
if (file == STDOUT) {
putbuf(buffer, length);
return length;
}
if (file == STDERR) {
putbuf(buffer, length);
return length;
}
lock_acquire(&filesys_lock);
bytes = file_write(file, buffer, length);
lock_release(&filesys_lock);
return bytes;
}
/** Project 2-Extend File Descriptor */
void
close(int fd)
{
struct thread *curr = thread_current();
struct file *file = process_get_file(fd);
if (file == NULL)
return;
process_close_file(fd);
if (file == STDIN) {
file = 0;
return;
}
if (file == STDOUT) {
file = 0;
return;
}
if (file == STDERR) {
file = 0;
return;
}
if (file->dup_count == 0)
file_close(file);
else
file->dup_count--;
}
static void
__do_fork (void *aux) {
struct intr_frame if_;
struct thread *parent = (struct thread *) aux;
struct thread *current = thread_current ();
/* TODO: somehow pass the parent_if. (i.e. process_fork()'s if_) */
struct intr_frame *parent_if = &parent->parent_if;
bool succ = true;
/* 1. Read the cpu context to local stack. */
memcpy (&if_, parent_if, sizeof (struct intr_frame));
if_.R.rax = 0; // ์์ ํ๋ก์ธ์ค์ return๊ฐ (0)
/* 2. Duplicate PT */
current->pml4 = pml4_create();
if (current->pml4 == NULL)
goto error;
process_activate (current);
#ifdef VM
supplemental_page_table_init (¤t->spt);
if (!supplemental_page_table_copy (¤t->spt, &parent->spt))
goto error;
#else
if (!pml4_for_each (parent->pml4, duplicate_pte, parent))
goto error;
#endif
/* TODO: Your code goes here.
* TODO: Hint) To duplicate the file object, use `file_duplicate`
* TODO: in include/filesys/file.h. Note that parent should not return
* TODO: from the fork() until this function successfully duplicates
* TODO: the resources of parent.*/
if (parent->fd_idx >= FDCOUNT_LIMIT)
goto error;
/** Project 2-Extend File Descriptor */
struct file *file;
for (int fd = 0; fd < FDCOUNT_LIMIT; fd++) {
file = parent->fdt[fd];
if (file == NULL)
continue;
if (file > STDERR)
current->fdt[fd] = file_duplicate(file);
else
current->fdt[fd] = file;
}
current->fd_idx = parent->fd_idx;
sema_up(¤t->fork_sema);
process_init();
/* Finally, switch to the newly created process. */
if (succ)
do_iret(&if_); // ์ ์ ์ข
๋ฃ ์ ์์ Process๋ฅผ ์ํํ๋ฌ ๊ฐ
error:
sema_up(¤t->fork_sema); // ๋ณต์ ์ ์คํจํ์ผ๋ฏ๋ก ํ์ฌ fork์ฉ sema unblock
exit(TID_ERROR);
}