[PintOS] Project 2 - User Programs 4

Quro·2024년 5월 25일
0

OS

목록 보기
3/6
post-thumbnail

System Calls 함수 설명

프로세스 관련 시스템 콜

halt()

👉 pintOS 자체를 종료
void halt(){
	power_off();
}

exit()

👉 현재 프로세스 종료하는 시스템 콜
void exit(int status){
	struct thread *curr = thread_current();
	curr->exit_status = status;
	printf("%s: exit(%d)\n", curr->name, status);
	thread_exit();
}
  • 종료 시 "프로세스 이름: exit(status)" 출력
  • thread 구조체에 exit_status 필드 추가
    • exit_status : 프로세스 종료 유무 확인
  • 정상적으로 종료 시 status : 04

fork()

👉 부모 프로세스로 부터 자식 프로세스를 복제
pid_t fork(const char *thread_name){
	check_address(thread_name);
	return process_fork(thread_name, f);
}
  • thread_name : 새로 생성될 자식 프로세스의 이름
    • 자식 프로세스에 부모 프로세스의 레지스터 값(%RBX ~ %R15)을 복사
  • f : 부모의 인터럽트 프레임
  • 반환값 : 생성된 자식 프로세스의 pid
  • 자식 프로세스는 부모 프로세스의 파일 디스크립터와 가상 메모리 공간을 복제해야한다
  • process_fork 함수 source code 및 해석
    tid_t
    process_fork (const char *name, struct intr_frame *if_ UNUSED) {
        /* Clone current thread to new thread.*/
    
        struct thread *curr = thread_current();
    
        memcpy(&curr->parent_if, if_, sizeof(struct intr_frame)); // 전달받은 intr_frame을 parent_if필드에 복사한다.
        // ↳ '__do_fork' 에서 자식 프로세스에 부모의 컨텍스트 정보를 복사하기 위함(부모의 인터럽트 프레임을 찾는 용도로 사용)
    
        tid_t tid = thread_create(name, PRI_DEFAULT, __do_fork, curr); // __do_fork를 실행하는 스레드 생성, 현재 스레드를 인자로 넘겨준다.
        if (tid == TID_ERROR)
            return TID_ERROR;
    
        struct thread *child = get_child_process(tid);
    
        sema_down(&child->fork_sema); // 자식 프로세스가 로드될 때까지 부모 프로세스는 대기한다.
        if (child->exit_status == TID_ERROR)
            return TID_ERROR;
    
        return tid; // 부모 프로세스의 리턴값 : 생성한 자식 프로세스의 tid
    }
  • __do_fork 함수 source code 및 해석
    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_) */
        struct intr_frame *parent_if;
        bool succ = true;
    
        parent_if = &parent->parent_if; // process_fork에서 복사 해두었던 intr_frame
        /* 1. Read the cpu context to local stack. */
        memcpy (&if_, parent_if, sizeof (struct intr_frame));
    
        if_.R.rax = 0; // fork 시스템 콜의 결과로 자식 프로세스는 0을 리턴해야하므로 0을 넣어준다.
    
        /* 2. Duplicate PT */
        current->pml4 = pml4_create(); // 부모의 pte를 복사하기 위해 페이지 테이블을 생성한다.
        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
        // "pml4_for_each" : Apply FUNC to each available pte entries including kernel's.
        if (!pml4_for_each (parent->pml4, duplicate_pte, parent)) // "duplicate_pte" : 페이지 테이블을 복제하는 함수(부모 -> 자식) 
            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.*/
        /*
         * 파일 객체를 복제하려면 'file_duplicate'를 사용하라.
         * 이 함수가 부모의 리소스를 성공적으로 복제할 때까지 부모 프로세스는 fork로 부터 리턴할 수 없다.
        */
        if (parent->next_fd == FDCOUNT_LIMIT)
            goto error;
    
        // 부모의 fdt를 자식의 fdt로 복사한다.
        for (int fd = 2; fd < FDCOUNT_LIMIT; fd++) {
            struct file *file = parent->fdt[fd];
            if (file == NULL) // fd엔트리가 없는 상태에는 그냥 건너뛴다.
                continue;
            current->fdt[fd] = file_duplicate (file);
        }
    
        current->next_fd = parent->next_fd; // 부모의 next_fd를 자식의 next_fd로 옮겨준다.
        sema_up(&current->fork_sema); // fork가 정상적으로 완료되었으므로 현재 wait중인 parent를 다시 실행 가능 상태로 만든다. 
    
        /* Finally, switch to the newly created process. */
        if (succ)
            do_iret (&if_);
    error: // 제대로 복제가 안된 상태 - TID_ERROR 리턴 
        sema_up(&parent->fork_sema);
        exit(TID_ERROR);
        // thread_exit (); // origin_code
    }
    • __do_fork 의 인자로 thread_create 를 하면서 4번째 인자로 넣은 curr (aux) 가 들어가게 된다.
    1. 자식 프로세스에 부모의 인터럽트 프레임(실행 컨텍스트)를 복사해서 넣어준다.
    2. 부모 프로세스의 페이지 테이블을 자식 프로세스의 페이지 테이블로 복제한다.(duplicate_pte _”filesys/filesys.h”) 사용
    3. 부모의 fdt와 next_fd를 복사하여 자식 프로세스에게 설정해준다.
    4. 이후, 부모 프로세스에서 자식 프로세스로의 모든 복사 과정이 완료되었으므로 sema_up 을 수행한다.
      • 반드시 process_fork 에서의 세마포어와 동일한 세마포어에 대해 Up 연산을 수행해주어야한다!
    5. do_iret (&if_); : sema_up 을 진행해서 부모 프로세스가 다시 Ready 상태가 되었으므로 컨텍스트 스위치를 수행한다.

