[운체] 오늘의 삽질 - 0728

방법이있지·2025년 7월 28일
post-thumbnail

파일 시스템 콜

/* An open file. */
struct file {
	struct inode *inode;        /* File's inode. */
	off_t pos;                  /* Current position. */
	bool deny_write;            /* Has file_deny_write() been called? */
};
  • inode: 인덱스 노드. 보조기억장치에 파일이 저장된 블록 정보를 색인하는 용도.
  • pos: 현재 읽거나 쓸 위치.
  • deny_write: true일 시 쓰기 연산이 금지됨

파일 명시자 테이블

struct thread {
    // file 관련 시스템 콜에 필요
	struct file **fdt;			/* file descriptor 테이블 */
	int next_fd;				/* file descriptor - 다음은 몇번째? */
}

void process_init (void) {
	// [구현 11-1] fdt 초기화
	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);
}

파일 시스템 콜 종류

  • create: 새 파일이나 객체를 생성한다.
case SYS_CREATE:
	/* Create a file. */
	// [구현 9]	파일을 만든다.
	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:
	/* Delete a file. */
	// [구현 10] 파일을 삭제한다.
	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:
	/* Open a file. */
	// [구현 11-3] 파일 오픈 후 반한된 file 포인터를 fdt 테이블에 삽입한 뒤, 식별자 번호를 반환한다.
	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){
			// 파일 열기에 실패한 경우 -1 반환
			f -> R.rax = -1;
		} else {
			// 파일 열기에 성공한 경우 fdt에 포인터 삽입하기
			(thread_current() -> fdt)[set_fd] = opened_file;
			// 파일 식별자 반환
			f -> R.rax = set_fd;
			// 다음 파일 식별자 값 1 증가
			thread_current() -> next_fd = (set_fd + 1) % FD_LIMIT;
		}
	}
	lock_release(&filesys_lock);
	break;
  • filesize: 파일의 크기를 반환한다.
case SYS_FILESIZE:               
	/* Obtain a file's size. */
	// [구현 12] 파일 식별자에 대응되는 파일의 크기를 반환한다.
	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:  				
	/* Close a file. */
	// [구현 13] 파일을 닫는다. fdt에서 NULL로 바꿔준다.
	int close_fd = (int)(f -> R.rdi);
	// fdt에 할당된 범위의 fd만 닫을 수 있게 한다.
	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:                   
	/* Change position in a file. */
	// [구현 14] fd에서 읽을 다음 위치를 변경한다.
	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:                   
	/* Report current position in a file. */
	// [구현 15] fd에서 읽을 다음 위치를 반환한다.
	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); 
	// [구현 16-1] fd가 0일 땐 stdin, 키보드에서 읽는다
	if (read_fd == 0){
		// 이게 맞나?? 개선 필요.
		f -> R.rax = (int)input_getc();
	} else if (2 <= read_fd && read_fd <= 127) {
		// [구현 16-2] fd가 0이 아닐 땐 파일에서 읽는다
		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:
	/* Write to a file. */
	// [구현 4-1] fd가 1일 땐 콘솔창으로 출력한다
	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;
profile
뭔가 만드는 걸 좋아하는 개발자 지망생입니다. 프로야구단 LG 트윈스를 응원하고 있습니다.

0개의 댓글