본문 바로가기

KAIST PINTOS

syscall.c

시스템 콜을 짜기 전에 각 스레드는 자신의 파일 디스크립터 테이블을 가지고 있어야 한다. 이중 포인터로 thread 스트럭쳐에 필드를 추가해준다. 또한, exit 시스템콜을 위해서 exit 여부를 확인할 수 있는 필드와, exit_status도 선언해준다. 

bool is_exited;
int exit_status;

struct file** fd_table;
int index;

그리고 thread.c의 thread_create()에서 

     t -> fd_table = palloc_get_page(PAL_ZERO)

를 해준다. 스레드를 만들 때 palloc으로 할당을 해줬으니까 스레드가 죽을 때 free 해주면 될 것 같은데!

thread가 죽을 때는 thread_exit()을 호출하고, thread_exit에서는 ifdef USERPROG를 통해 process_exit()을 호출한다. 그러니까 process_exit() 내부에 일단 palloc_free_page(curr -> fd_table)을 써주자. 

 

handler를 짜줘야한다. 그러기 위해서는 system call function들을 syscall.h에 선언해줘야한다. 필요한 헤더들과 같이 선언해주자. 

#ifndef USERPROG_SYSCALL_H
#define USERPROG_SYSCALL_H

#include <stdbool.h>
#include <stdint.h>

#include "threads/thread.h"
#include "threads/synch.h"

typedef pid_t;

struct lock syscall_lock;

void syscall_init (void);

void sys_halt (void);
void exit (int status);
pid_t sys_fork(const char *thread_name, struct intr_frame* f);
int sys_exec (const char *cmd_line);
int sys_wait (pid_t pid);
bool sys_create (const char *file, unsigned initial_size);
bool sys_remove (const char *file);
int sys_open (const char *file);
int sys_filesize (int fd);
int sys_read (int fd, void *buffer, unsigned size);
int sys_write (int fd, const void *buffer, unsigned size);
void sys_seek (int fd, unsigned position);
unsigned sys_tell (int fd);
void sys_close (int fd);

int add_file(struct file *file);
void close_file(int fd);


#endif /* userprog/syscall.h */

syscall_lock은 syscall.c의 syscall_init에서 lock_init(&syscall_lock)을 해준다. 

syscall handler는 아래와 같다. sys_fork()를 아직 짜지 않았기 때문에 case SYS_FORK: 내부에는 break문만 써놓았다. 

printf("system call!\n")도 나중에 삭제해야될 수도 있다. 

void
syscall_handler (struct intr_frame *f UNUSED) {
	// TODO: Your implementation goes here.
	printf ("system call!\n");


	if (!is_user_vaddr(f -> rsp)){
		exit(-1);
	}

	switch(f -> R.rax){
		case SYS_HALT:
			sys_halt();
			break;

		case SYS_EXIT:
			//printf("sys_exit\n");
			exit(f->R.rdi);
			break;

		case SYS_FORK:
			//printf("sys_fork\n");
			// f->R.rax = sys_fork(f->R.rdi, f);
			break;

		case SYS_EXEC:
			//printf("sys_exec\n");
			f->R.rax = sys_exec(f->R.rdi);
			break;

		case SYS_WAIT:
			//printf("sys_wait\n");
			f->R.rax = sys_wait(f->R.rdi);
			break;

		case SYS_CREATE:
			//printf("sys_create\n");
			f->R.rax = sys_create(f->R.rdi, f->R.rsi);
			break;

		case SYS_REMOVE:
			//printf("sys_remove\n");
			f->R.rax = sys_remove(f->R.rdi);
			break;

		case SYS_OPEN:
			//printf("sys_open\n");
			f->R.rax = sys_open(f->R.rdi);
			break;

		case SYS_FILESIZE:
			//printf("sys_filesize\n");
			f->R.rax = sys_filesize(f->R.rdi);
			break;

		case SYS_READ:
			//printf("sys_read\n");
			f->R.rax = sys_read(f->R.rdi, f->R.rsi, f->R.rdx);
			break;

		case SYS_WRITE:
			//printf("sys_write\n");
			f->R.rax = sys_write(f->R.rdi, f->R.rsi, f->R.rdx);
			break;

		case SYS_SEEK:
			//printf("sys_seek\n");
			sys_seek(f->R.rdi, f->R.rsi);
			break;

		case SYS_TELL:
			//printf("sys_tell\n");
			f->R.rax = sys_tell(f->R.rdi);
			break;

		case SYS_CLOSE:
			//printf("sys_close\n");
			sys_close(f->R.rdi);
			break;

		default:
			thread_exit ();
			break;
    }
}

 