exec()

👉 cmd_line으로 들어온 실행 파일을 실행하는 시스템 콜
int exec(const char *cmd_line){
	check_address(cmd_line);

	// 파일 사이즈(NULL 포함 +1)
	int size = strlen(cmd_line) + 1;
	char *fn_copy = palloc_get_page(PAL_ZERO);

	// 메모리 할당 불가 시
	if(fn_copy == NULL)
		exit(-1);
	strlcpy(fn_copy, cmd_line, size);

	if(process_exec(fn_copy) == -1)
		return -1;

	return 0;
}
  • 현재 실행중인 프로세스를 cmd_line에 지정된 실행 파일로 변경하고 인수들을 전달
  • process_exec 함수 source code 및 해석
    int
    process_exec (void *f_name) {
        char *file_name = f_name; // 커맨드 라인 전체가 인자로 들어온다.
        bool success;
    
        struct intr_frame _if;
        _if.ds = _if.es = _if.ss = SEL_UDSEG;
        _if.cs = SEL_UCSEG;
        _if.eflags = FLAG_IF | FLAG_MBS;
    
        int argc = 0;
        char *argv[128]; // 64bit computer(uint64_t : 8byte)
    
        /* We first kill the current context */
        process_cleanup ();
    
    		/* ----- 추가 부분 ------- */
        /* 커맨드 라인을 파싱한다. */
        argument_parse(file_name, &argc, argv);
    
        /* And then load the binary */
        success = load (file_name, &_if);
    
        /* If load failed, quit. */
        if (!success){
            palloc_free_page (file_name);
            return -1;
        }
    
        argument_stack(argc, argv, &_if); // argc, argv로 커맨드 라인 파싱
        // hex_dump(_if.rsp, _if.rsp, USER_STACK - _if.rsp, true); // 메모리에 적재된 상태 출력
    
        /* Start switched process. */
        do_iret (&_if);
        NOT_REACHED ();
    }

wait()

👉
int wait(__pid_t pid){
	process_wait(pid);
}
  • pid : 대기하려는 자식 프로세스의 pid
  • process_wait 함수 source code 및 해석
    process_wait (tid_t child_tid UNUSED) {
        struct thread *child = get_child_process(child_tid);
    
        if(child == NULL) // 해당 자식이 존재하지 않는다면 -1 리턴
            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;
    }
    • 해당 자식 프로세스가 성공적으로 종료될 때까지 부모 프로세스는 대기한다.
    • threads/thread.c -> init_thread 에서 wait_sema 의 값을 0으로 설정해줬으므로 부모 프로세스는 wait_list로 들어가게된다.
    • ⭐ 이후 자식 프로세스가 종료(process_exit)된 후, sema_up을 한 뒤에서야 해당 부모 프로세스가 Ready 상태로 전환된다!
    • 자식 프로세스가 성공적으로 종료됐다면 부모 프로세스의 자식 프로세스 리스트에서 해당 자식 프로세스를 제거한다.
    • free_sema 는 자식 프로세스의 종료 상태를 받고 자식 프로세스를 종료해야하므로 세마포어를 이중적으로 걸어줬다고 보면 된다.

