시스템 콜을 짜기 전에 각 스레드는 자신의 파일 디스크립터 테이블을 가지고 있어야 한다. 이중 포인터로 thread 스트럭쳐에 필드를 추가해준다. 또한, exit 시스템콜을 위해서 exit 여부를 확인할 수 있는 필드와, exit_status도 선언해준다.
bool is_exited;
int exit_status;
struct file** fd_table;
int index;
그리고 thread.c의 thread_create()에서
t -> fd_table = palloc_get_page(PAL_ZERO)
를 해준다. 스레드를 만들 때 palloc으로 할당을 해줬으니까 스레드가 죽을 때 free 해주면 될 것 같은데!
thread가 죽을 때는 thread_exit()을 호출하고, thread_exit에서는 ifdef USERPROG를 통해 process_exit()을 호출한다. 그러니까 process_exit() 내부에 일단 palloc_free_page(curr -> fd_table)을 써주자.
handler를 짜줘야한다. 그러기 위해서는 system call function들을 syscall.h에 선언해줘야한다. 필요한 헤더들과 같이 선언해주자.
#ifndef USERPROG_SYSCALL_H
#define USERPROG_SYSCALL_H
#include <stdbool.h>
#include <stdint.h>
#include "threads/thread.h"
#include "threads/synch.h"
typedef pid_t;
struct lock syscall_lock;
void syscall_init (void);
void sys_halt (void);
void exit (int status);
pid_t sys_fork(const char *thread_name, struct intr_frame* f);
int sys_exec (const char *cmd_line);
int sys_wait (pid_t pid);
bool sys_create (const char *file, unsigned initial_size);
bool sys_remove (const char *file);
int sys_open (const char *file);
int sys_filesize (int fd);
int sys_read (int fd, void *buffer, unsigned size);
int sys_write (int fd, const void *buffer, unsigned size);
void sys_seek (int fd, unsigned position);
unsigned sys_tell (int fd);
void sys_close (int fd);
int add_file(struct file *file);
void close_file(int fd);
#endif /* userprog/syscall.h */
syscall_lock은 syscall.c의 syscall_init에서 lock_init(&syscall_lock)을 해준다.
syscall handler는 아래와 같다. sys_fork()를 아직 짜지 않았기 때문에 case SYS_FORK: 내부에는 break문만 써놓았다.
printf("system call!\n")도 나중에 삭제해야될 수도 있다.
void
syscall_handler (struct intr_frame *f UNUSED) {
// TODO: Your implementation goes here.
printf ("system call!\n");
if (!is_user_vaddr(f -> rsp)){
exit(-1);
}
switch(f -> R.rax){
case SYS_HALT:
sys_halt();
break;
case SYS_EXIT:
//printf("sys_exit\n");
exit(f->R.rdi);
break;
case SYS_FORK:
//printf("sys_fork\n");
// f->R.rax = sys_fork(f->R.rdi, f);
break;
case SYS_EXEC:
//printf("sys_exec\n");
f->R.rax = sys_exec(f->R.rdi);
break;
case SYS_WAIT:
//printf("sys_wait\n");
f->R.rax = sys_wait(f->R.rdi);
break;
case SYS_CREATE:
//printf("sys_create\n");
f->R.rax = sys_create(f->R.rdi, f->R.rsi);
break;
case SYS_REMOVE:
//printf("sys_remove\n");
f->R.rax = sys_remove(f->R.rdi);
break;
case SYS_OPEN:
//printf("sys_open\n");
f->R.rax = sys_open(f->R.rdi);
break;
case SYS_FILESIZE:
//printf("sys_filesize\n");
f->R.rax = sys_filesize(f->R.rdi);
break;
case SYS_READ:
//printf("sys_read\n");
f->R.rax = sys_read(f->R.rdi, f->R.rsi, f->R.rdx);
break;
case SYS_WRITE:
//printf("sys_write\n");
f->R.rax = sys_write(f->R.rdi, f->R.rsi, f->R.rdx);
break;
case SYS_SEEK:
//printf("sys_seek\n");
sys_seek(f->R.rdi, f->R.rsi);
break;
case SYS_TELL:
//printf("sys_tell\n");
f->R.rax = sys_tell(f->R.rdi);
break;
case SYS_CLOSE:
//printf("sys_close\n");
sys_close(f->R.rdi);
break;
default:
thread_exit ();
break;
}
}
각각의 시스템콜 함수들은 아래와 같다.
void sys_halt (void){
power_off();
}
void exit (int status){
printf("%s: exit(%d)\n", thread_name(), status);
thread_current() -> is_exited = true;
thread_current() -> exit_status = status;
thread_exit();
}
int sys_exec (const char *cmd_line){
if (!is_user_vaddr(cmd_line))
exit(-1);
if (&cmd_line == NULL)
return -1;
return process_exec(cmd_line);
}
int sys_wait (pid_t pid){
if (pid == NULL)
return -1;
return process_wait(pid);
}
bool sys_create (const char *file, unsigned initial_size){
if (file == NULL)
return false;
return filesys_create(file, initial_size);
}
bool sys_remove (const char *file){
if (file == NULL)
return false;
return filesys_remove(file);
}
int sys_open (const char *file){
if (!is_user_vaddr(file))
exit(-1);
if (file == NULL)
exit(-1);
lock_acquire(&syscall_lock);
struct file *f = filesys_open(file);
if (f == NULL){
lock_release(&syscall_lock);
return -1;
}
if (strcmp(file, thread_current() -> name) == 0){
file_deny_write(f);
}
int result = add_file(f);
lock_release(&syscall_lock);
return result;
}
int sys_filesize (int fd){
struct file *f = thread_current() -> fd_table[fd];
if (f == NULL)
return -1;
return file_length(f);
}
int sys_read (int fd, void *buffer, unsigned size){
int result = -1;
if (fd < 0 || fd == 1)
return result;
lock_acquire(&syscall_lock);
if (fd == 0){
result = 0;
for (int i = 0; i < size; i++){
result ++;
if (input_getc() == '\n') break;
}
}
else{
struct file *f = thread_current() -> fd_table[fd];
if (f == NULL){
lock_release(&syscall_lock);
exit(-1);
}
result = file_read(f, buffer, size);
}
lock_release(&syscall_lock);
return result;
}
int sys_write (int fd, const void *buffer, unsigned size){
if (!is_user_vaddr(buffer))
exit(-1);
int result = 0;
if (fd < 0)
return -1;
else if (fd == 1){
putbuf(buffer, size);
result = size;
}
else {
lock_acquire(&syscall_lock);
struct file *f = thread_current() -> fd_table[fd];
if (f == NULL){
lock_release(&syscall_lock);
return result;
}
result = file_write(f, buffer, size);
lock_release(&syscall_lock);
}
return result;
}
void sys_seek (int fd, unsigned position){
struct file *f = thread_current() -> fd_table[fd];
if (f == NULL)
return;
file_seek(f, position);
}
unsigned sys_tell (int fd){
struct file *f = thread_current() -> fd_table[fd];
if (f == NULL)
return -1;
return file_tell(fd);
}
void sys_close (int fd){
close_file(fd);
}
int add_file(struct file *file){
struct thread *curr = thread_current();
if (curr -> fd_table == NULL || curr -> index > 127){
file_close(file);
return -1;
}
curr -> fd_table[curr -> index] = file;
curr -> index++;
return curr -> index - 1;
}
void close_file(int fd){
struct thread *curr = thread_current();
if (curr -> fd_table == NULL)
exit(-1);
if (fd < 2 || fd >= curr ->index)
return;
file_close(curr -> fd_table[fd]);
curr -> fd_table[fd] == NULL;
}
'KAIST PINTOS' 카테고리의 다른 글
argument passing (0) | 2022.02.13 |
---|---|
Process.c (0) | 2022.02.13 |
Project 2 디버깅 (0) | 2022.02.07 |
system call (0) | 2022.01.21 |
PROJECT 1 - Alarm Clock, Priority Scheduling (0) | 2022.01.20 |