[PINTOS PROJECT 2] SYSTEM CALL

zeo·2021년 10월 13일
0

1. halt()

: pintos 프로그램 종료

void halt(void)
{
	power_off();
}

2. exit()

: 현재 실행중인 스레드 종료

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() 
}

3. fork()

: 현재 스레드를 클론하여, 새로운 스레드 생성 성공시 새로운 스레드의 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;
}

4. exec()

: 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;
}

5. wait()

: 해당 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() 종료
}

6. create()

: 파일 생성

  • bool create(const char *file, unsigned initial_size)
// file은 생성할 파일의 이름 및 경로 정보, initial_size는 생성할 파일의 크기
bool create(const char *file, unsigned initial_size)
{
	check_address(file);
	return filesys_create(file, initial_size);
}
  • filesys_create() : inode 생성 및 초기화, root 디렉터리 엔트리에 파일명과 inode 블록 번호 추가
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;
}

7. remove()

: 파일 삭제

  • bool remove(const char *file)
bool remove(const char *file)
{
	check_address(file);
	return filesys_remove(file);
}
  • bool filesys_remove (const char *name)
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)
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;
}

8. open()

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;
}

9. filesize()

: 열려있는 파일의 크기(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'
}

10. seek()

: 열린 파일의 위치를 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 값 갱신
}

11. tell()

: 현재 파일의 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을 반환
}

12. read()

: 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;
}

13. write()

: 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;
}

14. close()

: 파일 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--;
}

0개의 댓글