ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Project2 : SystemCall
    OS/Pintos 2022. 1. 11. 00:05

    Systemcall

    시스템콜 ?

    사용자 프로세스가 디스크 읽기와 같은 명령어를 실행하려면 어떻게 해야 할까? 이 때 필요한 것이 **시스템 콜(System call)**이다.

    시스템 콜은 운영체제가 제공하는 서비스에 대한 프로그래밍 인터페이스로, 사용자 모드 프로그램이 커널 기능을 사용할 수 있도록 한다. 시스템 콜은 커널 모드에서 실행되며, 실행이 끝나면 다시 사용자 모드로 복귀된다.

    Implement system call infrastructure.

    Implement the system call handler in userprog/syscall.c.

    어떠userprog/syscall.c에 시스템 콜 핸들러를 구현하자.

    • 스켈레톤 코드에서는 프로세스를 종료하여 시스템 콜을 처리한다.
    • 시스템 콜 번호를 얻고, 시스템 콜 인자를 얻어서 적절한 작업을 수행하자.

    현재 userprog/syscall.c에 구현되어 있는 syscall_handler( ) 함수는 골격만 있다.

    해당 함수를 수정하여 각각의 시스템 콜에 알맞은 처리 작업을 수행할 수 있도록 해야 한다.

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

    System Call Details

    x86과는 다르게 x86_64 시스템에서는 syscall이라는 특별한 명령어를 제공한다. syscall 명령어는 시스템 콜 핸들러를 부를 수 있는 가장 빠른 방법이다.

    사용자 프로그램은 syscall 명령어를 통해 시스템 콜을 보낼 수 있다. 이 때 다른 함수들을 호출할 때와 비슷하게 인자들과 리턴값이 레지스터에 저장되는데, 딱 두 가지가 다르다.

    • %rax에는 시스템 콜 넘버가 저장된다(보통의 함수라면 이 자리에 callee의 반환값을 저장한다).
    • 4번째 인자는 %rcx가 아닌 **%r10에** 저장된다(원래 보통의 함수라면 %rdi, %rsi, %rdx, %rcx, %r8 그리고 %r9에 저장된다).
      • %rdi, %rsi, %rdx, %r10, %r8 , %r9

    시스템 콜을 부른 사용자 함수의 레지스터 값은 struct intr_frame에서 확인할 수 있다.

     

    Implement the following system calls

    • 시스템 콜 번호는 include/lib/syscall-nr.h 에 정의되어있음

    이제 본격적으로 시스템 콜 핸들러를 구현해보도록 하자. 시스템 콜이 호출되면 어떤 시스템 콜인지에 따라 다른 작업이 수행되어야 한다.

    따라서 시스템 콜 핸들러의 인자로 전달된 inter_frame의 f->R.rax를 통해 확인할 수 있다. switch 문에 이를 넣어서 조건별로 알맞은

    시스템 콜이 호출될 수 있도록 설정해주자. 가장 먼저 구현할 시스템 콜은 SYS_HALT이다.

     

    halt

    • src/include/threads/init.h
    • 위의 경로에 정의되어있음.
    • 거의 사용되지 않는다.
    • 아래 요구 조건에 따라 halt( ) 함수를 구현하면 되는데 power_off( ) 함수를 호출할 수 있도록 작성하면 된다.
    • power_off( ) 함수를 사용하기 위해서 threads/init.h를 추가해야 한다.
      • Terminates Pintos by calling power_off( )(declared in src/include/threads/init.h).
    • /* userprog/syscall.c */
      
      #include "threads/init.h"
      
      /*--------------- PROJECT2: User Programs ----------------*/
      /* The main system call interface */
      void syscall_handler(struct intr_frame *f UNUSED){
      	// TODO: Your implementation goes here.
      
      	switch (f->R.rax){
      		case SYS_HALT:
      			halt();
      			break;
      		default:
      			exit(-1);
      			break;
      		}
      }
      
      void halt(void){
      	power_off();
      }

    create

    • 성공하면 true반환, 아니면 false반환
    • 파일 생성은 파일을 열지는 않는다.
      • 여는 것은 open system call에서 담당한다.
    • file : 생성할 파일의 이름 및 경로 정보
    • initial_size : 생성할 파일의 크기

    그런데 create( )함수 인자로 넘어오는 주소가 올바른 값인지 확인할 필요가 있다.

    이를 위해 check_address( )라는 함수를 추가로 구현해야 한다.

    check_address( ) : 확인할 주소가 NULL 포인터이거나 유저 어드레스가 아니거나, 할당되지 않은 주소인 경우 프로세스를 종료하는 함수이다.

    Q. create 와 remove의 인자가 몇개인지 어떻게 알지?

    A. syscall.h에 몇개를 받는지 정의되어있음.

    /* userprog/syscall.c */
    
    // 중략
    
    #include "filesys/filesys.h"
    
    /*--------------- PROJECT2: User Programs ----------------*/
    void syscall_handler(struct intr_frame *f UNUSED){
    	// TODO: Your implementation goes here.
        
    	switch (f->R.rax){
        
        		// 중략
            
    		case SYS_CREATE:
    			f->R.rax = create(f->R.rdi, f->R.rsi);
    			break;
    		case SYS_REMOVE:
    			f->R.rax = remove(f->R.rdi);
    			break;
    		default:
    			exit(-1);
    			break;
    		}
    }
    
    
    void check_address(const uint64_t *uaddr){
    	struct thread *cur = thread_current();
    	if (uaddr == NULL || !(is_user_vaddr(uaddr)) || pml4_get_page(cur->pml4, uaddr) == NULL){
    		exit(-1);
    	}
    }
    
    
    bool create(const char *file, unsigned initial_size){
    	check_address(file);
    	return filesys_create(file, initial_size);
    }

    remove

    • 성공하면 true반환, 아니면 false반환
    • 파일은 열리고 닫히는 여부와 관계없이 제거될 수 있고, 열린 파일을 제거해도 파일이 닫히지 않는다.
    • bool remove(const char *file){
      	check_address(file);
      	return filesys_remove(file);
      }

    exit

    • exit( )함수는 내부에서 thread_exit( ) 함수를 호출하고 바로 다시 process_exit( ) 함수를 호출한다.
    • process_exit( ) 함수에서는 palloc_free_multiple( ), file_close( ), process_cleanup( ) 등을 수행한다.
    • 이를 통해 메모리 누수 방지, 사용하던 자원 반납 등을 진행함으로써 프로그램을 종료한다.
    • /* userprog/syscall.c */
      
      /*--------------- PROJECT2: User Programs ----------------*/
      void exit(int status){
      	struct thread *cur = thread_current();
      	cur->exit_status = status;
      
      	printf("%s: exit(%d)\n", thread_name(), status);
      
      	thread_exit();
      }
      
      
      /* userprog/process.c */
      
      void thread_exit (void) {
      	ASSERT (!intr_context ());
      
      #ifdef USERPROG
      	process_exit ();
      #endif
      	/*--------------- PROJECT2: User Programs ----------------*/
      	list_remove(&thread_current()->allelem);
      
      	/* Just set our status to dying and schedule another process.
      	   We will be destroyed during the call to schedule_tail(). */
      	intr_disable ();
      	do_schedule (THREAD_DYING);
      	NOT_REACHED ();
      }
      
      
      void process_exit (void) {
      	struct thread *curr = thread_current ();
      	/* TODO: Your code goes here.
      	 * TODO: Implement process termination message (see
      	 * TODO: project2/process_termination.html).
      	 * TODO: We recommend you to implement process resource cleanup here. */
      
      	/*--------------- PROJECT2: User Programs ----------------*/
      	for (int i = 0; i < FDCOUNT_LIMIT; i++){
      		close(i);
      	}
      
      	palloc_free_multiple(curr->fdTable, FDT_PAGES); 
      
      	file_close(curr->running);
      
      	process_cleanup ();
      
      	sema_up(&curr->wait_sema);
      	
      	sema_down(&curr->free_sema);
      }

    fork

    fork( ) 함수는 내부에서 process_fork( ) 함수를 호출하며, 이때 인자로 thread_name과 Interrupt stack frame f를 전달한다.

    process_fork( ) 함수는 내부에서 다양한 함수들을 호출하는데, 

    우선, memcpy( ) 함수를 호출하여 해당 함수의 두 번째 인자(if_)의 값을 첫 번째 인자(&cur->parent_if)로 복사한다.

    fork( ) 함수가 자식 프로세스를 생성하는 과정으로 이해한다면,

    이는 자식 프로세스 생성에 앞서 부모 프로세스의 내용을 memcpy 하는 과정으로 이해할 수 있다.

     

    memcpy( ) 이후, thread_create( ) 함수를 진행하고, 해당 함수의 리턴 값을 tid에 저장한다.

    thread_create( ) 함수의 인자로는 fork( ) 함수의 인자로 받았던 thread_name과, __do_fork( ) 함수, 현재 스레드 등이 들어간다.

    __do_fork( ) 함수를 요약하자면 부모 프로세스의 내용을 자식 프로세스로 복사하는 과정이라고 할 수 있다.

    이는 memcpy( ) 함수와 반복문, do_iret( ) 함수 등을 통해 이루어진다.

     

    process_fork( ) 과정에서 semaphore가 등장한다는 것이다.

    자세히 설명하자면, 부모 프로세스는 thread_create( ) 함수의 리턴으로 받은 tid를 갖고 자식 프로세스를 찾는다.

    이후, 해당 자식의 fork_sema를 sema_down( ) 한다.

    이러한 과정은 자식 프로세스의 정상적인 로드를 위한 것으로,

    자식 프로세스는 __do_fork( ) 함수를 통해 부모 프로세스의 정보를 모두 복사한 이후 sema_up( )을 호출한다. 

    /* userprog/syscall.c */
    
    /*--------------- PROJECT2: User Programs ----------------*/
    tid_t fork(const char *thread_name, struct intr_frame *f){
    	return process_fork(thread_name, f);
    }
    
    
    /* userprog/process.c */
    
    tid_t process_fork (const char *name, struct intr_frame *if_ UNUSED) {
    	/* Clone current thread to new thread.*/
    	struct thread *cur = thread_current();
    	memcpy(&cur->parent_if, if_, sizeof(struct intr_frame)); // 부모 프로세스 memcpy 
    
    	tid_t tid = thread_create(name, PRI_DEFAULT, __do_fork, cur); // 전달받은 thread_name으로 __do_fork() 진행 
    	
    	if (tid == TID_ERROR)
    		return TID_ERROR;
    
    	struct thread *child = get_child_with_pid(tid); // get_child_with_pid 함수 실행
    	sema_down(&child->fork_sema); // child load 대기
    	if (child -> exit_status == -1)
    		return TID_ERROR;
    
    	return tid;
    }
    
    
    static void __do_fork (void *aux) {
    	struct intr_frame if_;
    	struct thread *parent = (struct thread *) aux;
    	struct thread *current = thread_current ();
    	/* TODO: somehow pass the parent_if. (i.e. process_fork()'s if_) */
    	
    	/*--------------- PROJECT2: User Programs ----------------*/
    	struct intr_frame *parent_if;
    	parent_if = &parent->parent_if;
    	bool succ = true;
    
    	/* 1. Read the cpu context to local stack. */
    	memcpy (&if_, parent_if, sizeof (struct intr_frame));
    	if_.R.rax = 0; 
    
    	/* 2. Duplicate PT */
    	current->pml4 = pml4_create();
    	if (current->pml4 == NULL)
    		goto error;
    
    	process_activate (current); 
    
    #ifdef VM
    	supplemental_page_table_init (&current->spt);
    	if (!supplemental_page_table_copy (&current->spt, &parent->spt))
    		goto error;
    #else
    	if (!pml4_for_each (parent->pml4, duplicate_pte, parent))
    		goto error;
    #endif
    
    	/* TODO: Your code goes here.
    	 * TODO: Hint) To duplicate the file object, use `file_duplicate`
    	 * TODO:       in include/filesys/file.h. Note that parent should not return
    	 * TODO:       from the fork() until this function successfully duplicates
    	 * TODO:       the resources of parent.*/
    
    	if (parent->fdIdx == FDCOUNT_LIMIT)
    		goto error;
    
    	/*--------------- PROJECT2: User Programs ----------------*/
    	for (int i = 0; i < FDCOUNT_LIMIT; i++) {
    		struct file *file = parent->fdTable[i];
    		if (file == NULL)
    			continue;
    
    		// If 'file' is already duplicated in child, don't duplicate again but share it
    		bool found = false;
    		if (!found) {
    			struct file *new_file;
    			if (file > 2)
    				new_file = file_duplicate(file);
    			else
    				new_file = file;
    
    			current->fdTable[i] = new_file;
    		}
    	}
    
    	current->fdIdx = parent->fdIdx;
    
    	sema_up(&current->fork_sema); // child load 완료 시
    
    	/* Finally, switch to the newly created process. */
    	if (succ)
    		do_iret (&if_);
    error:
    	current->exit_status = TID_ERROR;
    	sema_up(&current->fork_sema);
    	exit(TID_ERROR);
    }
    
    
    /*--------------- PROJECT2: User Programs ----------------*/
    struct thread *get_child_with_pid(int pid) {
    	struct thread *cur = thread_current();
    	struct list *child_list = &cur->child_list;
    
    	for (struct list_elem *e = list_begin(child_list); e != list_end(child_list); e = list_next(e))
    	{
    		struct thread *t = list_entry(e, struct thread, child_elem);
    		if (t->tid == pid)
    			return t;
    	}	
    	return NULL;
    }

    exec

    • exec(): 자식 프로세스를 생성하고 프로그램을 실행시키는 시스템 콜, 현재 프로세스를 명령어로 입력받은 실행가능 파일로 변경하는 함수이다.
    • cmd_line으로 주어진 이름을 가진 실행 파일로 현재 프로세스를 바꾸고 지정된 인자를 전달한다.
    • 성공하는 경우 반환하지 않는다.
    • 프로그램이 모종의 이유로 로드되지 못하는 경우 -1의 상태로 프로세스를 종료한다.
    • 이 함수는 exec를 호출한 스레드의 이름을 바꾸지 않는다.
    • file descriptor는 Exec호출 도중에 열려 있음을 유의하자.
    • 가장 먼저 인자로 받은 file_name 주소의 유효성을 확인한다
    • 이후, palloc_get_page( ) 함수와 strlcpy( ) 함수를 이용하여 file_name을 fn_copy로 복사한다.
    • 마지막으로 process_exec( ) 함수를 호출하여 해당 fn_copy를 이용하여 프로세스를 로드하고, 해당 정보를 스택에 쌓아준다.
    •  
    • /* userprog/syscall.c */ /*--------------- PROJECT2: User Programs ----------------*/ int exec(char *file_name){ check_address(file_name); int siz = strlen(file_name) + 1; char *fn_copy = palloc_get_page(PAL_ZERO); if (fn_copy == NULL) exit(-1); strlcpy(fn_copy, file_name, siz); if (process_exec(fn_copy) == -1) return -1; NOT_REACHED(); return 0; }

     

    wait

      • wait( ) 함수는 내부에서 process_wait( ) 함수를 호출한다.
      • 이때 인자로 전달하는 것은 자식 프로세스의 ID이다.
      • 해당 ID를 이용하여 process_wait( ) 함수 내부에서 get_child_with_pid( ) 함수를 호출하며, 이를 통해 자식 프로세스 구조체를 찾는다.
        • 이후, 자식 프로세스의 wait_sema를 sema_down( )한다.
        • 해당 semaphore는 자식 프로세스가 process_exit( )를 호출할 때 sema_up( )이 이루어진다. (즉, 자식 프로세스가 작업을 모두 마칠 때까지 기다린다는 의미라고 할 수 있다.)
        • 작업을 마친 자식 프로세스를 자식 리스트에서 삭제 해주고, 자식 프로세스의 free_sema를 sema_up( ) 한다.
        • 이 free_sema 역시, process_exit( ) 과정에서 자식 프로세스가 sema_down( ) 한 것을 변경해주는 것이다.
        • /* userprog/syscall.c */
          
          /*--------------- PROJECT2: User Programs ----------------*/
          int wait (tid_t pid){
          	process_wait(pid);
          };
          
          
          /* userprog/process.c */
          
          int process_wait (tid_t child_tid UNUSED) {
          	/* XXX: Hint) The pintos exit if process_wait (initd), we recommend you
          	 * XXX:       to add infinite loop here before
          	 * XXX:       implementing the process_wait. */
          
          	struct thread *cur = thread_current();
          	struct thread *child = get_child_with_pid(child_tid);
          
          	if (child == NULL)
          		return -1;
          	
          	sema_down(&child->wait_sema); 
          	int exit_status = child->exit_status;
          	list_remove(&child->child_elem);
          	sema_up(&child->free_sema);
          
          	return exit_status;
          }

    open

    • file이 가리키는 문자열 이름의 파일을 연다.
      • 파일 디스크립터(fd)또는 -1을 반환한다.
      • 파일 디스크립터 0과 1은 콘솔이 미리 예약해두었다.
        • STDIN_FILENO(0)
        • STDOUT_FILENO(1)
    • 각각의 프로세스는 독립적인 파일 디스크립터들을 가진다.
    • 파일 디스크립터는 자식에게 상속된다.
    • 동일한 파일이 여러번 열리는 경우 각각은 새로운 파일 디스크립터를 갖는다.
    • 한 파일에 대한 서로 다른 파일 디스크립터는 독립적으로 다루어져야 한다.
    • filesys_open( ) 함수를 이용하여 파일 객체를 생성하도록 하면 된다.
    • 파일 디스크립터 테이블이란 프로세스가 현재 사용 중인 파일을 관리하기 위한 테이블로, 프로세스마다 하나씩 가지고 있다.
    • 그런데 이는 이전 프로젝트에서 사용하지 않았던 것이다. 따라서 thread 구조체에 새롭게 추가해주어야 한다
    • thread 구조체에 fdTable과 해당 테이블을 인덱싱할 때 사용하기 위한 fdIdx를 선언하자.
    • 마지막으로 thread를 생성할 때, 해당 파일 디스크립터 테이블과 각종 정보들을 초기화할 수 있도록 tread_create( ) 함수를 수정한다.
    •  
    • /* userprog/syscall.c */ /*--------------- PROJECT2: User Programs ----------------*/ int open(const char *file){ check_address(file); struct file *fileobj = filesys_open(file); if (fileobj == NULL) return -1; int fd = add_file_to_fdt(fileobj); if (fd == -1) file_close(fileobj); return fd; } int add_file_to_fdt(struct file *file){ struct thread *cur = thread_current(); struct file **fdt = cur->fdTable; // file descriptor table if (cur->fdIdx >= FDCOUNT_LIMIT) return -1; fdt[cur->fdIdx] = file; return cur->fdIdx; } /* threads/thread.h */ struct thread { // 중략 struct file **fdTable; int fdIdx; // 중략 }; /* threads/thread.c */ tid_t thread_create (const char *name, int priority,thread_func *function, void *aux) { // 중략 /*--------------- PROJECT2: User Programs ----------------*/ t->fdTable = palloc_get_multiple(PAL_ZERO, FDT_PAGES); if (t->fdTable == NULL) return TID_ERROR; t->fdIdx = 2; // 0: stdin, 1: stdout t->fdTable[0] = 1; // dummy values to distinguish fd 0 and 1 from NULL t->fdTable[1] = 2; t->stdin_count = 1; t->stdout_count = 1; // 중략 }

    filesize

    • 파일 사이즈를 알기 위해서는 fd가 아닌 파일이 필요하다.
    • 입력받은 fd를 이용하여 파일을 찾는 함수 find_file_by_fd( )를 구현해보자.
    • 해당 함수를 통해 파일을 구한 이후에는 file_length( ) 함수를 이용하여 사이즈를 리턴하면 된다.
    • /* userprog/syscall.c */
      
      /*--------------- PROJECT2: User Programs ----------------*/
      int filesize(int fd){
      	struct file *fileobj = find_file_by_fd(fd);
      	if (fileobj == NULL)
      		return -1;
      	return file_length(fileobj);
      }
      
      
      static struct file *find_file_by_fd(int fd){
      	struct thread *cur = thread_current();
      
      	if (fd < 0 || fd >= FDCOUNT_LIMIT)
      		return NULL;
      
      	return cur->fdTable[fd]; // automatically returns NULL if empty
      }

    read

      • read( ) 함수는 인자로 fd, buffer, size를 받는다. buffer가 유효한 주소인지 check_address( ) 함수를 통해 확인한다. 이후, fd를 이용하여 파일 객체를 찾는다.
      • 요구 조건에서 fd가 0인 경우, input_getc( ) 함수를 이용하여 키보드 입력을 읽어오라고 하였다.
      • 따라서 해당 조건을 구현해주고, 그렇지 않은 경우 file_read( ) 함수를 이용하여 파일을 buffer에 size 크기만큼 읽어온다.
      • 이때, 락(lock)을 이용하여 파일을 읽어올 때, 다른 접근을 막아야 한다. 그렇지 않으면 의도와 다른 결과가 발생할 수 있다. (락을 사용하기 위해 해당 구조체를 userprog/syscall.h에 선언해주어야 한다.)
      • syscall_init( ) 함수에도 lock_init( ) 함수를 추가해주어야 한다.
      • /* userprog/syscall.c */
        
        /*--------------- PROJECT2: User Programs ----------------*/
        void syscall_init(void){
        
        	// 중략
            
        	lock_init(&file_rw_lock);
        }
        
        int read(int fd, void *buffer, unsigned size){
        	check_address(buffer);
        	int read_count;
        	struct thread *cur = thread_current();
        
        	struct file *fileobj = find_file_by_fd(fd);
        	if (fileobj == NULL)
        		return -1;
        
        	if (fileobj == STDIN){
        		int i;
        		unsigned char *buf = buffer;
        		for (i = 0; i < size; i++)
        		{
        			char c = input_getc();
        			*buf++ = c;
        			if (c == '\0')
        				break;
        		}
        		read_count = i;
        	} 
        	else if (fileobj == STDOUT){
        		read_count = -1;
        	}
        	else{
        		lock_acquire(&file_rw_lock);
        		read_count = file_read(fileobj, buffer, size);
        		lock_release(&file_rw_lock);
        	}
        	return read_count;
        }
        
        
        /* userprog/syscall.h */
        
        struct lock file_rw_lock;

    write

    • 해당 함수는 인자로 fd, buffer, size를 받는다.
    • read( ) 함수와 마찬가지로 buffer의 주소값을 확인해주고, fd를 이용하여 파일 객체를 찾는다.
    • 파일 객체의 값이 STDOUT과 같으면 putbuf( ) 함수를 이용하여 버퍼에 있는 값을 사이즈 만큼 화면에 출력해준다.
    • 그렇지 않다면, 파일 객체에 버퍼에 있는 값을 사이즈 만큼 적어준다.
    • 이때도 락을 이용하여 파일에 대한 동시 접근을 제한해야 한다.
    • /* userprog/syscall.c */
      
      /*--------------- PROJECT2: User Programs ----------------*/
      int write(int fd, const void *buffer, unsigned size){
      	check_address(buffer);
      	int read_count;
      
      	struct file *fileobj = find_file_by_fd(fd);
      	if (fileobj == NULL)
      		return -1;
      
      	struct thread *cur = thread_current();
      
      	if (fileobj == STDOUT){
      		putbuf(buffer, size);
      		read_count = size;
      
      	}
      	else if (fileobj == STDIN){
      		read_count = -1;
      	}
      	else{
      		lock_acquire(&file_rw_lock);
      		read_count = file_write(fileobj, buffer, size);
      		lock_release(&file_rw_lock);
      	}
      
      	return read_count;
      }

    seek

      • seek( ) 함수의 경우, 인자로 fd와 position을 받는다.
      • fd를 이용하여 파일을 찾고, 해당 파일 객체의 pos를 입력 받은 position으로 변경한다.
      • /* userprog/syscall.c */
        
        /*--------------- PROJECT2: User Programs ----------------*/
        void seek(int fd, unsigned position){	
        	if (fd < 2)
        		return;
        	struct file *fileobj = find_file_by_fd(fd);
        	if (fileobj == NULL) 
        		return;
        	fileobj->pos = position;
        }

    tell

    • tell( ) 함수도 seek()함수와 유사하다. fd를 이용하여 파일을 찾고, file_tell( ) 함수에 해당 객체를 인자로 넣어 리턴한다.
    • /* userprog/syscall.c */
      
      /*--------------- PROJECT2: User Programs ----------------*/
      
      unsigned tell(int fd){
      	if (fd < 2)
      		return;
      	struct file *fileobj = find_file_by_fd(fd);
      	if (fileobj == NULL) 
      		return;
      	return file_tell(fileobj);
      }

    close

      • 파일을 닫는다는 것은 현재 프로세스의 파일 디스크립터 테이블에서 해당 fd를 제거한다는 의미이다.
      • 이를 위해 close( ) 함수 내에 remove_file_from_fdt( ) 함수를 호출해주었다
      • 해당 함수를 통해 현재 파일 디스크립터 테이블에서 fd를 인덱스로 하는 값을 NULL로 바꾸어주면 된다.
      • /* userprog/syscall.c */
        
        /*--------------- PROJECT2: User Programs ----------------*/
        void close(int fd){
        	struct file *fileobj = find_file_by_fd(fd);
        	if (fileobj == NULL)
            		return;
        
        	struct thread *cur = thread_current();
        
        	if (fd == 0 || fileobj == STDIN){
        		cur->stdin_count--;
        	}
        	else if (fd == 1 || fileobj == STDOUT){
        		cur->stdout_count--;
        	}
        
        	remove_file_from_fdt(fd);
        	if (fd < 2 || fileobj <= 2)
            		return;
        }
        
        
        void remove_file_from_fdt(int fd){
        	struct thread *cur = thread_current();
        
        	if (fd < 0 || fd >= FDCOUNT_LIMIT)
        		return;
        
        	cur->fdTable[fd] = NULL;

     

    참고블로그

    https://always-be-wise.tistory.com/164?category=1027194

    'OS > Pintos' 카테고리의 다른 글

    Project 1,2 정리  (0) 2022.01.11
    Pintos 프로젝트 시 도움받은 블로그들!  (0) 2022.01.11
    Project2 : Argument Passing  (0) 2022.01.10
    Project2: User Programs(introduction)  (0) 2022.01.10
    Project1 : Thread - Priority Scheduling(3)  (0) 2021.12.30

    댓글

Designed by Tistory.