이어서
구현된 부분
(exec, open, file size, read, write) + exception.c
file을 실행가능한 파일로 변경함 - 성공하면 아무것도 return 안하고 실패하면 -1을 return
process_exec 는 앞에서 load를 구현할때 사용하였다. load에 문제가 없다면 정상적으로 동작할 것임
//syscall.c
int
exec_handler (const char *file) { // exec handler가 정상 동작을 한다면 아무것도
// return하지 않고 실패한다면 -1 을 return 한다
check_add (file);
char *file_name_copy = palloc_get_page (PAL_ZERO);
if (file_name_copy == NULL) // page를 정상적으로 할당 받지 못했다면
exit_handler (-1);
strlcpy (file_name_copy, file,
strlen (file) + 1); // +1은 NULL 문자를 위해서
if (process_exec (file_name_copy) == -1) // process_exec에 성공하지 못하면 -1을 return 함
return -1;
}
file을 open을 하고 open된 file을 이중포인터로 관리한다
//syscall.c
int // open 하는데 성공하면 0 이상의 정수를 반환함 실패하면 음수를 반환
open_handler (const char *file) {
check_add (file);
struct file *file_st = filesys_open (file); // 일단 파일을 open하고
if (file_st == NULL) { // open 한게 Null이 아니면 if문을 통과
return -1;
}
int fd_idx = add_file_to_FDT (file_st); // open한 file 을 table로 관리함
// 현재 thread가 가진 구조체 내부 fd table에 빈공간이 있으면
// 추가 후 해당 위치를 return 하고 추가하지 못했으면 -1을 return함
if (fd_idx == -1) { // 추가하지 못했다면
file_close (file_st); // 열린걸 다시 닫아줘야함 (열린 상태로 두면 안됨)
}
return fd_idx; // 파일이 잘 열렸다면 열린 파일의 fd table에서의 index를
// 반환함 (아마도 열린 파일의 개수랑 동일할 것으로 보임)
}
//syscall.c
int
add_file_to_FDT (
struct file *file) { // 각 process에서 open한 부분을 기억하는 부분
struct thread *cur = thread_current ();
struct file **fdt = cur->fd_table;
int fd_index = cur->fd_idx;
while (fdt[fd_index] != NULL &&
fd_index < FD_COUNT_LIMT) { // 현재 fd_table의 빈공간을 찾는 작업
fd_index++;
}
if (fd_index >= FD_COUNT_LIMT) { // fd_index가 FD_count_limit 보다 크다는건
// 공간이 없다는 의미
return -1;
}
cur->fd_idx = fd_index; // fd_index를 thread에 저장해주고
fdt[fd_index] = file; // fd table에 file을 저장
return fd_index;
}
file_length 는 사전에 구현되어 있는 함수임
들어온 fd를 이용하여 file을 찾고 그 크기를 찾아 return 함
int
file_size_handler (
int fd) { // input된 fd를 이용하여 file의 size를 찾아주는 handler
struct file *file_ =
find_file_using_fd (fd); // 들어온 fd에 맞는 file을 찾아주고
if (file_ == NULL) // 만일 적합한 file을 찾지 못했다면 -1 을 return 함
return -1;
return file_length (file_); // 미리 구현되어있는 file_length 함수를 사용하여
// file_의 크기를 찾아서 return 해줌
}
int
read_handler ( int fd, const void *buffer, unsigned size) { // open 된 file을 읽고 + 읽은 file의 크기를 반환
check_add (buffer);
int read_result; // file을 읽고 난 후 크기를 저장하기 위한 선언
struct file *file_obj = find_file_using_fd (fd); // 받은 식별자에 해당하는 file을 찾음
if (file_obj == NULL)
return -1;
if (fd == STDIN_FILENO) { // fd == STDIN_FILENO 는 표준 입력을 얘기한다 == 키보드 등으로 input 받음
char word; // 키보드로 입력을 한글자씩 받기위한 공간
for (read_result = 0; read_result < size; read_result++) { // read_result는 0부터 input들어온 개수 또는 처음 들어온 size까지 받아서 출력함
word = input_getc ();
if (word == "\0") // 중간에 NULL 문자가 들어오면 break
break;
}
} else if (fd == STDOUT_FILENO) { // 표준 출력이면 출력부인데 읽을수 없으니 실패를 의미하는 -1을 return 함
return -1;
} else {
lock_acquire (&filesys_lock); // file_read를 사용하기 전에 lock을 걸어야함 - 내가 읽는 동안에 file이 수정되거나 간섭받으면 안되니깐
read_result = file_read (file_obj, buffer, size); // file_read는 구현이 되어있는 함수임
lock_release (&filesys_lock); // lock을 release해줌
}
return read_result; // 읽은 크기를 return함
}
int
write_handler (int fd, const void *buffer, unsigned size) {
check_add (buffer);
struct file *file_obj = find_file_using_fd (fd);
if (fd == STDIN_FILENO) // fd == STDIN이면 표준 입력이라서 write가 불가함 따라서 return 0
return 0;
if (fd == STDOUT_FILENO) { // fd == STDOUT이면 표준 출력 따라서
putbuf (buffer, size); // putbuf (사전에 구현된 함수) 함수릍 통해서 buffer와 size를 출력함
return size; // 그리고 결과로 크기만큼 return 함
} else {
if (file_obj == NULL) // file_obj가 NULL이면 return 0;
return 0;
lock_acquire (&filesys_lock); // file write를 하기 전에 lock을 걸고
off_t write_result = file_write (file_obj, buffer, size); // file에 buffer를 size만큼 쓰고
lock_release (&filesys_lock); // lock 을 풀어줌
return write_result; // 결과로 write 크기 (buffer에 적힌 크기) 를 return 함
}
}
write 와 read의 중요한 점은 file_write, file_read를 사용할때 앞뒤로 lock을 걸어줘야한다는 것이다. 안그러면 니가 읽는동안에 또는 쓰는 동안에 file이 바뀔수도 있다
//exception.c - page_fault 함수 안에
if (user) {
f->R.rdi = -1;
exit_handler (f->R.rdi);
}