파일 시스템 콜
struct file {
struct inode *inode;
off_t pos;
bool deny_write;
};
inode: 인덱스 노드. 보조기억장치에 파일이 저장된 블록 정보를 색인하는 용도.
pos: 현재 읽거나 쓸 위치.
deny_write: true일 시 쓰기 연산이 금지됨
파일 명시자 테이블
struct thread {
struct file **fdt;
int next_fd;
}
void process_init (void) {
current -> fdt = calloc(128, sizeof(struct file *));
current -> next_fd = 2;
}
- 파일 명시자 (파일을 나타내는 인덱스 번호)
- 파일이 open되면 파일 명시자를 부여받고, 테이블 해당 인덱스에 해당 파일의
struct file*형 포인터 저장
- open될 때마다
next_fd에 해당하는 위치의 명시자를 부여함
- 핀토스에서 0은 표준입력(
stdin), 1은 표준출력(stdout)에 예약됨
- 최대 128 - 2 = 126개 파일 명시자 허용하는 메모리를 할당
세마포어
- 한번에 여러 작업단위(쓰레드/프로세스)가 파일에 접근할 시 race condition 등 문제가 발생할 수 있으므로, global lock을 사용해 통제
- 한 번에 한 작업 단위만 파일 관련 시스템 콜 수행 가능
struct lock filesys_lock;
void syscall_init (void) {
lock_init(&filesys_lock);
}
파일 시스템 콜 종류
case SYS_CREATE:
valid_pointer(f -> R.rdi);
lock_acquire(&filesys_lock);
f -> R.rax = filesys_create((char *)(f -> R.rdi), f -> R.rsi);
lock_release(&filesys_lock);
break;
remove: 지정된 파일이나 객체를 삭제한다.
case SYS_REMOVE:
valid_pointer(f -> R.rdi);
lock_acquire(&filesys_lock);
f -> R.rax = filesys_remove((char *)(f -> R.rdi));
lock_release(&filesys_lock);
break;
open: 파일을 열어 접근할 수 있는 파일 식별자를 반환한다. (핀토스에선 닫는 과정에서 파일 객체에 대한 메모리할당도 이루어짐)
case SYS_OPEN:
struct file *opened_file;
valid_pointer(f -> R.rdi);
lock_acquire(&filesys_lock);
int set_fd = find_empty_fd(thread_current() -> next_fd);
if (set_fd == -1){
f -> R.rax = -1;
} else if (2 <= set_fd && set_fd <= 127) {
opened_file = filesys_open((char *)(f -> R.rdi));
if (opened_file == NULL){
f -> R.rax = -1;
} else {
(thread_current() -> fdt)[set_fd] = opened_file;
f -> R.rax = set_fd;
thread_current() -> next_fd = (set_fd + 1) % FD_LIMIT;
}
}
lock_release(&filesys_lock);
break;
case SYS_FILESIZE:
int size_fd = (int)(f -> R.rdi);
if (2 <= size_fd && size_fd <= 127){
lock_acquire(&filesys_lock);
f -> R.rax = file_length(thread_current() -> fdt[(int)(f -> R.rdi)]);
lock_release(&filesys_lock);
}
break;
close: 파일을 닫는다. (핀토스에선 닫는 과정에서 파일 객체에 대한 메모리할당 해제도 이루어짐)
case SYS_CLOSE:
int close_fd = (int)(f -> R.rdi);
if (2 <= close_fd && close_fd <= 127){
lock_acquire(&filesys_lock);
struct file *close_file = (thread_current() -> fdt)[close_fd];
file_close(close_file);
(thread_current() -> fdt)[close_fd] = NULL;
lock_release(&filesys_lock);
}
break;
seek: 파일에서 현재 읽거나 쓸 위치를 변겅한다.
case SYS_SEEK:
int seek_fd = (int)(f -> R.rdi);
unsigned seek_position = (unsigned)(f -> R.rsi);
if (2 <= seek_fd && seek_fd <= 127){
file_seek((thread_current() -> fdt)[seek_fd], (off_t)(seek_position));
}
break;
seek: 파일에서 현재 읽거나 쓸 위치를 반환한다.
case SYS_TELL:
int tell_fd = (int)(f -> R.rdi);
if (2 <= tell_fd && tell_fd <= 127){
f -> R.rax = (off_t)file_tell((thread_current() -> fdt)[tell_fd]);
}
break;
read: 입력 연산 -> 파일에서 프로그램으로 데이터가 전송.
- 파일명시자가 0인 경우, 파일은 표준 입력인 키보드(
stdin)
case SYS_READ:
int read_fd = (int)(f -> R.rdi);
if (read_fd == 0){
f -> R.rax = (int)input_getc();
} else if (2 <= read_fd && read_fd <= 127) {
lock_acquire(&filesys_lock);
valid_pointer(f -> R.rsi);
struct file *read_file = (thread_current() -> fdt)[read_fd];
if (read_file != NULL){
f -> R.rax = (int)file_read(read_file, f -> R.rsi, f -> R.rdx);
}
lock_release(&filesys_lock);
}
break;
write: 출력 연산 -> 파일에서 프로그램으로 데이터가 전송.
- 파일명시자가 1인 경우, 파일은 표준 출력인 모니터(
stdout)
case SYS_WRITE:
valid_pointer(f -> R.rsi);
int write_fd = (int)(f -> R.rdi);
if (write_fd == 1){
putbuf((char *)(f -> R.rsi), (size_t)(f -> R.rdx));
} else if (2 <= write_fd && write_fd <= 127) {
lock_acquire(&filesys_lock);
struct file *write_file = (thread_current() -> fdt)[write_fd];
if (write_file != NULL){
f -> R.rax = file_write(write_file, f -> R.rsi, f -> R.rdx);
}
lock_release(&filesys_lock);
}
break;