우리가 사용했던 system call [ 크래프톤 정글 42일차 ]

jinsung·2025년 6월 25일

크래프톤 정글 9기

목록 보기
40/59

이번주 내내 CSAPP : 7,8,9 장을 읽고 CSAPP:8장을 읽고 예외적인 제외흐름에 대해서 정리했지만, 직접 사용해보지 않았기에 이해하기 어려운 부분이 있었어요.

그런데 저희는 CSAPP만 읽은 게 아니라 RB-tree도 만들었잖아요?
그래서 RB-tree 를 만들 때 사용했던 system call 에 대해서 정리하면 나에게도 도움이 되고 같이 공부하는 여러분들에게도 8장의 내용을 이해하는데에 조금 더 도움이 되지 않을까 해서
이번주 발표 내용은 우리가 사용했던 system call 입니다.

✅ [ WEEK06 ] 탐험준비 - Red-Black-Tree


WEEK 진행률

🎯 1. 키워드 공부

  • ☑️ 포인터
  • ☑️ 가상화
  • ☑️ GCC
  • ☑️ 포인터의 연산
  • ☑️ 동적 메모리 할당
  • ☑️ 이진 탐색 트리
  • ☑️ 레드 블랙 트리의 삽입/삭제
  • ☑️ malloc, calloc, realloc

🎯 2. 테스트 케이스

  • ☑️ test_init
  • ☑️ test_insert_single
  • ☑️ test_find_single
  • ❗️ test_erase_root
  • ☑️ test_find_erase_fixed
  • ☑️ test_minmax_suite
  • ☑️ test_to_array_suite
  • ☑️ test_distinct_values
  • ☑️ test_duplicate_values
  • ☑️ test_multi_instance
  • ☑️ test_find_erase_rand

🎯 3. 책 읽기

  • ☑️ CS APP : 7장 링커
  • ☑️ CS APP : 8장 예외적인 제어 흐름
  • ☑️ CS APP : 9장 가상 메모리

진행률 : 95%

1. system call 다시 한번

트랩 이란?

  • 트랩은 소프트웨어에서 의도적으로 발생시키는 예외적인 제어 흐름이예요.
  • 사용자모드 -> 커널모드로 진입하기 위한 메커니즘으로 사용돼요.
  • 트랩은 현재 실행 중인 명령어를 완료한 뒤 커널에게 특정 처리를 요청하며, 이는 복구 가능한 예외예요.

시스템 콜은 이 트랩을 발생시켜서 커널에게 요청하는 서비스입니다.

CPU에는 사용자 모드커널 모드가 있는데요.
사용자 모드에서는

  • 파일 (열기,읽기,쓰기)
  • 물리 메모리 주소 접근, 페이지 테이블 조작
  • 키보드,마우스,디스크 등 입출력 장치
  • 다른 프로세스 죽이기
  • 시스템 시계 조작, 타이머 설정

등을 할 수가 없어요. 그래서 system call이라는 명령어를 이용해서 커널모드로 진입하는 거예요.

시스템 콜번호설명
read0파일에서 읽기
write1파일에 쓰기
open2파일 열기
close3파일 닫기
fork57자식 프로세스 생성
execve59새 프로그램 실행
exit60프로세스 종료
kill62시그널 보내기

다양한 system call명령어가 있는데 운영체제마다 다르고
리눅스는 /usr/include/x86_64-linux-gnu/asm/unistd_64.h 경로에 저장되어 있다고 합니다.

2. 우리가 사용했던 system call

우리는 총 5개의 system call을 이번 RB-tree에서 사용했어요.

    1. 메모리 관리 : malloc,free
    1. 입출력 : printf
    1. 난수생성 : rand,srand

근데 이 중 randsrand는 test case를 위해서 사용된거고 잘 모르니까 안할게요.

3개만 살펴볼게요. malloc,free,printf

2-1. printf 는 유명한 system call임

실제로 printf 는 데이터를 그냥 바로 출력하지 않아요.
그 대신 포맷처리와 버퍼링을 담당하고 최종 출력은 write() 시스템 콜 을 사용해서 출력합니다.

