본문 바로가기
Review/SW Jungle

[WEEK10] Pintos _ Project2 User Program (2) System Calls

by jamiehun 2022. 11. 29.

1. 프로젝트 관련 공부

Pintos Project2

 

Pintos에서 User Program을 실행시켜라!

(Argument Passing, System Calls 등)

 

우리 과제는 프로그램을 실행시키기 위해서 아래와 같은 항목들의 일부를 수행하는 것으로 보인다.


2. 코드 구현 

우리조는 조금 더 구현이 쉬울 것 같은 File Descriptor 부분을 먼저 수행하고 fork, exec, wait으로 넘어갔다.

 

두번째 미션 : System Calls

관련함수 : create, remove, open, filesize, read, write, seek, tell, close 등

 

Pintos에는 File Descriptor 부분이 누락되어 있다.

File Descriptor Table을 구현하고 FD를 활용하여 파일 열기, 닫기 등을 구현해야한다.

 

(해당 파트는 이미 구현되어 있는 함수를 가져다 쓰는 경우가 많았다.

어려웠던 점은 각종 예외처리나 lock을 걸고 푸는 부분이 꽤나 생각을 요했던 것 같다.

팀원들과 수많은 의논과 코드 구현을 해본 후 해당 내용도 Pass!)

 

아래의 내용에서는 thread 구조체 변경과 시스템콜 switch 문은 따로 다루지 않음

 

 

 

1) check_address

: 주소가 유효한 주소값인지 찾는 함수

 

void 
check_address(void *addr)
{
	struct thread *t = thread_current();

	/* Method 1: 
	 * Verify the validity of a user-provided pointer.
	 * The simplest way to handle user memory access.
	 * Use the functions in ‘userprog/pagedir.c’ and in ‘threads/vaddr.h’
     */

	/* User can pass invalid pointers through the systemcall
	 * 1) A pointer to kernel virtual memory address space (above PHYS_BASE)
	 * 2) A null pointer
	 * 3) A pointer to unmapped virtual memory
	 */
	if ((is_user_vaddr(addr) == false) || (addr == NULL) || (pml4_get_page (t->pml4, addr) == NULL))
		exit(-1);
}

 

 

2) halt

: Terminates Pintos by calling power_off()

 

/* System Call 0 : Halt */
void
halt (void){
	power_off();
}

 

 

3) exit

 

/* System Call 1 : Create */
void
exit (int status){
	struct thread *cur = thread_current();
	cur->process_exit_status=status;
	printf("%s: exit(%d)\n", cur->name, status); // 한양대 기준
	thread_exit(); 
}

 

 

4) create

 

/* System Call 5 : Create */
bool create(const char *file, unsigned initial_size){
	check_address(file);
	bool success = filesys_create(file, initial_size);
	return success;
}

 

 

5) remove

 

/* Deletes the file named NAME.
 * Returns true if successful, false on failure.
 * Fails if no file named NAME exists,
 * or if an internal memory allocation fails. */
bool
filesys_remove (const char *name) {
	struct dir *dir = dir_open_root ();
	bool success = dir != NULL && dir_remove (dir, name);
	dir_close (dir);

	return success;
}

 

 

6) open

- 이 부분은 예외처리가 꽤 힘들었고, 예외처리에 따른 lock aquire와 release를 어디에 해줘야할지 한참 헤메었던것 같다.

- print를 찍어보거나 테스트케이스를 개별로 찍어보며 디버깅을 수행했다.

 

/* System Call 7 : Open */
int open(const char *file) {
	struct thread *cur = thread_current();

	check_address(file);

	if (lock_held_by_current_thread(&filesys_lock))
		return -1;
	
	while (cur->fdt[cur->fd_idx] && cur->fd_idx < FDCOUNT_LIMIT) {
		cur->fd_idx++;
	}
	
	if (cur->fd_idx >= FDCOUNT_LIMIT)
		return -1;
	
	lock_acquire(&filesys_lock);
	
	cur->fdt[cur->fd_idx] = filesys_open(file);

	if (cur->fdt[cur->fd_idx] == NULL)
		return -1;

	lock_release(&filesys_lock);

	return cur->fd_idx;
}

 

 

7) filesize

 

/* System Call 8 : Filesize */
int filesize (int fd)
{
	int file_len;
	struct file * temp;

	temp = process_get_file(fd);

	if (temp == NULL)
		return -1;

	file_len = file_length(temp);

	return file_len;
}

 

 

8) read

- 이 부분도 위의 open과 비슷한 문제점을 겪었다. 다행히도 이미 구현된 함수를 쓰는 부분이 많아 통과할 수 있었다.

 

/* System Call 10 : Read */
int read (int fd, void* buffer, unsigned size)
{
	struct file * temp;
	off_t byte;
	check_address(buffer);
	check_address(buffer+size-1);
	temp=process_get_file(fd);

	if (fd == 1 || fd < 0 ){
		return -1;
	}
	else if (fd == 0){
		lock_acquire(&filesys_lock);
		int saved_size;
		if (size==0) return 0;
		for (saved_size=0; saved_size<size; saved_size++){
			*(uint8_t*)buffer=input_getc();
			buffer++;
		}
		lock_release(&filesys_lock);
		return saved_size;
	}
	else{
		lock_acquire(&filesys_lock);
		if (temp==NULL){
			lock_release(&filesys_lock);
			// exit(0);
			return 0;
		}
		else{
			byte=file_read(temp,buffer,size);
			if (byte==0){
				lock_release(&filesys_lock);
				return 0;
			} 
			lock_release(&filesys_lock);
			return byte;
		}
	}
}

 

 

9) write

- 예외처리와 check address!

 

/* System Call 10 : Write */
int write(int fd, const void *buffer, unsigned size)
{	
	struct file * temp;
	off_t byte;
	check_address(buffer);
	check_address(buffer+size-1);

	temp=process_get_file(fd);
	
	if (fd < 0){
		return -1;
	}

	else if (fd == 1){
		putbuf(buffer, size);	
		return size;
	}

	else if (fd == 0){
		return 0;
	}

	else {
		if (temp==NULL){
			// printf("====%d====", temp);
			return 0;
		}		
		else{
			lock_acquire(&filesys_lock);
			byte=file_write(temp,buffer,size);
			if (byte==0){
				lock_release(&filesys_lock);
				return 0;
				}
			lock_release(&filesys_lock);
			return byte;
		}
	}
}

 

 

10) seek, tell, close

 

/* System Call 11 : Seek */
void seek (int fd, unsigned position){
	struct file * temp;
	temp=process_get_file(fd);
	file_seek(temp,position);
}

/* System Call 12 : Tell */
unsigned tell (int fd){
	struct file * temp;
	temp=process_get_file(fd);
	return file_tell(temp)?file_tell(temp):-1;
}

/* System Call 13 : Close */
void close (int fd){
	struct file * temp;
	struct thread *cur = thread_current();
	
	if (fd < 0) {
		return;
	}

	temp=process_get_file(fd);
	

	lock_acquire(&filesys_lock);
	file_close(temp);

	cur->fdt[fd] = 0;
	lock_release(&filesys_lock);
}