각각의 시스템콜 함수들은 아래와 같다. 

void sys_halt (void){
	power_off();
}


void exit (int status){
	printf("%s: exit(%d)\n", thread_name(), status);

	thread_current() -> is_exited = true;
	thread_current() -> exit_status = status;

	thread_exit();
}


int sys_exec (const char *cmd_line){
	if (!is_user_vaddr(cmd_line))
		exit(-1);

	if (&cmd_line == NULL)
		return -1;

	return process_exec(cmd_line);
}


int sys_wait (pid_t pid){
	if (pid == NULL)
		return -1;

	return process_wait(pid);
}


bool sys_create (const char *file, unsigned initial_size){
	if (file == NULL)
		return false;

	return filesys_create(file, initial_size);
}


bool sys_remove (const char *file){
	if (file == NULL)
		return false;
	
	return filesys_remove(file);
}


int sys_open (const char *file){
	if (!is_user_vaddr(file))
		exit(-1);

	if (file == NULL)
		exit(-1);

	lock_acquire(&syscall_lock);
	
	struct file *f = filesys_open(file);
	if (f == NULL){
		lock_release(&syscall_lock);
		return -1;
	}

	if (strcmp(file, thread_current() -> name) == 0){
		file_deny_write(f);
	}

	int result = add_file(f);

	lock_release(&syscall_lock);
	return result;
}


int sys_filesize (int fd){
	struct file *f = thread_current() -> fd_table[fd];
	if (f == NULL)
		return -1;

	return file_length(f);
}


int sys_read (int fd, void *buffer, unsigned size){
	int result = -1;
	if (fd < 0 || fd == 1)
		return result;
	
	lock_acquire(&syscall_lock);
	
	if (fd == 0){
		result = 0;

		for (int i = 0; i < size; i++){
			result ++;
			if (input_getc() == '\n') break;
		}
	}

	else{
		struct file *f = thread_current() -> fd_table[fd];
		if (f == NULL){
			lock_release(&syscall_lock);
			exit(-1);
		}

		result = file_read(f, buffer, size);
	}

	lock_release(&syscall_lock);
	return result;
}


int sys_write (int fd, const void *buffer, unsigned size){
	if (!is_user_vaddr(buffer))
		exit(-1);

	int result = 0;

	if (fd < 0)
		return -1;

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

	else {
		lock_acquire(&syscall_lock);

		struct file *f = thread_current() -> fd_table[fd];
		if (f == NULL){
			lock_release(&syscall_lock);
			return result;
		}

		result = file_write(f, buffer, size);
		lock_release(&syscall_lock);
	}

	return result;
}


void sys_seek (int fd, unsigned position){
	struct file *f = thread_current() -> fd_table[fd];
	if (f == NULL)
		return;

	file_seek(f, position);
}


unsigned sys_tell (int fd){
	struct file *f = thread_current() -> fd_table[fd];
	if (f == NULL)
		return -1;

	return file_tell(fd);
}


void sys_close (int fd){
	close_file(fd);
}


int add_file(struct file *file){
	struct thread *curr = thread_current();

	if (curr -> fd_table == NULL || curr -> index > 127){
		file_close(file);
		return -1;
	}

	curr -> fd_table[curr -> index] = file;
	curr -> index++;

	return curr -> index - 1;
} 

void close_file(int fd){
	struct thread *curr = thread_current();
	if (curr -> fd_table == NULL)
		exit(-1);

	if (fd < 2 || fd >= curr ->index) 
		return;

	file_close(curr -> fd_table[fd]);
	curr -> fd_table[fd] == NULL;
}

 

'KAIST PINTOS' 카테고리의 다른 글

argument passing  (0) 2022.02.13
Process.c  (0) 2022.02.13
Project 2 디버깅  (0) 2022.02.07
system call  (0) 2022.01.21
PROJECT 1 - Alarm Clock, Priority Scheduling  (0) 2022.01.20