파일 관련 시스템 콜

create()

👉 `file`을 이름으로 하고 크기가 `initial_size`인 새로운 파일 생성
bool create(const char *file, unsigned initial_size){
	check_address(file);
	return filesys_create(file, initial_size);
}
  • file : 생성할 파일의 이름 및 경로 정보
  • initial_size : 생성할 파일의 크기
  • 파일 생성은 파일 열기X
  • 파일 열기는 open 시스템 콜이 수행

remove()

👉 `file` 이름을 가진 파일 삭제
bool remove(const char *file){
	check_address(file);
	return filesys_remove(file);
}
  • file : 제거할 파일의 이름 및 경로 정보
  • 파일은 열려있는지 닫혀있는지와 관계없이 삭제될 수 있다
    • 삭제 전 파일을 꼭 닫아줄 것!

open()

👉 파일을 열 때 사용하는 시스템 콜
int open(const char *file){
	check_address(file);
	struct file *target_file = filesys_open(file);

	if(target_file == NULL)
		return -1;
	int fd = fdt_add_fd(target_file);
	
	// fdt가 가득 찼다면
	if(fd == -1){
		file_close(target_file);
	}
	return fd;
}
  • file : 파일의 이름 및 경로 정보
  • 콘솔용으로 예약 되어있는 파일 디스크립터
    • 0 : 표준 입력(STDIN_FILENO)
    • 1 : 표준 출력(STDOUT_FILENO)
  • 하나의 파일이 한번 이상 열릴 때, 각 open 프로세스는 새로운 파일 디스크립터를 반환

filesize()

👉 파일의 크기를 알려주는 시스템 콜
int filesize(int fd){
	struct file *target_file = fdt_get_file(fd);
	if(target_file == NULL)
		return -1;
	return file_length(target_file);
}

read()

👉 열린 파일의 데이터를 읽는 시스템 콜
int read(int fd, void *buffer, unsigned size){
	int read_bytes = -1;

	if(fd == STDIN_FILENO){
		int i;
		unsigned char *buf = buffer;

		for(i = 0; i < size; i++){
			char c = input_getc();
			*buf++ = c;
			if(c == '\0')
				break;
		}
		return i;
	}
	else{
		struct file *file = fdt_get_file(fd);
		if(file != NULL && fd != STDOUT_FILENO){
			// 파일을 읽는 동안 접근 못하게 락 걸기
			lock_acquire(&filesys_lock);
			read_bytes = file_read(file, buffer, size);
			// 락 해제
			lock_release(&filesys_lock);
		}
	}
	return read_bytes;
}
  • fd 가 0이면 STDIN이기 때문에 키보드로 들어온 값을 읽고
  • fd 가 1이면 STDOUT이다
  • 그게 아닐 경우 fd로 열린 파일에서 size바이트를 buffer로 읽는다
  • 실제로 읽은 바이트 수를 반환하거나 만약 파일을 읽을 수 없다면 (EOF로 인한) -1을 반환
  • input_getc 함수 source code 및 해석
    uint8_t
    input_getc (void) {
    	enum intr_level old_level;
    	uint8_t key;
    
    	old_level = intr_disable ();
    	key = intq_getc (&buffer);
    	serial_notify ();
    	intr_set_level (old_level);
    
    	return key;
    }
    • 입력 버퍼로부터 누른 키 값을 가져온다
    • 만약 입력 버퍼가 비어있으면 키를 누를 때까지 기다린다

write()

