Linux 2.6 커 널 노트 [Process - 3: fork, 커 널 프로 세 스]

더 읽 기
Utensil 누 르 기:
 
마지막 리 눅 스 커 널 노트 몇 편 은 정말 난산 이 었 다. 중간 에 APUE 를 읽 고 자바 아이 잡담 형식 으로 수많은 작은 필 기 를 했다.'에이스 프로그래머 가이드' 를 세 번 째 (아니면 네 번 째?) 읽 었 지만 이번 에는 필 기 를 했다.Programming Erlang 도 보고 UDP 기반 TCP 를 Erlang 으로 쓰 는 ErlyUbt 도 눈 에 띄 었 고 GitHub 에 push 를 올 렸 다.안 타 깝 게 도 그동안 해 야 할 일 은 진전 이 없 었 는데..
 
'Understanding Linux Kernel' 은 18 일 도서관 에 반납 해 야 합 니 다. 이틀 동안 컴퓨터 가 고장 난 날 에 세 번 째 로 필 기 를 할 중단 과 이상, 커 널 동기 화, 시간 측정 을 읽 었 습 니 다. 나머지 장절 도 약간 읽 었 습 니 다. 이 장절 들 은 작은 잡담 으로 쓰 기 를 바 랍 니 다.컴퓨터 가 오늘 밤 정상 으로 돌아 올 것 으로 예상 된다. 그 전에 나 는 도서관 에 와 서 오랫동안 준비 해 온 필 기 를 쓰기 시작 했다. 첫 번 째 편 은 Process 에 대한 마무리 이다.
 
Process 의 종료 
이것 은 이 노트 가 주목 하 는 중점 이 아니 라 다음 과 같은 점 만 기록 하 세 요.
 