왜냐고요? 순수 c 언어로는 터미널에 출력 ( 디스크에쓸수도있음 ) 을 못함 권한이 없어서,
그래서 커널한테 자격 넘겨줄려고 write 써요.

이런 순서를 거쳐요

사용자 코드
 └─▶ printf()              // 라이브러리 함수
      └─▶ vfprintf()       // %d , %s , %p 포맷 처리
           └─▶ _IO_file_xsputn() // 버퍼(버퍼는 데이터를 임시로 저장해두는 공간) 에 데이터 복사
                └─▶ _IO_do_write() // 파일 스트림 flush
                    └─▶ syscall write(fd=1, buf, size)

이렇게 여러 중간과정을 거치고 최종적으로는 write() 시스템 콜을 사용합니다!

write(1, "Hello\n", 6);
  • 첫번째 매개변수는 출력 대상 파일디스크립터 ( 1 = stdout , 2 = stderr ) 등
  • 두번째 매개변수는 출력할 데이터의 메모리 주소
  • 세번째 매개변수는 출력할 데이터의 바이트 수
유저모드 write() 호출
  ↓
CPU의 트랩 → 커널 진입 (syscall)
  ↓
fd 검증 → 버퍼 접근 시도 → 파일디스크립터가 가리키는 대상(터미널,디스크파일)에 기록
  ↓
오류 발생 시 → 예외(페이지 폴트, 권한 오류 등) → errno 설정 → -1 리턴

2-2. malloc은 시스템 콜을 직접쓰진 않음

malloc 은 내부에 ptmalloc 이라는 힙 관리자가 따로 있는데 얘가 시스템 콜을 관리해줘요.

언제 쓰냐!!

malloc 이 heap 영역에 메모리를 할당하는 건 아시죠?

만약 heap 영역에 메모리가 꽉 차면 이 힙 영역을 늘려줘야 하잖아요.
그 때, 이제 brk() 라는 시스템 콜을 사용해서 조절되는 거예요.

  • malloc의 메모리 할당은 확보해둔 힙 여역에서 작동하며, 커널 모드 진입안해도 됨
  • 근데 메모리가 부족하면? malloc 의 내부 로직이 커널한테 메모리 더주세여 하고 요청해야함
  • 그 때 , brk() 라는 시스템 콜 사용 ( malloc 의 데이터가 큰 경우 또는 특수한 경우에 mmap() 시스템 콜 사용 )

brk 시스템 콜은 인자로 원하는 힙의 끝 주소를 전달해요.

int brk(void *end_data_segment); // 절대주소
void *sbrk(int increment); // 상대주소

혹은 sbrk로 상대적인 주소를 전달하기도 한답니다?

2-3. free 는 사실 시스템 콜을 쓰진 않음

대부분의 경우 free 는 단순히 사용자가 요청한 메모리 블록을 내부 힙 관리구조(free list)에 반환해서 다음에 malloc이 재활용할 수 있도록 표시함.

이건 완전히 사용자 공간에서 처리되고요 시스템 콜이 발생하진 않아요.

free 쓸때 시스템콜이 발생하는 경우는

위에서 쓴 malloc 에서 데이터가 클 경우 mmap()을 쓴다고 했자나여 이걸 쓴 메모리 블록을 free()할 때 넘 크니까 free list에 안넣고 그냥 munmap() 시스템콜을 호출해서 해제해요

왜냐면 brk는 연속된공간을 확장하는 방식인데
mmap은 아예 새로운 메모리 공간을 만드는 느낌이예요.

이런느낌

brk 는 heap 에 바로 연속적으로 만들어지고
mmap은 아예 새로운 공간을 할당했다가 해제할때 그 공간 자체를 해제

마무리

8장이 너무 어려워서 최대한 주변 예제로 이해하고 싶어서 그 경험을 공유합니다.
화이또

2개의 댓글

comment-user-thumbnail
2025년 6월 25일

나 왜 인상찌푸리고있어ㅠ

답글 달기
comment-user-thumbnail
2025년 6월 25일

wow amazing

답글 달기