👉 열린 파일에 데이터를 쓰는 시스템 콜
int write(int fd, const void *buffer, unsigned size){
	check_address(buffer);
	int write_bytes = -1;

	if(fd == STDOUT_FILENO){
		putbuf(buffer, size);
		return size;
	}
	else{
		struct file *file = fdt_get_file(fd);
		if(file != NULL && fd != STDIN_FILENO){
			// 파일을 쓰는 동안 접근 못하게 락 걸기
			lock_acquire(&filesys_lock);
			write_bytes = file_write(file, buffer, size);
			lock_release(&filesys_lock);	// 락 해제
		}
	}
	return write_bytes;
}
  • buffer 에서 열린 파일 fdsize 만큼의 바이트를 쓴다
  • 실제로 쓴 바이트 수를 반환
  • 일부의 바이트를 쓸 수 없는 경우에는 반환값이 size 보다 작을 수 있다
  • 파일 끝까지 가능한 한 많은 바이트를 쓰고, 실제 바이트 수를 반환하거나 쓸 수 없는 경우 0을 반환
  • fd 1은 putbuf() 를 이용해서 콘솔에 쓴다

seek()

👉 열린 파일의 위치를 알려주는 시스템 콜
void seek(int fd, unsigned position){
	struct file *target_file = fdt_get_file(fd);

	if(fd <= STDOUT_FILENO || target_file == NULL)
		return;

	file_seek(target_file, position);
}
  • position : 현재 위치(offset)를 기준으로 이동할 거리
  • 열린 파일 fd 에서 읽거나 쓸 다음 바이트를 position으로 바꾼다
    • position 0 은 파일의 시작 위치
  • 현재 파일의 끝을 지나서 읽는 것은 오류 X
    • 파일의 끝을 지나서 read를 실행하면 0을 반환
  • but 파일의 끝을 지나서 쓰는 건(write) 불가능
  • file_seek 함수 source code 및 해석
    file_seek (struct file *file, off_t new_pos) {
      // 파일 유효성 검사
    	ASSERT (file != NULL);
    	// 새로운 위치 확인 (파일의 위치는 0 이상이어야 한다)
    	ASSERT (new_pos >= 0);
    	// 파일 위치 업데이트 (인자값으로 받은 new_pos로 설정)
    	file->pos = new_pos;
    }

tell()

👉 열린 파일의 위치를 알려주는 시스템 콜
unsigned tell(int fd){
	struct file *target_file = fdt_get_file(fd);

	if(fd <= STDOUT_FILENO || target_file == NULL)
		return;

	file_tell(target_file);
}
  • 열린 파일 fd 에서 읽거나 쓸 다음 바이트를 반환
  • file_tell 함수 source code 및 해석
    off_t
    file_tell (struct file *file) {
      // 파일 유효성 검사
    	ASSERT (file != NULL);
    	// 현재 위치 반환
    	return file->pos;
    }
    • 현재 파일 내에서의 위치를 나타내는 파일 offset 반환

close()

👉 파일을 닫는 시스템 콜
void close(int fd){
	struct file *target_file = fdt_get_file(fd);

	if(fd <= STDOUT_FILENO || target_file == NULL || target_file <= 2)
		return;

	// fdt 에서 해당 fd값을 제거
	fdt_remove_fd(fd);
	// 파일을 닫음
	file_close(target_file);
}
  • 파일을 닫고 fd를 제거

추가 함수

fdt_add_fd()

👉 file descriptor table에 file descriptor 추가하는 함수
static int fdt_add_fd(struct file *f){
	struct thread *curr = thread_current();
	struct file **fdt = curr->fdt;
	
	while(curr->next_fd < FDCOUNT_LIMIT && fdt[curr->next_fd]){
		curr->next_fd++;
	}

	if(curr->next_fd >= FDCOUNT_LIMIT)
		return -1;

	fdt[curr->next_fd] = f;
	return curr->next_fd;
}
  • file descriptor가 제한 범위를 넘지 않으면서 fdt의 인덱스 위치와 일치할 때
    까지 다음 인덱스로 이동하는 것을 반복
  • fdt가 가득 차게되면 return -1
  • fdt에 인자값으로 받은 fd 삽입하고 다음 fd 인덱스를 반환

fdt_get_file()

👉 file descriptor table에서 인자로 들어온 file descriptor를 검색 후 파일 객체를 반환
static struct file *fdt_get_file(int fd){
	struct thread *curr = thread_current();
	if(fd < STDIN_FILENO || fd >= FDCOUNT_LIMIT)	// 실패
		return NULL;				
	
