: pintos 프로그램 종료
void halt(void)
{
power_off();
}
: 현재 실행중인 스레드 종료
void exit(int status)
{
struct thread *cur = thread_current();
cur->exit_status = status;
// exit_status에 인자로 받은 status(f->R.rdi) 저장
printf("%s: exit(%d)\n", thread_name(), status);
// 종료 시, "프로세스 이름 : exit(status) 출력"
// 정상 종료 시 status는 0
thread_exit(); // thread_exit() -> process_exit()
}
: 현재 스레드를 클론하여, 새로운 스레드 생성 성공시 새로운 스레드의 TID를 반환
tid_t process_fork(const char *name, struct intr_frame *if_)
{
/* Clone current thread to new thread.*/
struct thread *cur = thread_current();
// 1. 현재 실행중인 스레드의 parent_if 멤버에 if_ 저장
// if_ 받아서, parent_if에 복사
memcpy(&cur->parent_if, if_, sizeof(struct intr_frame)); // Pass this intr_frame down to child
// 2. 자식 스레드 생성 -> 자식 스레드를 child list에 넣기
tid_t tid = thread_create(name, PRI_DEFAULT, __do_fork, cur);
if (tid == TID_ERROR)
return TID_ERROR;
// 3. 생성한 자식 스레드의 tid를 가진 스레드 child_list에서 찾기
struct thread *child = get_child_with_pid(tid);
// 4. 찾은 스레드의 sema_down
// do_fork에서 sema up으로 막혀있었는데, sema_down 해줌
// 즉, 자식 스레드 생성하고, do_fork 완료할 때까지 fork()에서 나갈 수 없음
sema_down(&child->fork_sema); // wait until child loads
if (child->exit_status == -1)
return TID_ERROR;
#ifdef DEBUG_WAIT
printf("[process_fork] pid %d : child %s\n", tid, child->name);
#endif
// 모두 완료되면, 자식 스레드의 tid 리턴
return tid;
}
: exec() -> process_exec()
int exec(char *file_name)
{
check_address(file_name); // 주소 유효성 검사
// 문제점) SYS_EXEC - process_exec의 process_cleanup 때문에 f->R.rdi 날아감
// 여기서 file_name 동적할당해서 복사한 뒤, 그걸 넘겨주기
int siz = strlen(file_name) + 1;
//strlen(file_name) +1 에서 +1은 '\n'을 위한 것
// +1 은 char*(8byte)만큼 늘어나는 것을 의미하므로, 한글자 더 읽을 수 있게됨
char *fn_copy = palloc_get_page(PAL_ZERO); // 힙에 메모리 동적 할당 해주기
if (fn_copy == NULL) // 할당 실패시
exit(-1);
strlcpy(fn_copy, file_name, siz); //file_name을 fn_copy에 복사해 넣기
// 실패 시, 할당한 page free하고 -1 리턴함
if (process_exec(fn_copy) == -1)
return -1;
// Not reachable
NOT_REACHED();
return 0;
}
: 해당 tid를 가진 자식 스레드가 끝나길 기다리고, 해당 자식 스레드의 exit_status를 반환
int process_wait(tid_t child_tid UNUSED)
{
struct thread *cur = thread_current();
// 해당 tid를 가진 자식이 있는지 확인 -> 없을 경우, -1 리턴
struct thread *child = get_child_with_pid(child_tid);
if (child == NULL)
return -1;
// 자식 스레드가 process_exit()에서 sema_up(wait_sema) 할 때까지 기다림(block 상태 진입)
// wait_sema는 부모가 기다리는 sema
sema_down(&child->wait_sema);
int exit_status = child->exit_status;
// 자식 프로세스의 exit_status 기록
// 자식 프로세스는 syscall.c/exit()에서 exit_status 갱신 후, thread/thread_exit() -> process.c/process_exit()을 한 상태
// 부모의 child list에서 해당 자식 지우기
list_remove(&child->child_elem);
// wake-up child in process_exit - proceed with thread_exit
// 잠들었던 자식 프로세스 깨우기
sema_up(&child->free_sema);
return exit_status;
// 부모 프로세스의 wait() 종료 -> 자식 프로세스의 process_exit() 종료
}
: 파일 생성
// file은 생성할 파일의 이름 및 경로 정보, initial_size는 생성할 파일의 크기
bool create(const char *file, unsigned initial_size)
{
check_address(file);
return filesys_create(file, initial_size);
}
bool
filesys_create (const char *name, off_t initial_size) {
disk_sector_t inode_sector = 0;
struct dir *dir = dir_open_root ();
// dir_open_root (): 메모리에 root 디렉터리 inode 자료구조 생성
bool success = (dir != NULL
&& free_map_allocate (1, &inode_sector)
// free_map_allocate() : free 블럭의 할당 및 할당된 주소의 저장
// 할당받은 블록의 시작 번호를 2번재 인자에 저장
&& inode_create (inode_sector, initial_size)
// inode_create(): 데이터 블럭을 할당 받고, inode에 위치 저장,
// 해당 inode 디스크 저장
&& dir_add (dir, name, inode_sector));
// 열려있는 루트 디렉터리에 새로 만든 파일 아이노드 엔트리 추가하고, 디스크에 기록
// dir_add() : 디렉터리 내 파일의 존재여부 검사 후, 디렉터리 엔트리에 추가
if (!success && inode_sector != 0)
free_map_release (inode_sector, 1);
dir_close (dir);
return success;
}
: 파일 삭제
bool remove(const char *file)
{
check_address(file);
return filesys_remove(file);
}
bool
filesys_remove (const char *name) {
struct dir *dir = dir_open_root (); // 루트 디렉터리 열기
bool success = dir != NULL && dir_remove (dir, name);
// 디렉터리에서 해당 엔트리 사용 안함 처리 후, inode removed = true처리
dir_close (dir); // 루트 디렉터리 닫기
return success;
}
bool
dir_remove (struct dir *dir, const char *name) {
struct dir_entry e;
struct inode *inode = NULL;
bool success = false;
off_t ofs;
ASSERT (dir != NULL);
ASSERT (name != NULL);
/* Find directory entry. */
// 1. 디렉터리에서 파일 이름 가진 엔트리 찾기(offset)
if (!lookup (dir, name, &e, &ofs))
goto done;
/* Open inode. */
// 2. 엔트리에 해당하는 아이노드 열기
inode = inode_open (e.inode_sector);
if (inode == NULL)
goto done;
// 3. 엔트리 사용안함 처리
/* Erase directory entry. */
e.in_use = false;
// 4. 디렉터리의 해당 엔트리 갱신(사용안함 처리 반영해주기)
if (inode_write_at (dir->inode, &e, sizeof e, ofs) != sizeof e)
goto done;
/* Remove inode. */
// 5. 해당 아이노드 deleted 처리 (inode-> removed = true)
inode_remove (inode);
success = true;
done:
inode_close (inode); //inode -> opencnt 하나 내리고 0이 되면 메모리에서 내림
return success;
}
int open(const char *file)
{
check_address(file); // file 주소 유효성 검사
struct file *fileobj = filesys_open(file);
// filesys_open()은 return file_open(inode) -> file_open()은 return file 이므로,
// fileobj = 리턴 값으로 받은 file이 됨
// 실패시
if (fileobj == NULL)
return -1;
int fd = add_file_to_fdt(fileobj);
// current thare의 fdt에서 파일 오픈할 장소를 찾고, 파일 넣은 후, 해당 위치를 가리키는 fd 리턴 받음
// add_file_to_fdt(): 현재 실행 스레드의 FDT(file descriptor table)의 비어있는 인덱스에 파일 할당
// return cur-> fdIdx (이게 fd(int형)를 의미함)
// FD table full
if (fd == -1)
file_close(fileobj);
return fd;
}
: 열려있는 파일의 크기(bytes) 반환
int filesize(int fd)
{
struct file *fileobj = find_file_by_fd(fd);
// find_file_by_fd(fd): Check if given fd is valid, return cur->fdTable[fd]
// 현재 실행 스레드의 fdt에서 fd번째 파일 찾기
if (fileobj == NULL)
return -1;
return file_length(fileobj);
// file_length(fileobj) -> inode_length(file->inode) -> 'inode->data.length'
}
: 열린 파일의 위치를 position 크기만큼 이동
void seek(int fd, unsigned position)
{
struct file *fileobj = find_file_by_fd(fd);
if (fileobj <= 2)
// 프로세스는 이미 3개의 파일을 열어놓은 상태이므로(STDIN, STDOUT, ERROR)..?
return;
fileobj->pos = position; // 주어진 position 값으로 pos 값 갱신
}
: 현재 파일의 position 반환
unsigned tell(int fd)
{
struct file *fileobj = find_file_by_fd(fd);
if (fileobj <= 2)
return;
return file_tell(fileobj); // find_tell()은 file->pos을 반환
}
: file에서 buffer로 read한 size bytes 반환
int read(int fd, void *buffer, unsigned size)
{
check_address(buffer);
int ret;
struct thread *cur = thread_current();
struct file *fileobj = find_file_by_fd(fd);
if (fileobj == NULL)
return -1;
if (fileobj == STDIN)
{
if (cur->stdin_count == 0) // STDIN인데, stdin_count가 0이면
{
// Not reachable
NOT_REACHED();
remove_file_from_fdt(fd);
//remove_file_from_fdt() : cur->fdTable[fd] = NULL 처리하고, 아무것도 리턴하지 않음
ret = -1;
}
else // STDIN인데, stdin_count가 있으면 키보드로 입력받은 문자 글자 수(bytes) 반환
{
int i;
unsigned char *buf = buffer;
for (i = 0; i < size; i++)
{
char c = input_getc(); //키보드로 입력받은 문자를 반환
*buf++ = c;
if (c == '\0')
break;
}
ret = i;
}
}
else if (fileobj == STDOUT) // STDOUT이면, -1 반환 처리
{
ret = -1;
}
// 파일에서 read하는 경우
else
{
// 읽는 동안 lock을 통해 동시접근 방지
lock_acquire(&file_rw_lock);
ret = file_read(fileobj, buffer, size); // file_read()는 bytes_read 리턴함
lock_release(&file_rw_lock);
}
return ret;
}
: buffer에서 file로 write한 size bytes 반환
int write(int fd, const void *buffer, unsigned size)
{
check_address(buffer); // buffer의 주소 유효성 검사
int ret;
struct file *fileobj = find_file_by_fd(fd);
if (fileobj == NULL)
return -1;
struct thread *cur = thread_current();
if (fileobj == STDOUT)
{
if (cur->stdout_count == 0) //STDOUT 상태이고, stdout_count가 0이면
{
// Not reachable
NOT_REACHED();
remove_file_from_fdt(fd);
ret = -1;
}
else //STDOUT 상태이고, stdout_count가 있으면
{
putbuf(buffer, size); // 문자열을 화면에 출력해주는 함수
// buffer에서 open file fd로 size만큼 write
ret = size;
}
}
else if (fileobj == STDIN)
{
ret = -1;
}
else
{
lock_acquire(&file_rw_lock);
ret = file_write(fileobj, buffer, size);
// file_write()는 bytes_written 리턴함
// file_write() -> inode_write_at() -> inode->deny_write_cnt가 하나라도 있으면 return 0
lock_release(&file_rw_lock);
}
return ret;
}
: 파일 fd close
void close(int fd)
{
struct file *fileobj = find_file_by_fd(fd); //fd로 해당 파일 찾기
if (fileobj == NULL)
return;
struct thread *cur = thread_current();
if (fd == 0 || fileobj == STDIN) // STDIN는 stdin_count--
{
cur->stdin_count--;
}
else if (fd == 1 || fileobj == STDOUT) // STDOUT는 stdin_count++
{
cur->stdout_count--;
}
remove_file_from_fdt(fd); //fdTable 안에 fd 번째에 있는 주소값을 NULL로 갈음
if (fd <= 1 || fileobj <= 2)
return;
if (fileobj->dupCount == 0) // 해당 파일과 연결되어 있는 fd의 개수가 0개면, close
file_close(fileobj);
else
fileobj->dupCount--;
}