C 라 이브 러 리 함수 exit () exit 호출group () 시스템 호출 (do group exit () 을 수행 합 니 다. 전체 스 레 드 그룹 을 종료 합 니 다. exitgroup () 은 exit () 시스템 호출 (do exit () 을 호출 하여 지정 한 스 레 드 를 종료 합 니 다. 
 
프로 세 스 의 탄생 
POSIX 에서 프로 세 스 를 만 들 려 면 fork () 가 필요 합 니 다. 오래된 fork () 는 땀 이 납 니 다. 부모 프로 세 스 의 모든 자원 을 완전 하 게 복사 합 니 다.Linux 는 fork 를 다음 세 가지 상황 으로 세분 화 합 니 다.
 
fork 의 정상 적 인 프로 세 스 라면 Copy - on - write (CoW) 기술 을 사용 하 십시오. 하위 프로 세 스 는 부모 프로 세 스 의 모든 페이지 를 사용 하고 있 습 니 다. 한 페이지 를 수정 하려 고 할 때 그 페이지 를 복사 하여 고 치 려 고 합 니 다.
 
만약 에 스 레 드 (경량급 프로 세 스) 를 원한 다 면 모두 가 원래 의 자원 을 공유 하고 모두 가 배 를 타 는 것 이다.
 
그리고 vfork () 가 대표 하 는 상황 입 니 다. 하위 프로 세 스 가 만들어 진 후에 부모 프로 세 스 가 막 혔 습 니 다. 그러면 호랑이 가 집에 없 으 면 원숭이 가 왕 이 되 고 하위 프로 세 스 는 원래 의 주소 공간 을 계속 사용 합 니 다. 종료 되 거나 새로운 프로그램 을 실행 하면 부모 프로 세 스 가 막 힙 니 다.
 
시스템 호출 에 대한 준비 지식: 시스템 호출 xyz () 의 함수 이름 은 흔히 sys 입 니 다.xyz (), 다음 시스템 호출 은 sysxyz () 의 형태 표현.
 
clone () 인터페이스 
Linux 에서 프로 세 스 를 만 드 는 전체 인터페이스 는 clone () 입 니 다. 이 함 수 는 Linux 커 널 소스 코드 에 정의 되 지 않 고 libc 의 일부분 입 니 다. 새로운 프로 세 스 의 stack 을 만 들 고 sys 를 호출 합 니 다.clone()。그리고 sysclone () 에서 실제로 일 하 는 것 은 dofork (), dofork () 는 앞 뒤 사소한 일 을 많이 했 습 니 다. 프로 세 스 설명자 와 관련 데이터 구 조 를 진정 으로 복사 하 는 것 은 copy 입 니 다.process()。
 
clone () 은 이 모양 입 니 다. clone (fn, arg, flags, child stack, 기타 우리 가 관심 이 없 는 인자) 입 니 다.
 
fn 은 새 프로 세 스 가 실행 해 야 할 함수 입 니 다. arg 는 이 함수 의 인자 입 니 다.
 
flags 의 낮은 바이트 가 새 프로 세 스 가 끝 날 때 오래된 프로 세 스에 보 내 는 신 호 를 지정 합 니 다. 보통 SIGCHLD 이 고, 높 은 바이트 는 clone 입 니 다.flag,clone_flag 는 매우 중요 합 니 다. clone 의 행동 을 결정 합 니 다.재 미 있 는 클 라 이언flag 포함 (이 flag 는 < linux / include / linux / sched. h > 에 정의 되 어 있 습 니 다):
 
CLONE_VM (Virtual Memory): 새 프로 세 스 는 memory descriptor 와 모든 Page Table 을 공유 합 니 다.
CLONE_FS(File System);
CLONE_FILES;
CLONE_SIGHAND (Signal Handling): 새 프로 세 스 공유 신호 설명자 (signal handler 와 현재 blocked / pending 의 신호 대기 열);
CLONE_PTRACE: Debugging 에 사용 합 니 다.
CLONE_PARENT: 오래된 프로 세 스 의 realparent 가 새 프로 세 스 로 등 록 된 parent 와 realparent;
CLONE_THREAD: 새 프로 세 스 가 오래된 프로 세 스 의 스 레 드 그룹 에 가입 합 니 다.
CLONE_STOPPED: 당신 을 만 들 지만 실행 하지 마 세 요.
 
child_stack 은 새 프로 세 스 사용자 상태 stack 의 주소 입 니 다. 오래된 프로 세 스 를 공유 하거나 오래된 프로 세 스 가 새로운 stack 을 할당 해 야 합 니 다.
 
do_fork () 탐구  
책 에 따 르 면 fork () 와 vfork () 는 clone () 을 호출 하 는 기초 위 에 세 워 진 wrapper 함수 (libc 에서 도) 에 불과 합 니 다. 실제로:
 
asmlinkage int sys_fork(struct pt_regs regs)
{
        return do_fork(SIGCHLD, regs.esp, &regs, 0, NULL, NULL);
}

asmlinkage int sys_clone(struct pt_regs regs)
{
        /*      regs        do_fork       */
        return do_fork(clone_flags, newsp, &regs, 0, parent_tidptr, child_tidptr);
}

asmlinkage int sys_vfork(struct pt_regs regs)
{
        return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, &regs, 0, NULL, NULL);
}

 
나 는 처음에 fork () 와 vfork () 가 직접 sys 를 불 렀 다 고 추측 했다.fork () 와 sysvfork () 도 문제 가 없 을 것 입 니 다. 하지만 이 세 시스템 호출 은 모두 pt 만 받 아들 이 는 것 을 알 게 되 었 습 니 다.regs 는 레지스터 의 매개 변수 만 포함 합 니 다. 분명히 clone () 의 작업 중 주요 부분 은 자신 이 받 아들 인 매개 변 수 를 레지스터 의 값 으로 바 꾸 는 것 입 니 다. 사실은 clone 은 fn 과 args 를 stack 에 눌 러 야 합 니 다. 왜냐하면 dofork () 는 이 렇 습 니 다.
 
do_fork (clone flags, stack start, regs, 우리 가 관심 이 없 는 인자 들)
 
그 러 니까 do포크 는 잘 모 르 고 fn 과 args 를 알 필요 가 없습니다. 포크 를 다 한 후에 특정한 return 에서 이전에 process 전환 에 사 용 했 던 기술 (jmp + ret) 과 유사 하 게 CPU 를 stack 에서 주 소 를 되 돌려 주 고 fn 주 소 를 잘못 가 져 왔 습 니 다.이것 이 바로 clone () 이라는 wrapper 가 해 야 할 일 입 니 다. fork () 와 vfork () 는 clone () 을 재 활용 하 는 것 이 좋 습 니 다.
 
do_fork () 호출 완료 copyprocess 이후 CLONE 을 지정 하지 않 는 한STOPPED, wake 를 부른다up_new_task (), 이 안 에는 재 미 있 는 점 이 있 습 니 다.
 
새 프로 세 스 가 같은 CPU 에서 실행 되 고 CLONE 이 지정 되 지 않 았 다 면VM (즉, 결국 분 가 를 하고 CoW 를 사용 해 야 한 다 는 것) 은 새로운 프로 세 스 를 이전 프로 세 스 보다 먼저 실행 하 게 합 니 다. 그러면 새로운 프로 세 스 가 시작 되 자마자 exec 를 사용 하면 CoW 의 시간 을 절약 할 수 있 습 니 다.
 
exec 내부 에서 flush 를 호출 하기 때 문 입 니 다.old_exec () 는 오래된 프로 세 스 와 의 공유 에서 벗 어 나 자신의 신호 설명자, 파일 을 가지 고 원래 의 mmap 를 방출 하여 오래된 프로 세 스 에 대한 모든 지식 을 없 앴 습 니 다. 이것 이 바로 성공 적 으로 실 행 된 exec 가 돌아 오지 않 고 돌아 오지 못 하 는 이유 입 니 다.어쨌든 이후 더 는 공유 되 지 않 았 으 니 당연히 CoW 가 필요 하지 않 을 것 이다.(< Program Execution > 1 장 < exec function > 의 소 개 를 참조 하 십시오.)
 
커 널 프로 세 스 (커 널 스 레 드) 
무엇이 책 에서 말 하 는 '커 널 스 레 드' 입 니까?먼저 리 눅 스 커 널 에서 process 와 thread 를 혼용 하기 때문에 이곳 의 thread 는 실제 적 으로 process 로 이해 할 수 있 고 일반적인 프로 세 스 와 같 으 며 오래된 프로 세 스 중의 커 널 에 속 하 는 스 레 드 로 이해 할 수 없습니다.그래서 다음은 커 널 프로 세 스 라 고 부른다.
 
커 널 프로 세 스 는 다른 도시 와 마찬가지 로 배 치 될 실체 입 니 다. 프로 세 스 와 의 유일한 차이 점 은 커 널 상태 에서 영원히 실행 되 고 커 널 에 속 하 는 일부 선형 주소 (PAGE OFFSET 이상) 에 만 접근 하 는 것 입 니 다.
 
이것 은 그것 을 만 들 때 매우 편리 합 니 다. 그것 을 만 드 는 일반 프로 세 스 와 PAGE 보다 직접 공유 합 니 다.OFFSE 의 선형 주 소 는 어차피 사용 하지 않 습 니 다.
 
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{
        /*       regs    */
        return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
}

  에서 정의 되 었 습 니 다.
 
#define CLONE_KERNEL     (CLONE_FS | CLONE_FILES | CLONE_SIGHAND )
 
제공 가능 kernelthread () 를 호출 할 때 사용 하면 절 약 된 복제 가 더 많아 집 니 다.
 
커 널 프로 세 스 는 불필요 한 사용자 상태 컨 텍스트 에 끌 리 지 않 기 때문에 중요 한 커 널 작업 을 수행 할 수 있 습 니 다. 예 를 들 어 디스크 캐 시 새로 고침, 사용 하지 않 는 pageframe, 서비스 네트워크 연결 등 이 있 습 니 다. 이런 작업 들 은 예전 에 주기 적 으로 실 행 된 프로 세 스 이 고 선형 실행 방식 이 었 습 니 다. 현재 의 커 널 은 사용자 상 태 를 그들 에 게 서 분리 시 켰 습 니 다.그리고 다른 프로 세 스 와 함께 스케줄 링 을 하면 더 좋 은 응답 을 얻 을 수 있 습 니 다.
 
모든 프로 세 스 의 조상 은 프로 세 스 0 입 니 다. idle 프로 세 스 나 swapper 프로 세 스 라 고 합 니 다. 커 널 이 초기 화 될 때 만 든 커 널 프로 세 스 입 니 다. 데이터 구 조 를 초기 화 한 후에 init 프로 세 스 를 만 들 고 init () 함 수 를 실행 합 니 다. 그 중에서 exec 를 호출 하여 init 프로그램 을 실 행 했 습 니 다. 이로써 init 프로 세 스 는 일반 프로 세 스 가 되 었 습 니 다.idle 프로 세 스 이후 cpu 계속 실행idle () 함수 가 할 일이 없습니다.스케줄 러 는 실행 가능 한 프로 세 스 가 없 는 상태 (TASK RUNNING) 에서 만 선택 할 수 있 습 니 다.
 
여러 개의 CPU 가 있 으 면 BIOS 는 처음부터 다른 CPU 를 사용 하지 않 고 하나만 남 겨 두 고 프로 세 스 0 이 그 위 에서 탄생 합 니 다. 다른 CPU 를 활성화 하고 copy 를 통 해process 는 모든 CPU 에 pid 가 0 인 프로 세 스 를 가지 게 하여 모든 CPU 에 0 프로 세 스 가 있 는 국면 을 형성 했다.

좋은 웹페이지 즐겨찾기