	return curr->fdt[fd];							// 성공
}
  • fd가 0이하 또는 512이상이면 파일 찾기 실패

fdt_remove_fd()

👉 file descriptor table에서 인자로 들어온 file descriptor를 삭제
static void fdt_remove_fd(int fd){
	struct thread * curr = thread_current();

	if(fd < STDIN_FILENO || fd >= FDCOUNT_LIMIT)	// 실패
		return;

	curr->fdt[fd] = NULL;							// 성공
}
  • 조건은 위와 동일

get_child_process()

👉 자식 리스트를 검색해서 해당 프로세스 디스크립터를 반환
struct thread *get_child_process(int pid){
	struct thread *curr = thread_current();
	struct list *child_list = &curr->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);
		// 해당 pid가 존재하면 프로세스 디스크립터 반환
		if(t->tid == pid)
			return t;
	}
	// 리스트에 존재하지 않으면 NULL 반환
	return NULL;
}
  • process_fork 를 통해 부모 프로세스에서 자식 프로세스를 복제하며 부모 프로세스의 child_list 에 자식 프로세스의 element 값을 넣어준다
  • 이후, process_waitprocess_forkload 과정 이전에 tid 로 받은 프로세스가 실제 부모의 자식 프로세스가 맞는지 검증하는 과정을 거친다

함수 수정 및 추가

👉 `thread_create()` 함수에 fdt 공간 할당 부분 추가
    // fdt 공간 할당
    t->fdt = palloc_get_multiple(PAL_ZERO, FDT_PAGES);
    if(t->fdt == NULL)
        return TID_ERROR;
    t->next_fd = 2;     // 0: stdin, 1: stdout
    t->fdt[0] = 1;      // STDIN_FILENO -> dummy value
    t->fdt[1] = 2;      // STDOUT_FILENO -> dummy value
  • palloc_get_multiple(enum palloc_flags flags, size_t page_cnt)
    • source code (주석 포함)
      void *
      palloc_get_multiple (enum palloc_flags flags, size_t page_cnt) {
        // 사용자 영역인지 커널 영역인지 확인
      	struct pool *pool = flags & PAL_USER ? &user_pool : &kernel_pool;
        
        /* 다중 스레드 환경에서 동시 접근을 방지하기 위해 해당 
           풀에 대한 락(lock) 획득 */
      	lock_acquire (&pool->lock);
      	/* bitmap_scan_and_flip 함수를 이용해 풀의 비트맵에서 
      	   연속된 'page_cnt'개의 빈 페이지를 찾는다 */
      	size_t page_idx = bitmap_scan_and_flip (pool->used_map, 0, page_cnt, false);
      	/* 페이지를 찾은 후에는 락을 해제 */
      	lock_release (&pool->lock);
      	void *pages;
      
        /* 페이지를 찾으면, 페이지의 시작 주소를 계산하여
           'pages' 변수에 저장 */
      	if (page_idx != BITMAP_ERROR)
      		pages = pool->base + PGSIZE * page_idx;
      	else
      	  // 찾지 못하면 NULL로 설정
      		pages = NULL;
      
      	if (pages) {
      	  // 'PAL_ZERO' 비트가 설정되어 있으면 페이지를 0으로 초기화
      		if (flags & PAL_ZERO)
      			memset (pages, 0, PGSIZE * page_cnt);
      	} else {
      	  // 'PAL_ASSERT' 비트가 설정되어 있으면 커널을 패닉시킨다
      		if (flags & PAL_ASSERT)
      			PANIC ("palloc_get: out of pages");
      	}
        // 찾은 페이지의 시작 주소를 반환
      	return pages;
      }
    • 연속된 여러 개의 빈 페이지를 할당하고 반환하는 함수
    • 인자값인 flags에 따라 사용자 영역이나 커널 영역에서 페이지를 할당하고, 필요에 따라 페이지를 0으로 초기화
    • STDIN(0)STDOUT(1) 은 미리 콘솔을 위해 예약된 fd이므로 next_fd 는 2부터 시작하도록 초기화한다.
    • fdt[0] 과 fdt[1] 에는 0(NULL)이 아닌 값으로 채워준다.
  • enum palloc_flags
    • source code (주석 포함)
      enum palloc_flags {
      	PAL_ASSERT = 001,           /* Panic on failure. */
      	PAL_ZERO = 002,             /* Zero page contents. */
      	PAL_USER = 004              /* User page. */
      };
      1. PAL_ASSERT (001):
        • 할당에 실패하면 패닉(Panic)을 발생
        • 할당에 실패할 경우, 프로그램이 중단되고 오류 메시지가 표시
      2. PAL_ZERO (002):
        • 할당된 페이지의 내용을 0으로 초기화
        • 즉, 페이지에 저장되는 데이터를 모두 0으로 설정
      3. PAL_USER (004):
        • 할당된 페이지가 사용자 페이지인 경우
        • 사용자 페이지는 일반적으로 사용자 프로세스에 의해 사용 커널 페이지와는 구분
