diff --git a/pintos/include/threads/thread.h b/pintos/include/threads/thread.h index f3c4c47..dc30132 100644 --- a/pintos/include/threads/thread.h +++ b/pintos/include/threads/thread.h @@ -29,7 +29,6 @@ typedef int tid_t; #define PRI_MIN 0 /* Lowest priority. */ #define PRI_DEFAULT 31 /* Default priority. */ #define PRI_MAX 63 /* Highest priority. */ -#define FD_TABLE_SIZE 128 /* A kernel thread or user process. * @@ -107,12 +106,14 @@ struct thread uint64_t *pml4; /* Page map level 4 */ int exit_status; - struct file **fd_table; + + struct fdt_entry **fdt_entry; struct list child_list; // struct thread *parent; struct child *child_info; struct file *executable; + int FD_TABLE_SIZE; #endif #ifdef VM @@ -125,11 +126,21 @@ struct thread unsigned magic; /* Detects stack overflow. */ }; -struct child { +enum fd_type { STDIN, STDOUT, FILE, DIR }; //DIR은 과제 4 + +struct fdt_entry { + enum fd_type type; + struct file *fdt; // type FILE인 경우 가져다 쓰기 + int ref_cnt; + /* dir인 경우 추가??(과제4) */ +}; + +struct child { struct list_elem child_elem; tid_t child_tid; int exit_status; bool waited; + bool p_alive; struct semaphore wait_sema; }; diff --git a/pintos/tests/userprog/dup2/Make.tests b/pintos/tests/userprog/dup2/Make.tests index d7aec04..f23dc6c 100644 --- a/pintos/tests/userprog/dup2/Make.tests +++ b/pintos/tests/userprog/dup2/Make.tests @@ -1,6 +1,6 @@ # -*- makefile -*- -tests/userprog/dup2_TESTS = $(addprefix tests/userprog/dup2/dup2-,complex simple) +tests/userprog/dup2_TESTS = $(addprefix tests/userprog/dup2/dup2-,complex simple fork-link) tests/userprog/dup2_PROGS = $(tests/userprog/dup2_TESTS) @@ -8,6 +8,9 @@ tests/userprog/dup2/dup2-complex_SRC = tests/userprog/dup2/dup2-complex.c \ tests/lib.c tests/userprog/boundary.c tests/userprog/dup2/dup2-simple_SRC = tests/userprog/dup2/dup2-simple.c \ tests/lib.c tests/userprog/boundary.c +tests/userprog/dup2/dup2-fork-link_SRC = tests/userprog/dup2/dup2-fork-link.c \ +tests/lib.c tests/userprog/dup2/dup2-complex_PUTFILES += tests/userprog/dup2/sample.txt tests/userprog/dup2/dup2-simple_PUTFILES += tests/userprog/dup2/sample.txt +tests/userprog/dup2/dup2-fork-link_PUTFILES += tests/userprog/dup2/sample.txt diff --git a/pintos/tests/userprog/dup2/dup2-fork-link.c b/pintos/tests/userprog/dup2/dup2-fork-link.c new file mode 100644 index 0000000..fe1e39f --- /dev/null +++ b/pintos/tests/userprog/dup2/dup2-fork-link.c @@ -0,0 +1,40 @@ +/* Confirm that dup2-linked descriptors stay linked after fork. The child + sees the primed offset, advances it once, and the parent observes the + updated position as soon as the child exits. */ + +#include +#include +#include "tests/lib.h" + +int +main (int argc UNUSED, char *argv[] UNUSED) { + test_name = "dup2-fork-link"; + + char buf[16]; + int fd = open ("sample.txt"); + CHECK (fd > 1, "open \"sample.txt\""); + CHECK (read (fd, buf, 5) == 5, "set offset to 5"); + int dup_fd = dup2 (fd, 30); + CHECK (dup_fd == 30, "dup2 to 30"); + pid_t pid = fork ("dup-child"); + if (pid < 0) + fail ("fork failed"); + + if (pid == 0) { + int off_fd = tell (fd); + int off_dup = tell (dup_fd); + if (off_fd != 5 || off_dup != 5) + fail ("child inherited offsets fd=%d dup=%d (expected 5)", off_fd, off_dup); + + CHECK (read (dup_fd, buf, 7) == 7, "child read dup fd"); + off_fd = tell (fd); + off_dup = tell (dup_fd); + if (off_fd != 12 || off_dup != 12) + fail ("child offsets diverged after read (fd=%d dup=%d)", off_fd, off_dup); + exit (0); + } + + if (pid > 0) + CHECK (wait (pid) == 0, "wait child"); + return 0; +} diff --git a/pintos/tests/userprog/dup2/dup2-fork-link.ck b/pintos/tests/userprog/dup2/dup2-fork-link.ck new file mode 100644 index 0000000..62dfada --- /dev/null +++ b/pintos/tests/userprog/dup2/dup2-fork-link.ck @@ -0,0 +1,21 @@ +# -*- perl -*- +use strict; +use warnings; +use tests::tests; +check_expected (IGNORE_EXIT_CODES => 1, [ +<<'EOF', +(dup2-fork-link) open "sample.txt" +(dup2-fork-link) set offset to 5 +(dup2-fork-link) dup2 to 30 +(dup2-fork-link) child read dup fd +(dup2-fork-link) wait child +EOF +,<<'EOF', +(dup2-fork-link) open "sample.txt" +(dup2-fork-link) set offset to 5 +(dup2-fork-link) dup2 to 30 +(dup2-fork-link) wait child +(dup2-fork-link) child read dup fd +EOF +]); +pass; diff --git a/pintos/userprog/.test_config b/pintos/userprog/.test_config index 2effd1f..6524047 100644 --- a/pintos/userprog/.test_config +++ b/pintos/userprog/.test_config @@ -114,7 +114,8 @@ priority-donate-chain | --fs-disk=10 | -q -threads-tests -f run | 'priority-don [extra] dup2-simple | --fs-disk=10 -p tests/userprog/dup2/dup2-simple:dup2-simple -p ../../tests/userprog/dup2/sample.txt:sample.txt | -q -f run | 'dup2-simple' | tests/userprog/dup2 dup2-complex | --fs-disk=10 -p tests/userprog/dup2/dup2-complex:dup2-complex -p ../../tests/userprog/dup2/sample.txt:sample.txt | -q -f run | 'dup2-complex' | tests/userprog/dup2 +dup2-fork-link | --fs-disk=10 -p tests/userprog/dup2/dup2-fork-link:dup2-fork-link -p ../../tests/userprog/dup2/sample.txt:sample.txt | -q -f run | 'dup2-fork-link' | tests/userprog/dup2 # Total testcases: 97 -# Generated on 2025-07-29 \ No newline at end of file +# Generated on 2025-07-29 diff --git a/pintos/userprog/fdt.c b/pintos/userprog/fdt.c new file mode 100644 index 0000000..6e5b311 --- /dev/null +++ b/pintos/userprog/fdt.c @@ -0,0 +1,147 @@ +#include "userprog/fdt.h" +#include "filesys/file.h" +#include "threads/synch.h" +#include + +/* file_lock is defined in syscall.c. */ +extern struct lock file_lock; + +/* file 받아서 fd 자리에 fdt_entry 만들기 */ +bool +open_fdt_entry(struct fdt_entry **fdt_entry, int fd, struct file *file){ + + if(fdt_entry == NULL || file == NULL) + return false; + + struct fdt_entry *entry = calloc(1, sizeof(struct fdt_entry)); + if(entry == NULL) + return false; + + fdt_entry[fd] = entry; + fdt_entry[fd]->fdt = file; + fdt_entry[fd]->ref_cnt = 1; + fdt_entry[fd]->type = FILE; + + return true; +} + + +/* ref_cnt 기준으로 파일 닫기 */ +void +close_fdt_entry(struct fdt_entry **table, int fd){ + struct fdt_entry *ent = table[fd]; + if (ent == NULL) + return; + + table[fd] = NULL; + ent->ref_cnt--; + if (ent->type == FILE && ent->fdt != NULL) { + if (ent->ref_cnt == 0) { + lock_acquire(&file_lock); + file_close(ent->fdt); + lock_release(&file_lock); + } + } + if (ent->ref_cnt == 0) + free(ent); +} + +/* 2^n 크기로 확장, 새 슬롯을 0으로 채우기 */ +bool +increase_fdt_size(struct thread *t, int fd) { + int old_size = t->FD_TABLE_SIZE; + if (fd < old_size) + return true; + + /* 2^n 값 구하기 */ + int need = fd + 1; + int new_size = old_size ? old_size : 1; + while (new_size < need) + new_size <<= 1; + + struct fdt_entry **old_entry = t->fdt_entry; + if (old_entry == NULL) + return false; + + /* 새 버퍼를 0으로 초기화, 기존 내용을 복사 */ + struct fdt_entry **new_entry = calloc(new_size, sizeof(struct fdt_entry*)); + if (new_entry == NULL) + return false; + memcpy(new_entry, old_entry, old_size * sizeof(struct fdt_entry*)); + + t->fdt_entry = new_entry; + t->FD_TABLE_SIZE = new_size; + + free(old_entry); + + return true; +} + +/* parent 엔트리 깊은 복사 해서 child에 연결 */ +/* FILE일 경우만 dup, STDIN/STDOUT 이면 그냥 만들기*/ +bool +dup_fdt_entry(struct fdt_entry *parent_ent, struct fdt_entry **child_ent){ + if (parent_ent == NULL || child_ent == NULL) + return false; + + struct fdt_entry *entry = calloc(1, sizeof(struct fdt_entry)); + if(entry == NULL) + return false; + + entry->type = parent_ent->type; + entry->ref_cnt = parent_ent->ref_cnt; + + if(parent_ent->type == FILE){ + lock_acquire(&file_lock); + struct file *dup = file_duplicate(parent_ent->fdt); + lock_release(&file_lock); + if (dup == NULL){ + free(entry); + return false; + } + entry->fdt = dup; + } + + *child_ent = entry; + return true; +} + +/* 부모 fdt_entry배열 fork*/ +bool +fork_fdt(struct thread *parent, struct thread *child){ + for (int i = 0; i < parent->FD_TABLE_SIZE; i++) { + struct fdt_entry *p_entry = parent->fdt_entry[i]; + if (p_entry == NULL) + continue; + + /* 부모에서 같은 엔트리를 공유한 fd라면 자식도 동일 포인터 공유 */ + bool dup_find = false; + if(p_entry->ref_cnt >= 2){ + for (int j = 0; j < i; j++) { + if (parent->fdt_entry[j] == p_entry) { + child->fdt_entry[i] = child->fdt_entry[j]; + dup_find = true; + break; + } + } + } + /* dup 연결 했으면 만들기 생략 */ + if (dup_find) + continue; + + if (!dup_fdt_entry(p_entry, &child->fdt_entry[i])) + return false; + } + + return true; +} + +/* fd 0,1은 건너뛰고 비어 있는 가장 낮은 fd 반환. 없으면 -1. */ +int +find_empty_fd(struct thread *t){ + for (int i = 2; i < t->FD_TABLE_SIZE; i++){ + if (t->fdt_entry[i] == NULL) + return i; + } + return -1; +} \ No newline at end of file diff --git a/pintos/userprog/fdt.h b/pintos/userprog/fdt.h new file mode 100644 index 0000000..89bdc83 --- /dev/null +++ b/pintos/userprog/fdt.h @@ -0,0 +1,13 @@ +#ifndef USERPROG_FDT_H +#define USERPROG_FDT_H + +#include "threads/thread.h" + +bool open_fdt_entry(struct fdt_entry **fdt_entry, int fd, struct file *file); +void close_fdt_entry(struct fdt_entry **table, int fd); +bool increase_fdt_size(struct thread *t, int fd); +bool dup_fdt_entry(struct fdt_entry *parent_ent, struct fdt_entry **child_ent); +bool fork_fdt(struct thread *parent, struct thread *child); +int find_empty_fd(struct thread *t); + +#endif /* USERPROG_FDT_H */ diff --git a/pintos/userprog/process.c b/pintos/userprog/process.c index 12cf014..c2d66b8 100644 --- a/pintos/userprog/process.c +++ b/pintos/userprog/process.c @@ -23,25 +23,61 @@ #endif #include "include/threads/synch.h" +#include "userprog/fdt.h" #include static void process_cleanup (void); +static void set_initd_stdio (struct thread *t); static bool load (const char **argv, int argc, struct intr_frame *if_); static void initd (void *aux); static void __do_fork (void *); +void child_init(struct thread *parent, struct child *c); extern struct lock file_lock; +/* 자식 구조체 세팅 */ +void child_init(struct thread *parent, struct child *c){ + c->child_tid = -1; //일단 안쓰는 -1로 + c->exit_status = -1; + c->waited = false; + c->p_alive = true; + sema_init(&c->wait_sema, 0); + list_push_back(&parent->child_list, &c->child_elem); +} + /* General process initializer for initd and other process. */ -static void +static bool process_init (void) { struct thread *curr = thread_current (); /* 프로세스에 필요한 구조체 여기서 만들어야함.*/ - // initialize the fd_table - curr->fd_table = calloc(FD_TABLE_SIZE, sizeof(struct file *)); - if (curr->fd_table == NULL) { - PANIC("Failed to allocate file descriptor table"); + + /* fdt entry 포인터 배열 할당 */ + curr->fdt_entry = calloc(curr->FD_TABLE_SIZE, sizeof(struct fdt_entry*)); + if (curr->fdt_entry == NULL) + return false; + return true; +} + +/* initd 처음 STDIN/STDOUT 세팅, (이후 fork는 부모 따라가도록) */ +static void +set_initd_stdio (struct thread *t) { + + struct fdt_entry *f0 = calloc(1, sizeof(struct fdt_entry)); + if (f0 == NULL) + PANIC("Failed to initd STDIN setting"); + + struct fdt_entry *f1 = calloc(1, sizeof(struct fdt_entry)); + if (f1 == NULL) { + free(f0); + PANIC("Failed to initd STDOUT setting"); } + t->fdt_entry[0] = f0; + t->fdt_entry[0]->type = STDIN; + t->fdt_entry[0]->ref_cnt = 1; + + t->fdt_entry[1] = f1; + t->fdt_entry[1]->type = STDOUT; + t->fdt_entry[1]->ref_cnt = 1; } /* Starts the first userland program, called "initd", loaded from FILE_NAME. @@ -91,22 +127,19 @@ process_create_initd (const char *file_name) { initd_arg->fn_copy = fn_copy; initd_arg->c = c; - sema_init(&c->wait_sema, 0); // 먼저 sema_init 해야함!! + child_init(parent, c); /* Create a new thread to execute FILE_NAME. */ tid = thread_create (file_name, PRI_DEFAULT, initd, initd_arg); if (tid == TID_ERROR){ + list_remove(&c->child_elem); palloc_free_page (fn_copy); free(c); free(initd_arg); return TID_ERROR; } - // 자식(initd) 구조체 필드 채우고 부모(main) list에 등록 c->child_tid = tid; - c->exit_status = -1; - c->waited = false; - list_push_back(&parent->child_list, &c->child_elem); return tid; } @@ -118,16 +151,21 @@ initd (void *aux) { supplemental_page_table_init (&thread_current ()->spt); #endif - /* initd 스레드의 child 구조체 생성 */ + struct thread *curr = thread_current(); + struct initd_arg *i = aux; struct child *child = i->c; char *file_name = i->fn_copy; free(i); // aux로 전달된 구조체 free - //exit시 child_info 접근(sema_up, exit_status) 하기 때문에 여기서 해야함 - thread_current()->child_info = child; + //exit시 child_info 접근하기 때문에 여기서 해야함 + curr->child_info = child; + curr->FD_TABLE_SIZE = 128; // 초기(initd) fdt size 128 세팅 + + process_init(); + + set_initd_stdio(curr); - process_init (); if (process_exec (file_name) < 0) PANIC("Fail to launch initd\n"); NOT_REACHED (); @@ -158,23 +196,20 @@ process_fork (const char *name, struct intr_frame *if_) { fork->f = if_; fork->t = thread_current(); fork->c = c; + sema_init(&fork->forksema, 0); //__do_fork 결과 확인용 - sema_init(&c->wait_sema, 0); // create전에 init 해야함 + + child_init(thread_current(), c); /* Clone current thread to new thread.*/ tid_t tid = thread_create (name, PRI_DEFAULT, __do_fork, fork); if(tid == TID_ERROR){ - /* 자원 해제 */ free(fork); free(c); return TID_ERROR; } - // 자식 구조체 필드 채우고 부모 list에 등록 c->child_tid = tid; - c->exit_status = -1; - c->waited = false; - list_push_back(&thread_current()->child_list, &c->child_elem); // __do_fork 결과 확인용 sema_down(&fork->forksema); @@ -184,7 +219,10 @@ process_fork (const char *name, struct intr_frame *if_) { return tid; } else{ + // 실패 시 free하고 반환 free(fork); + // list_remove(&c->child_elem); + // free(c); return TID_ERROR; } } @@ -251,7 +289,8 @@ __do_fork (void *aux) { struct thread *parent = (struct thread *) args->t; struct thread *current = thread_current (); - // current->parent = parent; + /* 자식 정보 채우기 */ + current->FD_TABLE_SIZE = parent->FD_TABLE_SIZE; current->child_info = args->c; /* TODO: somehow pass the parent_if. (i.e. process_fork()'s if_) */ @@ -284,22 +323,12 @@ __do_fork (void *aux) { * TODO: from the fork() until this function successfully duplicates * TODO: the resources of parent.*/ - process_init (); - - /* fdt 복사, 나중에 fdt 타입 바꾸면 수정 필요 */ - for (int i = 2; i < FD_TABLE_SIZE; i++) { - struct file *file = parent->fd_table[i]; - if (file == NULL) - continue; - - lock_acquire(&file_lock); - struct file *dup = file_duplicate(file); - lock_release(&file_lock); - if (dup == NULL) - goto error; //반환하면 안됨 + if(!process_init()) + goto error; - current->fd_table[i] = dup; //dup한거 채우기 - } + /* fdt 복제 */ + if(!fork_fdt(parent, current)) + goto error; /* Finally, switch to the newly created process. */ if (succ){ @@ -455,26 +484,21 @@ process_exit (void) { * TODO: project2/process_termination.html). * TODO: We recommend you to implement process resource cleanup here. */ + if(curr->pml4 == NULL) return; //커널 스레드면 그냥 리턴 + /* fdt 초기화 */ - if (curr->fd_table != NULL) { - for (int i = 2; i < FD_TABLE_SIZE; i++) { - if (curr->fd_table[i] != NULL) { - lock_acquire(&file_lock); - file_close(curr->fd_table[i]); - lock_release(&file_lock); - } - } - free(curr->fd_table); + if (curr->fdt_entry != NULL) { + for(int i = 0; i < curr->FD_TABLE_SIZE; i++){ + // entry가 있으면 + if (curr->fdt_entry[i] != NULL){ + close_fdt_entry(curr->fdt_entry, i); + } + } + free(curr->fdt_entry); } process_cleanup (); - /* child_info 없으면 그냥 exit하면 됨 */ - if (curr->child_info){ - printf("%s: exit(%d)\n", curr->name, curr->exit_status); - sema_up(&curr->child_info->wait_sema); - } - if (curr->executable) { lock_acquire(&file_lock); file_allow_write(curr->executable); @@ -482,6 +506,27 @@ process_exit (void) { lock_release(&file_lock); } + /* 부모가 먼저 죽으면 자식들에게 p_alive = false로 죽었음을 전달 */ + struct list_elem *e = list_begin(&curr->child_list); + if(e != NULL){ + while(e != list_end(&curr->child_list)){ + struct child *c = list_entry(e, struct child, child_elem); + c->p_alive = false; + e = list_next(e); + } + } + + /* 부모가 존재하면 정보 전달 */ + if(curr->child_info->p_alive == true){ + curr->child_info->exit_status = curr->exit_status; + sema_up(&curr->child_info->wait_sema); + } + /* 부모가 강제 exit 됐으면 자식이 child_info free */ + else{ + free(curr->child_info); + } + printf("%s: exit(%d)\n", curr->name, curr->exit_status); + } /* Free the current process's resources. */ diff --git a/pintos/userprog/syscall.c b/pintos/userprog/syscall.c index 3713411..f7731a7 100644 --- a/pintos/userprog/syscall.c +++ b/pintos/userprog/syscall.c @@ -8,6 +8,7 @@ #include "threads/flags.h" #include "intrinsic.h" #include "include/threads/init.h" +#include "userprog/fdt.h" #include "threads/synch.h" #include "include/filesys/filesys.h" @@ -40,7 +41,7 @@ static void sys_seek(int fd, unsigned position); static unsigned sys_tell(int fd); static void sys_close(int fd); static void sys_exit(int status); - +static int sys_dup2(int oldfd, int newfd); struct lock file_lock; @@ -169,6 +170,10 @@ syscall_handler (struct intr_frame *f) { sys_close(f->R.rdi); break; + case SYS_DUP2: + f->R.rax = sys_dup2(f->R.rdi, f->R.rsi); + break; + default: printf("system call! (unimplemented syscall number: %d)\n", syscall_num); thread_exit(); @@ -199,7 +204,6 @@ static void valid_put_buffer(char *buffer, unsigned length){ static void sys_exit(int status) { struct thread *curr = thread_current(); - curr->child_info->exit_status = status; curr->exit_status = status; thread_exit(); } @@ -257,68 +261,71 @@ static bool sys_remove(const char *file){ static int sys_open(const char *file){ valid_get_addr(file); - struct file **fd_table = thread_current()->fd_table; + struct thread *curr = thread_current(); + lock_acquire(&file_lock); struct file *opened_file = filesys_open(file); + lock_release(&file_lock); if (opened_file == NULL) { /* open 실패면 inode close, free(file) 해줌 */ - lock_release(&file_lock); return -1; } - int res = -1; - for (size_t i = 2; i < FD_TABLE_SIZE; i++) { - if(fd_table[i] == NULL){ - fd_table[i] = opened_file; - res = i; - break; - } - } + // 비어 있는 가장 낮은 fd 반환. 없으면 -1 + int res = find_empty_fd(curr); - // No free descriptors - close the file - if (res == -1) { - file_close(opened_file); - } + // 모두 차있으면 fdt size 늘리기 + if (res == -1){ + int old_size = curr->FD_TABLE_SIZE; + if (!increase_fdt_size(curr, old_size)) { + lock_acquire(&file_lock); + file_close(opened_file); + lock_release(&file_lock); + return -1; + } + res = old_size; + } - lock_release(&file_lock); + /* 늘렸으니 찾아서 넣기 */ + if(!open_fdt_entry(curr->fdt_entry, res, opened_file)){ + lock_acquire(&file_lock); + file_close(opened_file); + lock_release(&file_lock); + return -1; + } return res; } static void sys_close(int fd) { + struct thread *curr = thread_current(); + //fd 범위 검증 - if(fd<2 || fd>=FD_TABLE_SIZE) - { + if(fd < 0 || fd >= curr->FD_TABLE_SIZE) sys_exit(-1); - } - struct file **fd_table = thread_current()->fd_table; - if(fd_table == NULL || fd_table[fd]==NULL) - { + struct fdt_entry **fdt_entry = curr->fdt_entry; + if(fdt_entry == NULL || fdt_entry[fd] == NULL) sys_exit(-1); - } - lock_acquire(&file_lock); - file_close(fd_table[fd]); - fd_table[fd]=NULL; //fd 재사용 가능 - lock_release(&file_lock); + close_fdt_entry(fdt_entry, fd); } - static int sys_filesize(int fd){ - // Validate fd range - if (fd < 0 || fd >= FD_TABLE_SIZE) - return -1; + struct thread *curr = thread_current(); - struct file **fd_table = thread_current()->fd_table; - if (fd_table == NULL) + // Validate fd range + if (fd < 0 || fd >= curr->FD_TABLE_SIZE) return -1; + struct fdt_entry **fdt_entry = curr->fdt_entry; + if(fdt_entry == NULL || fdt_entry[fd] == NULL) + return -1; - struct file *f = fd_table[fd]; - if (f == NULL) + struct file *f = fdt_entry[fd]->fdt; + if (f == NULL) return -1; lock_acquire(&file_lock); @@ -328,16 +335,26 @@ static int sys_filesize(int fd){ return size; } +/* fd를 읽어서 buffer에 담기, STDOUT 불가능 */ static int sys_read(int fd, void *buffer, unsigned length){ + struct thread *curr = thread_current(); + if(length == 0) return 0; valid_put_buffer(buffer, length); //써보면서 확인해야함 - if(fd < 0 || fd > FD_TABLE_SIZE || fd == 1) + if(fd < 0 || fd >= curr->FD_TABLE_SIZE) //fd 범위 이상한지 확인 + return -1; + + struct fdt_entry **fdt_entry = curr->fdt_entry; + if(fdt_entry == NULL || fdt_entry[fd] == NULL) return -1; - if(fd == 0){ + if(fdt_entry[fd]->type == STDOUT) + return -1; + + if(fdt_entry[fd]->type == STDIN){ for (unsigned i = 0; i < length; i++) { uint8_t c = input_getc(); // 쓰기 시 @@ -345,36 +362,45 @@ static int sys_read(int fd, void *buffer, unsigned length){ if(!put_user((uint8_t *)buffer + i, c)) return i; // 실패시 지금까지 읽은 바이트 수 반환 } - } - else{ + }else{ /* fd에 해당하는 파일에서 length만큼 읽어서 buffer에 담음*/ - struct file *file = thread_current()->fd_table[fd]; + struct file *file = curr->fdt_entry[fd]->fdt; if(file == NULL){ return -1; } lock_acquire(&file_lock); - /* file_reat_at 필요시 변경할지도 */ int size = file_read(file, buffer, length); lock_release(&file_lock); return size; } } +/* buffer 내용을 fd에 쓰기, STDIN 불가*/ static int sys_write(int fd, void *buffer, unsigned length) { + struct thread *curr = thread_current(); + valid_get_buffer(buffer, length); //읽기(접근) 가능을 확인해야함 - if(fd <= 0 || fd > FD_TABLE_SIZE) //0(stdin) 불가능 1~127까지 가능해야함 + if(fd < 0 || fd >= curr->FD_TABLE_SIZE) //이상한 fd 차단 + return -1; + + struct fdt_entry **fdt_entry = curr->fdt_entry; + if(fdt_entry == NULL || fdt_entry[fd] == NULL) + return -1; + + if(fdt_entry[fd]->type == STDIN) return -1; - if (fd == 1) { + if(fdt_entry[fd]->type == STDOUT){ /* stdout으로 write*/ putbuf(buffer, length); // Write to console return length; // Return number of bytes written } else { /* file에 write*/ - struct file *file = thread_current()->fd_table[fd]; + struct file *file = curr->fdt_entry[fd]->fdt; if(file == NULL) return -1; + lock_acquire(&file_lock); off_t size = file_write(file, buffer, length); lock_release(&file_lock); @@ -385,12 +411,22 @@ static int sys_write(int fd, void *buffer, unsigned length) { /* 반환값이 없으면 문제 생기면 그냥 exit 시킨다. */ static void sys_seek(int fd, unsigned position) { - if(fd < 2 || fd > FD_TABLE_SIZE) - sys_exit(-1); + struct thread *curr = thread_current(); + + if(fd < 0 || fd >= curr->FD_TABLE_SIZE) //이상한 fd 차단 + return; + + struct fdt_entry **fdt_entry = curr->fdt_entry; + if(fdt_entry == NULL || fdt_entry[fd] == NULL) + return; - struct file *file = thread_current()->fd_table[fd]; + //IN OUT 불가능 + if(fdt_entry[fd]->type == STDIN || fdt_entry[fd]->type == STDOUT) + return; + + struct file *file = curr->fdt_entry[fd]->fdt; if(file == NULL) - sys_exit(-1); + return; lock_acquire(&file_lock); file_seek(file, position); @@ -399,15 +435,63 @@ static void sys_seek(int fd, unsigned position) { static unsigned sys_tell(int fd){ - if(fd < 2 || fd > FD_TABLE_SIZE) - return -1; + struct thread *curr = thread_current(); - struct file *file = thread_current()->fd_table[fd]; + if(fd < 0 || fd >= curr->FD_TABLE_SIZE) //이상한 fd 차단 + sys_exit(-1); + + struct fdt_entry **fdt_entry = curr->fdt_entry; + if(fdt_entry == NULL || fdt_entry[fd] == NULL) + sys_exit(-1); + + //IN OUT 불가능 + if(fdt_entry[fd]->type == STDIN || fdt_entry[fd]->type == STDOUT) + sys_exit(-1); + + struct file *file = curr->fdt_entry[fd]->fdt; if(file == NULL) - return -1; + sys_exit(-1); lock_acquire(&file_lock); unsigned size = file_tell(file); lock_release(&file_lock); return size; } + +/* stdin, stdout 닫기 가능해야함 + newfd가 이미 있다면 close + 해제 해야함 + oldfd entry를 newfd에 연결 */ + +/* oldfd가 유효하지 않으면 그냥 -1 리턴(newfd 안닫음) + 이미 oldfd와 newfd가 같으면 그냥 newfd리턴 */ +static int sys_dup2(int oldfd, int newfd) { + + struct thread *curr = thread_current(); + + if(oldfd < 0 || oldfd >= curr->FD_TABLE_SIZE || newfd < 0) //이상한 fd 차단 + return -1; + + /* oldfd 유효하지 않으면 -1 리턴 */ + if(curr->fdt_entry[oldfd] == NULL) + return -1; + + /* 필요시 fdt 크기 늘리기 */ + if (!increase_fdt_size(curr, newfd)) + return -1; + + /* newfd 있으면 */ + if(curr->fdt_entry[newfd]){ + /* 이미 같으면 newfd 리턴 */ + if(curr->fdt_entry[oldfd] == curr->fdt_entry[newfd]){ + return newfd; + } + /* 다르면 닫기*/ + close_fdt_entry(curr->fdt_entry, newfd); + } + + /* 연결 */ + curr->fdt_entry[newfd] = curr->fdt_entry[oldfd]; + curr->fdt_entry[newfd]->ref_cnt++; + + return newfd; +} diff --git a/pintos/userprog/targets.mk b/pintos/userprog/targets.mk index b85df5b..6635f08 100644 --- a/pintos/userprog/targets.mk +++ b/pintos/userprog/targets.mk @@ -4,3 +4,4 @@ userprog_SRC += userprog/syscall-entry.S # System call entry. userprog_SRC += userprog/syscall.c # System call handler. userprog_SRC += userprog/gdt.c # GDT initialization. userprog_SRC += userprog/tss.c # TSS management. +userprog_SRC += userprog/fdt.c # FDT helpers.