diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2593bb6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,61 @@ +# Created by https://www.toptal.com/developers/gitignore/api/c +# Edit at https://www.toptal.com/developers/gitignore?templates=c + +### C ### +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +# git_ignore +*.bin + +# End of https://www.toptal.com/developers/gitignore/api/c \ No newline at end of file diff --git a/include/threads/loader.h b/include/threads/loader.h index 9dfee6f..b063e73 100644 --- a/include/threads/loader.h +++ b/include/threads/loader.h @@ -5,7 +5,7 @@ #define LOADER_BASE 0x7c00 /* Physical address of loader's base. */ #define LOADER_END 0x7e00 /* Physical address of end of loader. */ -/* Physical address of kernel base. */ +/* Virtual address of kernel base. */ #define LOADER_KERN_BASE 0x8004000000 /* Kernel virtual address at which all physical memory is mapped. */ diff --git a/include/threads/thread.h b/include/threads/thread.h index aecd4c4..ccd29ee 100644 --- a/include/threads/thread.h +++ b/include/threads/thread.h @@ -5,6 +5,7 @@ #include #include #include "threads/interrupt.h" +#include "threads/synch.h" // 이것을 추가해야 포인터를 쓸 수 있습니다. #ifdef VM #include "vm/vm.h" #endif @@ -28,6 +29,9 @@ typedef int tid_t; #define PRI_DEFAULT 31 /* Default priority. */ #define PRI_MAX 63 /* Highest priority. */ +#define FDT_PAGES 2 +#define FDT_COUNT_LIMIT 128 + /* A kernel thread or user process. * * Each thread structure is stored in its own 4 kB page. The @@ -94,12 +98,28 @@ struct thread { int64_t wakeup_tick; /* 해당 쓰레드가 깨어나야 할 tick을 저장할 필드 */ /* Shared between thread.c and synch.c. */ struct list_elem elem; /* List element. */ + /*priority donation 관련 항목 추가*/ int init_priority; /* donation 이후 우선순위를 초기화하기 위해 초기값 저장 */ struct lock *wait_on_lock; /* 해당 스레드가 대기 하고 있는 lock자료구조의 주소를 저장 */ struct list donations; /* multiple donation 을 고려하기 위해 사용 */ struct list_elem donation_elem; /* multiple donation 을 고려하기 위해 사용 */ + /*project 2 - SystemCall 항목 추가*/ + int exit_status; /* exit 호출 시 종료 status */ + struct file **fdt; /* 부모 프로세스의 디스크립터 */ + int next_fd; /* 다음 디스크립트를 가리키는 테이블 번호 */ + + struct intr_frame parent_if; /* 프로세스 프로그램 메모리 적재 */ + struct list child_list; /* 자식 리스트 */ + struct list_elem child_elem; /* 자식 리스트 element */ + + struct semaphore load_sema; /* load 세마포어 */ + struct semaphore exit_sema; /* exit 세마포어 */ + struct semaphore wait_sema; /* wait 세마포어 */ + + struct file *running; // 현재 실행중인 파일 + #ifdef USERPROG /* Owned by userprog/process.c. */ uint64_t *pml4; /* Page map level 4 */ @@ -155,6 +175,10 @@ int64_t get_next_tick_to_awake(void); void test_max_priority(void); bool cmp_priority(const struct list_elem *a, const struct list_elem *b, void *aux UNUSED); +// project2 +bool cmp_thread_priority(const struct list_elem *a, const struct list_elem *b, void *aux); +bool cmp_thread_ticks(const struct list_elem *a, const struct list_elem *b, void *aux); +// --- void donate_priority(void); void remove_with_lock(struct lock *lock); @@ -163,4 +187,6 @@ void refresh_priority(void); bool thread_compare_donate_priority(const struct list_elem *x, const struct list_elem *y, void *aux UNUSED); +void preempt_priority(void); + #endif /* threads/thread.h */ diff --git a/include/userprog/process.h b/include/userprog/process.h index 4365424..43a9d3b 100644 --- a/include/userprog/process.h +++ b/include/userprog/process.h @@ -9,5 +9,11 @@ int process_exec (void *f_name); int process_wait (tid_t); void process_exit (void); void process_activate (struct thread *next); - +/* project 2 */ +void argument_stack(char **argv, int argc, void **rsp); +struct thread *get_child_process(int pid); +int process_add_file(struct file *f); +struct file *process_get_file(int fd); +void process_close_file(int fd); +struct thread *get_child_process(int pid); #endif /* userprog/process.h */ diff --git a/include/userprog/syscall.h b/include/userprog/syscall.h index 9059096..7b281ba 100644 --- a/include/userprog/syscall.h +++ b/include/userprog/syscall.h @@ -2,5 +2,6 @@ #define USERPROG_SYSCALL_H void syscall_init (void); +struct lock filesys_lock; -#endif /* userprog/syscall.h */ +#endif /* userprog/syscall.h */ \ No newline at end of file diff --git a/lib/user/entry.c b/lib/user/entry.c index 46f2d59..d324fdc 100644 --- a/lib/user/entry.c +++ b/lib/user/entry.c @@ -3,6 +3,7 @@ int main (int, char *[]); void _start (int argc, char *argv[]); +// user program의 진입점이다. void _start (int argc, char *argv[]) { exit (main (argc, argv)); diff --git a/output/test b/output/test new file mode 100755 index 0000000..0418115 Binary files /dev/null and b/output/test differ diff --git a/threads/thread.c b/threads/thread.c index 463048f..4471348 100644 --- a/threads/thread.c +++ b/threads/thread.c @@ -211,18 +211,33 @@ tid_t thread_create(const char *name, int priority, t->tf.cs = SEL_KCSEG; t->tf.eflags = FLAG_IF; + /* 현재 스레드의 자식으로 추가 */ + list_push_back(&thread_current()->child_list, &t->child_elem); + + /* File Descriptor 테이블 메모리 할당 */ + t->fdt = palloc_get_multiple(PAL_ZERO, FDT_PAGES); + if (t->fdt == NULL) // 메모리 할당 실패시 에러 리턴. + return TID_ERROR; // -1 + /* Add to run queue. */ thread_unblock(t); + preempt_priority(); + + return tid; +} - /* 현재 실행중인 thread와 우선순위를 비교하여, 새로 생성된 - thread의 우선순위가 높다면 thread_yield()를 통해 CPU를 양보 */ +/* 현재 실행중인 thread와 우선순위를 비교하여, 새로 생성된 +thread의 우선순위가 높다면 thread_yield()를 통해 CPU를 양보 */ +void preempt_priority(void) +{ + if (thread_current() == idle_thread) + return; + if (list_empty(&ready_list)) + return; struct thread *curr = thread_current(); - if (t->priority > curr->priority) - { + struct thread *ready = list_entry(list_front(&ready_list), struct thread, elem); + if (curr->priority < ready->priority) // ready_list에 현재 실행중인 스레드보다 우선순위가 높은 스레드가 있으면 thread_yield(); - } - - return tid; } /* Puts the current thread to sleep. It will not be scheduled @@ -441,6 +456,13 @@ init_thread(struct thread *t, const char *name, int priority) t->init_priority = priority; // 초기 중요도 값 설정 t->wait_on_lock = NULL; // 기다리는 락은 NULL로 설정 list_init(&t->donations); // 스레드의 donations를 초기화 + + t->exit_status = 0; /* exit status 는 0으로 초기화 */ + t->next_fd = 2; /* next_fd 는 2로 초기화 (0 - 표준 입력, 1 - 표춘출력) */ + sema_init(&t->load_sema, 0); /* load의 세마 초기화 */ + sema_init(&t->exit_sema, 0); /* exit의 세마 초기화 */ + sema_init(&t->wait_sema, 0); /* wait의 세마 초기화 */ + list_init(&(t->child_list)); /* child_list를 초기화(head,tail 지정) */ } /* Chooses and returns the next thread to be scheduled. Should diff --git a/userprog/exception.c b/userprog/exception.c index bf4a9b2..7a06673 100644 --- a/userprog/exception.c +++ b/userprog/exception.c @@ -134,11 +134,11 @@ page_fault (struct intr_frame *f) { be assured of reading CR2 before it changed). */ intr_enable (); - /* Determine cause. */ not_present = (f->error_code & PF_P) == 0; write = (f->error_code & PF_W) != 0; user = (f->error_code & PF_U) != 0; + exit(-1); #ifdef VM /* For project 3 and later. */ diff --git a/userprog/process.c b/userprog/process.c index a186a09..d7c0e59 100644 --- a/userprog/process.c +++ b/userprog/process.c @@ -50,6 +50,8 @@ process_create_initd (const char *file_name) { return TID_ERROR; strlcpy (fn_copy, file_name, PGSIZE); + char *save_ptr; // 분리된 문자열 중 남는 부분의 시작주소 + strtok_r(file_name, " ", &save_ptr); /* Create a new thread to execute FILE_NAME. */ tid = thread_create (file_name, PRI_DEFAULT, initd, fn_copy); if (tid == TID_ERROR) @@ -74,10 +76,39 @@ initd (void *f_name) { /* Clones the current process as `name`. Returns the new process's thread id, or * TID_ERROR if the thread cannot be created. */ tid_t -process_fork (const char *name, struct intr_frame *if_ UNUSED) { +process_fork (const char *name, struct intr_frame *if_ UNUSED) +{ /* Clone current thread to new thread.*/ - return thread_create (name, - PRI_DEFAULT, __do_fork, thread_current ()); + // 현재 스레드의 parent_if에 복제해야 하는 if를 복사한다. + struct thread *cur = thread_current(); + memcpy(&cur->parent_if, if_, sizeof(struct intr_frame)); + + // 현재 스레드를 fork한 new 스레드를 생성한다. + tid_t pid = thread_create(name, PRI_DEFAULT, __do_fork, cur); + if (pid == TID_ERROR) + return TID_ERROR; + + // 자식이 로드될 때까지 대기하기 위해서 방금 생성한 자식 스레드를 찾는다. + struct thread *child = get_child_process(pid); + + // 현재 스레드는 생성만 완료된 상태이다. 생성되어서 ready_list에 들어가고 실행될 때 __do_fork 함수가 실행된다. + // __do_fork 함수가 실행되어 로드가 완료될 때까지 부모는 대기한다. + sema_down(&child->load_sema); + + // 자식이 로드되다가 오류로 exit한 경우 + if (child->exit_status == -2) + { + // 자식이 종료되었으므로 자식 리스트에서 제거한다. + // 이거 넣으면 간헐적으로 실패함 (syn-read) + // list_remove(&child->child_elem); + // 자식이 완전히 종료되고 스케줄링이 이어질 수 있도록 자식에게 signal을 보낸다. + sema_up(&child->exit_sema); + // 자식 프로세스의 pid가 아닌 TID_ERROR를 반환한다. + return TID_ERROR; + } + + // 자식 프로세스의 pid를 반환한다. + return pid; } #ifndef VM @@ -91,22 +122,34 @@ duplicate_pte (uint64_t *pte, void *va, void *aux) { void *newpage; bool writable; + //모름 /* 1. TODO: If the parent_page is kernel page, then return immediately. */ + if (is_kernel_vaddr(va)) + return true; /* 2. Resolve VA from the parent's page map level 4. */ - parent_page = pml4_get_page (parent->pml4, va); + parent_page = pml4_get_page(parent->pml4, va); + if (parent_page == NULL) + return false; + /* 3. TODO: Allocate new PAL_USER page for the child and set result to * TODO: NEWPAGE. */ + newpage = palloc_get_page(PAL_USER | PAL_ZERO); + if (newpage == NULL) + return false; /* 4. TODO: Duplicate parent's page to the new page and * TODO: check whether parent's page is writable or not (set WRITABLE * TODO: according to the result). */ + memcpy(newpage, parent_page, PGSIZE); + writable = is_writable(pte); /* 5. Add new page to child's page table at address VA with WRITABLE * permission. */ if (!pml4_set_page (current->pml4, va, newpage, writable)) { /* 6. TODO: if fail to insert page, do error handling. */ + return false; } return true; } @@ -122,11 +165,12 @@ __do_fork (void *aux) { 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; + 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; // 자식 프로세스의 리턴 값은 0이다. /* 2. Duplicate PT */ current->pml4 = pml4_create(); @@ -149,13 +193,27 @@ __do_fork (void *aux) { * TODO: from the fork() until this function successfully duplicates * TODO: the resources of parent.*/ + // FDT 복사 + for (int i = 0; i < FDT_COUNT_LIMIT; i++) + { + struct file *file = parent->fdt[i]; + if (file == NULL) + continue; + if (file > 2) + file = file_duplicate(file); + current->fdt[i] = file; + } + current->next_fd = parent->next_fd; + + sema_up(¤t->load_sema); process_init (); /* Finally, switch to the newly created process. */ if (succ) do_iret (&if_); error: - thread_exit (); + sema_up(¤t->load_sema); + exit(-2); } /* Switch the current execution context to the f_name. @@ -206,11 +264,11 @@ process_exec (void *f_name) { _if.R.rdi = argc; // rdi(stack의 첫번째 인자?)에 크기 저장 _if.R.rsi = (uint64_t)*rspp + sizeof(void *); // 스택에 저장된 주소들의 첫번째 주소 argv[0]의 주소 저장 - hex_dump(_if.rsp, _if.rsp, USER_STACK - (uint64_t)*rspp, true); palloc_free_page(file_name); + do_iret(&_if); + hex_dump(_if.rsp, _if.rsp, USER_STACK - (uint64_t)*rspp, true); /* Start switched process. */ - do_iret(&_if); NOT_REACHED(); } @@ -229,8 +287,17 @@ process_wait (tid_t child_tid UNUSED) { /* XXX: Hint) The pintos exit if process_wait (initd), we recommend you * XXX: to add infinite loop here before * XXX: implementing thfe process_wait. */ - for (int i=0;i<100000000;i++){} - return -1; + struct thread *child = get_child_process(child_tid); + if (child == NULL)// 자식이 아니면 -1을 반환한다. + return -1; + // 자식이 종료될 때까지 대기한다. (process_exit에서 자식이 종료될때 sema_up 해줄 것) + sema_down(&child->wait_sema); + /* 자식이 종료됨을 알리는 `wait_sema` signal을 받으면 현재 스레드(부모)의 자식 리스트에서 제거한다. */ + list_remove(&child->child_elem); + /* 자식이 완전히 종료되고 스케줄링이 이어질 수 있도록 자식에게 signal을 보낸다. */ + sema_up(&child->exit_sema); + + return child->exit_status; /* 자식의 exit_status를 반환한다. */ } /* Exit the process. This function is called by thread_exit (). */ @@ -242,7 +309,19 @@ process_exit (void) { * TODO: project2/process_termination.html). * TODO: We recommend you to implement process resource cleanup here. */ + /* 프로세스 종료가 일어날 경우 프로세스에 열려있는 모든 파일을 닫음. */ + for (int i = 2; i < FDT_COUNT_LIMIT; i++) // 프로세스에 열린 모든 파일 확인 + { + if (curr->fdt[i] != NULL) /* 현재 프로세스가 null 이 아니면 닫기. 변경요망(파일 디스크립터의 최소값인 2가 될 때까지 파일을 닫음)*/ + close(i); + } + palloc_free_multiple(curr->fdt, FDT_PAGES); /* 파일 테이블 */ + file_close(curr->running); /* 현재 실행 중인 파일도 닫는다. */ + process_cleanup (); + + sema_up(&curr->wait_sema); /* 자식이 종료될 때까지 대기하고 있는 부모에게 signal을 보낸다. */ + sema_down(&curr->exit_sema); /* 부모의 signal을 기다린다. 대기가 풀리고 나서 do_schedule(THREAD_DYING)이 이어져 다른 스레드가 실행된다. */ } /* Free the current process's resources. */ @@ -432,7 +511,10 @@ load (const char *file_name, struct intr_frame *if_) { break; } } - + // 스레드가 삭제될 때 파일을 닫을 수 있게 구조체에 파일을 저장해둔다. + t->running = file; + // 현재 실행중인 파일은 수정할 수 없게 막는다. + file_deny_write(file); /* Set up stack. */ if (!setup_stack (if_)) goto done; @@ -447,7 +529,7 @@ load (const char *file_name, struct intr_frame *if_) { done: /* We arrive here whether the load is successful or not. */ - file_close (file); + //file_close (file); return success; } @@ -704,9 +786,62 @@ void argument_stack(char **argv, int argc, void **rsp) **(char ***)rsp = argv[i]; // argv[i]의 주소값을 저장 } - // Return address - printf("\n abcd~~ abcd~~~ 0x%02X \n", *(uint16_t **)rsp); (*rsp) -= 8; // 마지막 값을 // 마지막 fake address 값을 넣어준다. **(void ***)rsp = 0; // rsp의 값을 0으로 지정한다. +} + +/* 자식 리스트를 검색하여 프로세스 디스크립터의 주소 리턴 */ +struct thread *get_child_process(int pid) +{ + struct thread *cur = thread_current(); + struct list *child_list = &cur->child_list; + for (struct list_elem *e = list_begin(child_list); e != list_end(child_list); e = list_next(e)) + { + struct thread *t = list_entry(e, struct thread, child_elem); + /* 해당 pid가 존재하면 프로세스 디스크립터 반환 */ + if (t->tid == pid) + return t; + } + /* 리스트에 존재하지 않으면 NULL 리턴 */ + return NULL; +} + +// 파일 객체에 대한 파일 디스크립터를 생성하는 함수 +int process_add_file(struct file *f) +{ + struct thread *curr = thread_current(); + struct file **fdt = curr->fdt; + + // limit을 넘지 않는 범위 안에서 빈 자리 탐색 + while(curr->next_fd < FDT_COUNT_LIMIT && fdt[curr->next_fd]) + curr->next_fd++; // 파일 디스크립터의 최대값 1 증가 + if (curr->next_fd >= FDT_COUNT_LIMIT) // 파일 디스크립터가 128보다 크면 오류 삭제 + return -1; + fdt[curr->next_fd] = f; // 비어 있는 fd에 file에 대한 값 넣기. + + return curr->next_fd; +} + +// 파일 객체를 검색하는 함수 +struct file *process_get_file(int fd) +{ + struct thread *curr = thread_current(); + struct file **fdt = curr->fdt; + + /* 파일 디스크립터에 해당하는 파일 객체를 리턴 */ + /* 없을 시 NULL 리턴 */ + if (fd < 2 || fd >= FDT_COUNT_LIMIT) + return NULL; + return fdt[fd]; +} + +// 파일 디스크립터 테이블에서 객체를 제거하는 함수 +void process_close_file(int fd) +{ + struct thread *curr = thread_current(); + struct file **fdt = curr->fdt; + if (fd < 2 || fd >= FDT_COUNT_LIMIT) // 만약 fd 가 2보다 작거나 128 크기 이상이라면 오류 발생 + return NULL; + fdt[fd] = NULL; } \ No newline at end of file diff --git a/userprog/syscall.c b/userprog/syscall.c index 1928191..ca1d442 100644 --- a/userprog/syscall.c +++ b/userprog/syscall.c @@ -7,9 +7,32 @@ #include "userprog/gdt.h" #include "threads/flags.h" #include "intrinsic.h" +#include "filesys/filesys.h" +#include "filesys/file.h" +#include "userprog/process.h" +#include "threads/synch.h" +// 오류 를 일으켜서 추가한 라이브러리. +#include "devices/input.h" +#include "lib/kernel/stdio.h" +#include "threads/palloc.h" void syscall_entry (void); void syscall_handler (struct intr_frame *); +void check_address(void *addr); +void halt(void); +void exit(int status); +bool create(const char *file, unsigned initial_size); +bool remove(const char *file); +int exec(const char *cmd_line); +int wait(int pid); +int open(const char *file_name); +int filesize(int fd); +int read(int fd, void *buffer, unsigned size); +int write(int fd, const void *buffer, unsigned size); +void seek(int fd, unsigned position); +unsigned tell(int fd); +void close(int fd); +tid_t fork(const char *thread_name, struct intr_frame *f); /* System call. * @@ -35,12 +58,234 @@ syscall_init (void) { * 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); + lock_init(&filesys_lock); } /* The main system call interface */ void syscall_handler (struct intr_frame *f UNUSED) { // TODO: Your implementation goes here. - printf ("system call!\n"); - thread_exit (); + int systemcall_num = f->R.rax; + printf("%d\n", systemcall_num); + + switch (systemcall_num) + { + case SYS_HALT: + halt(); + break; + case SYS_EXIT: + exit(f->R.rdi); + break; + case SYS_FORK: + f->R.rax = fork(f->R.rdi, f); + break; + case SYS_EXEC: + f->R.rax = exec(f->R.rdi); + break; + case SYS_WAIT: + f->R.rax = 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); + } +} + +void check_address(void *addr){ + if (addr == NULL) + exit(-1); + if (!is_user_vaddr(addr)) + exit(-1); + if (pml4_get_page(thread_current()->pml4, addr) == NULL) + exit(-1); + // if (addr == NULL || !(is_user_vaddr(addr))||pml4_get_page(cur->pml4, addr) == NULL){ + // exit(-1); + // } +} + +// pintos를 종료시키는 시스템 콜 +void halt(void){ + power_off(); // 핀토스를 종료시키는 함수 } + +// 현재 프로세스를 종료시키는 시스템 콜 +void exit(int status){ + struct thread *cur = thread_current(); + cur->exit_status = status; + printf("%s: exit(%d)\n",thread_name(), status); + thread_exit(); +} + +//파일을 생성하는 시스템 콜 +bool create(const char *file, unsigned initial_size){ + check_address(file); + return filesys_create(file,initial_size); // 파일 이름과 파일 사이즈를 인자 값으로 받아 파일을 생성하는 함수 +} + +//파일을 삭제하는 시스템 콜 +bool remove(const char *file){ + check_address(file); + return filesys_remove(file); // 파일 이름에 해당하는 파일을 제거하는 함수 +} + +int exec(const char *cmd_line) +{ + check_address(cmd_line); + + // 새 스레드를 생성하지 않고 process_exec을 호출한다. + + char *cmd_line_copy; // filename으로 const char* 복사본을 만든다. + cmd_line_copy = palloc_get_page(0); + if (cmd_line_copy == NULL) // 메모리 할당 실패시 exit(-1) + exit(-1); + strlcpy(cmd_line_copy, cmd_line, PGSIZE); // cmd_line을 복사한다. + + if (process_exec(cmd_line_copy) == -1) + exit(-1); // 실패 시 status -1로 종료한다. +} + +int wait(int pid) +{ + return process_wait(pid); +} + +// 파일을 열 때 사용하는 시스템 콜 +int open(const char *file_name) +{ + check_address(file_name); + struct file *file = filesys_open(file_name); + if (file == NULL) + return -1; + int fd = process_add_file(file); + if (fd == -1) // 여기에 땀 있었음.(닦아줌) + file_close(file); + return fd; +} + +// 파일의 크기를 알려주는 시스템 콜 +int filesize(int fd) +{ + struct file *file = process_get_file(fd); + if (file == NULL) + return -1; + return file_length(file); +} + +// 열린 파일의 데이터를 읽는 시스템 콜 +int read(int fd, void *buffer, unsigned size) +{ + check_address(buffer); + + char *ptr = (char *)buffer; + int bytes_read = 0; + + lock_acquire(&filesys_lock); // 락을 요구합니다. + if(fd == STDIN_FILENO) + { + for (int i = 0; i < size; i++) + { + *ptr++ = input_getc(); + bytes_read++; + } + lock_release(&filesys_lock); + } + else + { + if (fd < 2) + { + lock_release(&filesys_lock); + return -1; + } + struct file *file = process_get_file(fd); + if (file == NULL) + { + lock_release(&filesys_lock); + return -1; + } + bytes_read = file_read(file, buffer, size); + lock_release(&filesys_lock); + } + return bytes_read; +} + +// 열린 파일의 데이터를 기록 시스템 콜 +int write(int fd, const void *buffer, unsigned size) +{ + check_address(buffer); + int bytes_write = 0; + if (fd == STDOUT_FILENO) + { + putbuf(buffer, size); + bytes_write = size; + } + else + { + if (fd < 2) + return -1; + struct file *file = process_get_file(fd); + if (file == NULL) + return -1; + lock_acquire(&filesys_lock); + bytes_write = file_write(file, buffer, size); + lock_release(&filesys_lock); + } + return bytes_write; +} + + +// 열린 파일의 위치를 이동하는 시스템 콜 +void seek(int fd, unsigned position) +{ + struct file *file = process_get_file(fd); + if (file == NULL) + return; + file_seek(file, position); +} + +// 열린 파일의 위치를 알려주는 시스템 콜 +unsigned tell(int fd) +{ + struct file *file = process_get_file(fd); + if (file == NULL) + return; + return file_tell(file); +} + +// 열린 파일을 닫는 시스템 콜 +void close(int fd) +{ + struct file *file = process_get_file(fd); + if (file == NULL) + return; + file_close(file); + process_close_file(fd); +} + + +tid_t fork(const char *thread_name, struct intr_frame *f) +{ + return process_fork(thread_name, f); +} \ No newline at end of file