이전 포스팅들에서 인자를 파싱했다. 이제 시스템 콜을 구현해 보겠다. 시스템 콜에 대한 것은 이전에 part.1에 담겨있다.
2025.05.19 - [크래프톤 정글] - [pintos] Week2~3: User Program Part.1
[pintos] Week2~3: User Program Part.1
1주 차에 Alarm Clock, Priority Scheduling과 같이 동기화와 스케줄링에 대해 다루었다면 2~3주 차는 User Program이 Pintos에서 돌아갈 수 있도록 구현을 진행한다.User Program을 OS에 로드하고, System Call을 통해 U
www.gowoong.com
우리는 그 중 (halt, exit, create, remove)를 먼저 구현해서 테스트 코드의 시작 부분을 먼저 검증하면서 진행하겠다.
인자 파싱(Arguments Parssing) 방법
이 전 시간에 커널은 사용자가 실행을 요청한 프로그램을 실행하기 위해 실행하며 입력한 명령어 문자열을 분리하여 파일 이름, 인자값으로 나누는 과정을 거쳐야 한다고 했다. 그렇다면 어떻게 문자열을 나누어야 할까?
Pintos강의 ppt에는 strtok_r() 함수를 사용해서 파싱을 진행하라고 나와있다.
strtok_r() 함수
char *strtok_r(char *str, const char *delim, char **save_ptr);
이 함수는 문자열을 특정 구분자로 잘라서 파싱 하는 함수다.
- str: 처음 호출 시 분할할 문자열, 이후 호출 시 NULL
- delim: 분할할 구분자 (예: 공백 " ")
- save_ptr: 내부 상태를 저장할 포인터 (재진입-safe)
마치 python의 .split(" ") 기능을 수행하는 것이라고 보면 된다. 차이점이라면 파이썬이 한 번에 리스트로 변환한다면 C에서는 반복문으로 하나씩 꺼내야 한다는 점이다. 또 다른 차이점으로는 strtok_r()은 원본 문자열을 수정한다는 것이다.
char str[] = "echo hello";
strtok_r(str, " ", &save); // str → "echo\0hello"
" "을 '\0' 으로 대체 삽입했다. 상태 저장을 위해 save_ptr로 호출자가 상태를 유지해야 한다는 점도 있다. 어쨌든 문자열을 분할하는 작업이다.
1. syscall_handler() 함수
- userprog/syscall.c
시스템 콜을 호출할 때, 원하는 기능에 해당하는 시스템 콜 번호를 rax에 담는다. 그리고 시스템 콜 핸들러는 rax의 숫자로 시스템 콜을 호출하고, 해당 콜의 반환값을 다시 rax에 담아서 intr frame(인터럽트 프레임)에 저장한다.
/* The main system call interface */
void
syscall_handler (struct intr_frame *f UNUSED) {
switch (f->R.rax)
{
case SYS_HALT:
halt(); // 핀토스 종료
break;
case SYS_EXIT:
exit(f->R.rdi); // 프로세스 종료
break;
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);
}
}
2. check_address() 함수
- userprog/syscall.c
- 주소 값이 유저 영역에서 사용하는 주소 값인지 확인
- 유저 영역을 벗어난 영역일 경우 프로세스 종료(exit(-1))
void
check_address (void *addr)
{
if (is_kernel_vaddr(addr) || addr == NULL || pml4_get_page(thread_current()->pml4, addr) == NULL)
exit(-1);
}
Pintos의 userprog 프로젝트에서 매우 중요한 보안 및 안정성 기능으로, 유저 프로그램이 잘못된 주소(커널 주소나 매핑되지 않은 주소)에 접근할 경우 이를 미리 감지하고 종료(exit) 시키기 위해 사용한다.
조건 | 의미 |
is_kernel_vaddr(addr) | 커널 영역 주소인지 확인. 유저가 커널 주소에 접근하려 하면 안 됨 |
addr == NULL | NULL 포인터 접근은 잘못된 접근이므로 종료 |
pml4_get_page(thread_current()->pml4, addr) == NULL | 현재 스레드의 페이지 테이블에서 해당 주소에 매핑된 실제 물리 주소가 없으면 → 접근 불가능한 페이지 |
이 함수를 통해 유저 프로그램이:
- 커널 메모리를 읽거나 쓰는 행위 차단
- 매핑되지 않은 주소에 접근해 Page Fault 발생시키는 것 방지
3. halt() 함수
- userprog/syscall.c
- 핀토스를 종료시키는 시스템 콜
void
halt(void)
{
power_off();
}
GitBook 설명: Pintos를 종료한다. power_off()를 호출하며, src/include/threads/init.h에 선언되어 있다. 이 시스템 콜은 디버깅에 유용하지만, 데드락 등 문제 원인을 분석할 기회를 잃게 되므로 최소한으로 사용해야 한다.
4. exit() 함수
- include/threads/thread.h
- exit(), wait()을 구현할 때 필요한 변수나 값을 구조체에 추가하고 초기화 한다.
uint64_t *pml4; /* Page map level 4 */
int exit_status;
- threads/thread.c
t->original_priority = t->priority;
t->niceness = NICE_DEFAULT;
t->recent_cpu = RECENT_CPU_DEFAULT;
/* 기존 구현 부 아래에 추가 */
t->exit_status = 0;
}
if (success) {
set_stack_data(buffer, count, &_if.rsp);
_if.R.rdi = count;
_if.R.rsi = (char *)_if.rsp + 8;
}
- userprog/syscall.c
- 현재 프로세스를 종료시키는 시스템 콜
- 종료 시 “프로세스 이름: exit(status)” 출력 (Process Termination Message)
- 정상적으로 종료 시 status는 0
- status : 프로그램이 정상적으로 종료됐는지 확인
void
exit(int status)
{
struct thread *t = thread_current();
t->exit_status = status;
printf("%s: exit(%d)\n", t->name, t->exit_status); // Process Termination Message
thread_exit();
}
GitBook 설명 : 현재 사용자 프로그램을 종료하고 커널에 status를 반환한다. 부모 프로세스가 wait()를 호출하면 이 status가 전달된다. 일반적으로 0은 성공, 0이 아닌 값은 에러를 의미한다.
5. create() 함수 구현
- userprog/syscall.c
- 파일을 생성하는 시스템 콜
- 성공 일 경우 true, 실패 일 경우 false 리턴
- file : 생성할 파일의 이름 및 경로 정보
- initial_size : 생성할 파일의 크기
bool
create(const char *file, unsigned initial_size)
{
check_address(file);
return filesys_create(file, initial_size);
}
GitBook 설명 : 크기 `initial_size`의 새 파일을 생성한다. 성공 시 `true`, 실패 시 `false` 반환. 생성은 열기와 다르다. 열려면 open() 호출 필요.
6. remove() 함수 구현
- userprog/syscall.c
- 파일을 삭제하는 시스템 콜
- file : 제거할 파일의 이름 및 경로 정보
- 성공 일 경우 true, 실패 일 경우 false 리턴
bool
remove(const char *file)
{
check_address(file);
return filesys_remove(file);
}
GitBook 설명 : 파일을 삭제한다. 열려 있든 닫혀 있든 상관없이 삭제 가능. 성공 시 true.
'크래프톤 정글' 카테고리의 다른 글
[pintos] Week2~3: User Program Part.3 (2) | 2025.05.20 |
---|---|
[pintos] Week2~3: User Program Part.2 (0) | 2025.05.19 |
[pintos] Week2~3: User Program Part.1 (2) | 2025.05.19 |
[pintos] Week1: Priority Scheduling - Part.3 (1) | 2025.05.12 |
[pintos] Week1: Priority Scheduling - Part.2 (0) | 2025.05.12 |