👉 `process_exit()` 함수 수정
  ...
  
  palloc_free_multiple(curr->fdt, FDT_PAGES);		// fdt 메모리 해제
	file_close(curr->running);						// 현재 프로세스가 실행중인 파일 종료
	
	process_cleanup();

	// 부모 프로세스가 자식 프로세스의 종료상태를 확인하게 한다
	sema_up(&curr->wait_sema);
	// 부모 프로세스가 자식 프로세스의 종료 상태를 받을때 까지 대기한다
	sema_down(&curr->free_sema);
}
  • 자식 프로세스의 종료 시, 부모 프로세스에게 자식 프로세스의 종료를 알릴 수 있게끔 세마포어 연산 수행
👉 `syscall_init()` 함수에 락 초기화 부분 추가
lock_init(&filesys_lock);
👉 `thread` 구조체 수정
#ifdef USERPROG

    ...
    int exit_status;        // 프로세스 종료 유무 확인
    struct file **fdt;      // file descriptor table의 시작주소(프로세스당 개별적으로 존재)
    int next_fd;            // 다음 file descriptor의 인덱스
    struct file *running;   // 현재 실행 중인 파일

    struct intr_frame parent_if;    // 부모 프로세스의 인터럽트 프레임
    struct list child_list;         // 자식 프로세스 리스트
    struct list_elem child_elem;    // 자식 프로세스 리스트의 element

    struct semaphore fork_sema;     // fork가 완료될 때 sema_up 수행
    struct semaphore free_sema;     // 자식 프로세스가 종료될 때까지 부모 프로세스는 대기
    struct semaphore wait_sema;     // 자식 프로세스가 종료될 때까지 대기, 종료 상태 저장
		...
		
#endif
👉 `init_thread` 함수 수정
...
    t->exit_status = 0;
    t->running = NULL;
    // 자식 리스트 및 세마포어 초기화
    list_init(&t->child_list);
    sema_init(&t->wait_sema, 0);
    sema_init(&t->fork_sema, 0);
    sema_init(&t->free_sema, 0);
 }
  • 수정한 thread 구조체에 대한 초기화 작업 수행
  • 이때 세마포어 값은 0
    • 부모 프로세스에서 먼저 호출하기 때문에 부모 프로세스를 대기(wait 상태) 시키기 위해서 0으로 만들어야함
👉 `load` 함수 수정
static bool
load (const char *file_name, struct intr_frame *if_) {
    struct thread *t = thread_current ();
    struct ELF ehdr;
    struct file *file = NULL;
    off_t file_ofs;
    bool success = false;
    int i;

    ...

    t->running = file;

    file_deny_write(file); // 현재 오픈한 파일에 접근 못하게 함

    ...

    return success;
}
  • exec를 통해 파일을 실행하게 되면 해당 프로세스에 해당하는 파일은 열린 상태로 있으므로 struct thread 의 running 필드에 해당 파일을 추가한다.
    • process_exit 에서 해당 파일에 대해 닫아주는 작업을 수행한다.
      • 또, 현재 실행하기위해 오픈한 파일에 대해 접근하지 못하게 하기 위해 file_deny_write를 이용해 접근 제한을 걸어준다.
profile
개발합니다

2개의 댓글

comment-user-thumbnail
2024년 5월 28일

아놔

1개의 답글