링크 ux 커 널 PID 관리

7849 단어 linuxkernel
PID 즉, 프로 세 스 설명자 가 Liux kernel 에서 의 배분 과 관리 가 복잡 합 니 다.본 고 는 관련 데이터 구조 와 함 수 를 분석 했다.(코드 v 3.0.3 기반)
PID 와 관련 된 데이터 구조 가 있 습 니 다.
struct pid
{
atomic_t count;
unsigned int level;
struct hlist_head tasks[PIDTYPE_MAX];
struct rcu_head rcu;
struct upid numbers[1];
};

그 중에서 count 는 이 데이터 구 조 를 가리 키 는 인용 횟수 입 니 다.
level 은 pid 가 pid namespace 에서 몇 번 째 층 에 있 습 니 다. level = 0 일 때 global namespace, 즉 최고 층 을 표시 합 니 다. pid namespace 라 는 데이터 구 조 는 뒤에서 설명 합 니 다.
tasks [PIDTYPE MAX] 배열 의 모든 요 소 는 서로 다른 의 미 를 나 타 냅 니 다. PIDTYPE MAX 는 pid 가 표시 하 는 형식의 최대 수 를 나 타 냅 니 다. 이 값 은 enum pid type 에 정 의 됩 니 다.
enum pid_type
{
PIDTYPE_PID,
PIDTYPE_PGID,
PIDTYPE_SID,
PIDTYPE_MAX
};
PIDTYPE PID 는 프로 세 스 설명자 (PID) 를 대표 합 니 다. PIDTYPE PGID 는 프로 세 스 설명 자 를 대표 합 니 다. 프로 세 스 (process)그룹 을 구성 할 수 있 고 그룹 설명자 가 있 습 니 다. 이러한 장점 은 이 그룹 설명 자 를 위 한 신호 가 있 으 면 그룹 내 모든 프로 세 스 를 받 아들 일 수 있 습 니 다. PIDTYPE SID 는 그룹 설명자 에 대해 하나의 그룹 을 만들어 session 을 만 드 는 것 입 니 다. 이것 은 더 높 은 차원 의 추상 입 니 다.
tasks [i] 가 가리 키 는 것 은 해시 표 입 니 다. 예 를 들 어 tasks [PIDTYPE PID] 가 가리 키 는 것 은 PID 의 해시 표 입 니 다.
rcu 도 메 인 에서 나 도 도대체 무엇 을 하 는 지 알 지 못 했다. (
numbers [1] 도 메 인 은 upid 구조 체 를 가리 키 고 있 습 니 다. numbers 배열 의 본 뜻 은 서로 다른 pid namespace 를 표시 하 는 것 입 니 다. 하나의 PID 는 서로 다른 namespace 에 속 할 수 있 습 니 다. numbers [0] 는 global namespace, numbers [i] 를 표시 합 니 다.i 층 namespace 를 표시 합 니 다. i 가 클 수록 해당 등급 이 낮 습 니 다. 현재 이 배열 은 하나의 요소 만 있 습 니 다. 즉, global namespace 입 니 다. 따라서 namespace 의 개념 은 pid 를 도 입 했 지만 실제로 사용 되 지 않 았 습 니 다. 미래 버 전에 서 사용 할 수 있 습 니 다.
다음은 upid 라 는 데이터 구 조 를 살 펴 보 겠 습 니 다.
struct upid {
int nr;
struct pid_namespace  × ns;
struct hlist_node pid_chain;
};

pid 구조 체 의 numbers 도 메 인 은 upid 구조 체 를 가리 키 고 있 습 니 다. 이 구조 체 는
nr 는 pid 의 값, 즉 task struct 에서 pid t pid 필드 의 값 입 니 다.
ns 는 이 pid 가 있 는 namespace 를 가리 키 고 있 습 니 다.
Liux 커 널 은 모든 프로 세 스 의 upid 를 하나의 해시 표 (pid hash) 에 저장 하여 찾기 쉽 고 통일 적 으로 관리 할 수 있 습 니 다. 따라서 pid 구조 체 의 numbers [0] 가 가리 키 는 upid intance 는 pid hash 에 저 장 됩 니 다. pid chain 즉 해시 표 의 노드 를 통 해 이 upid 가 있 는 pid hash 의 위 치 를 찾 을 수 있 습 니 다.
다음은 pid namespace 구조 체 를 살 펴 보 겠 습 니 다.
struct pid_namespace {
struct kref kref;
struct pidmap pidmap[PIDMAP_ENTRIES];
int last_pid;
struct task_struct *child_reaper;
struct kmem_cache *pid_cachep;
unsigned int level;
struct pid_namespace *parent;
};

kref 는 pid namespace 를 가리 키 는 개 수 를 표시 합 니 다.
pidmap 구조 체 는 pid 를 할당 하 는 비트 맵 을 표시 합 니 다. 새로운 pid 를 할당 해 야 할 때 비트 맵 을 찾 고 bit 가 0 인 위 치 를 찾 아 1 을 병 치 한 다음 통계 데이터 필드 (nr free) 를 업데이트 합 니 다.
struct pidmap {
atomic_t nr_free;
void *page;
};
nr free 는 분배 할 수 있 는 pid 의 수량 을 표시 합 니 다.
page 는 pid 를 저장 하 는 물리 페이지 를 가리킨다.
그래서 pidmap [PIDMAP ENTRIES] 도 메 인 은 이 pid namespace 에서 pid 가 분 배 된 상황 을 나타 낸다.
last pid 는 pidmap 의 분배 에 사 용 됩 니 다. 마지막 으로 분 배 된 pid 의 위 치 를 가리 키 고 있 습 니 다. (특별히 확인 되 지 않 음)
child reaper 는 프로 세 스 를 가리 키 고 있 습 니 다. 이 프로 세 스 는 하위 프로 세 스 가 끝 날 때 시 체 를 수 거 하 는 역할 을 합 니 다. 현재 global namespace 만 지원 하기 때문에 child reaper 는 init task 를 가리 키 고 있 습 니 다.
pid cachep 도 메 인 은 pid 를 할당 하 는 slab 의 주 소 를 가리 키 고 있 습 니 다.
level 은 이 namespace 가 어느 층 에 있 는 지 표시 합 니 다. 지금 여 기 는 0 입 니 다.
parent 는 이 namespace 의 아버지 namespace 를 가리 키 고 있 습 니 다. 지금 은 NULL 이 분명 합 니 다.
pid namespace 와 관련 된 데이터 구 조 를 소개 하 였 습 니 다. 디자인 의 본 뜻 이 무엇 인지 살 펴 보 겠 습 니 다. Linux 에서 namespace 라 는 개념 을 추가 하 는 목적 은 가상 화 와 편리 한 관 리 를 위 한 것 입 니 다. 예 를 들 어 서로 다른 namespace 에서 pid 와 같은 프로 세 스 를 가 질 수 있 습 니 다. pid namespace 의 결 구 는 계층 화 되 어 있 습 니 다. 또한 child namespace 에서 의 프로 세 스 는 반드시 parent namespace 의 영상 이 있 을 것 입 니 다.쏴 라. 이 말 은 이해 하기 어 려 울 수도 있다. 아래 그림 과 결합 할 수 있다.
위의 그림 은 예 를 들 어 pid hash 전역 해시 표 에 15 개 (9 + 3 + 3) upid 인 스 턴 스 를 저장 합 니 다.
앞에서 pid, upid, pid namespace 에 관 한 개념 을 많이 소 개 했 습 니 다. 다음은 task struct 와 의 관 계 를 살 펴 보 겠 습 니 다.
오른쪽 아래 에 있 는 타원형 점선 상 자 는 전역 pid hash 입 니 다. 분 배 된 upid 는 이 hash 표 에 저 장 됩 니 다.
왼쪽 아래 에 있 는 타원형 점선 상 자 는 pid namespace 의 관 계 를 표시 합 니 다. 물론 현재 한 층 만 있 습 니 다.
Linux 커 널 은 task struct 를 통 해 프로 세 스 를 관리 합 니 다. task struct 에 서 는 pid 와 관련 된 도 메 인 이 있 습 니 다.
struct task_struct
{
...
pid_t pid;
pid_t tgid;
struct task_struct *group_leader;
struct pid_link pids[PIDTYPE_MAX];
struct nsproxy *nsproxy;
...
};
pid 는 이 프로 세 스 의 프로 세 스 설명 자 를 말 합 니 다. 다음 에 fork 함수 에서 어떻게 값 을 부여 하 는 지 소개 합 니 다.
tgid 는 이 프로 세 스 의 스 레 드 설명 자 를 말 합 니 다. Liux 커 널 에서 스 레 드 를 특별한 처리 하지 않 았 거나 task struct 에서 관리 합 니 다. 따라서 커 널 의 측면 에서 볼 때 사용자 상태의 스 레 드 는 본질 적 으로 프로 세 스 입 니 다. 같은 프로 세 스 (사용자 상태) 에서 서로 다른 스 레 드 는 tgid 가 같 지만 pid 는 각각 다 릅 니 다. 메 인 스 레 드 는 group leader 입 니 다.(메 인 스 레 드 는 다른 모든 하위 스 레 드 를 만 듭 니 다). 단일 스 레 드 프로 세 스 (사용자 상태 각도) 라면 pid 는 tgid 와 같 습 니 다.
사용자 상태 프로그램 에 있어 서 getpid () 함 수 를 호출 하 는 것 은 tgid 입 니 다. 왜 그런 지 생각해 보 세 요.:)
group leader 는 다 중 스 레 드 모드 에서 주 스 레 드 를 가리 키 는 것 외 에 도 하나의 용도 가 있 습 니 다. 일부 프로 세 스 가 그룹 을 구성 할 때 (PIDTYPE PGID) 이 도 메 인 은 이 그룹의 leader 를 가리 키 고 있 습 니 다.
nsproxy 포인터 가 namespace 와 관련 된 도 메 인 을 가리 키 고 있 습 니 다.
struct nsproxy {
atomic_t count;
struct uts_namespace *uts_ns;
struct ipc_namespace *ipc_ns;
struct mnt_namespace *mnt_ns;
struct pid_namespace *pid_ns;
struct net           *net_ns;
};
nsproxy 도 메 인 을 통 해 이 task struct 가 어느 pid namespace 에 속 하 는 지 알 수 있 습 니 다. 물론 지금 은 global namespace 가 분명 합 니 다. (이미 여러 번 말 했 습 니 다:)
다른 도 메 인 들 도 namespace 와 관련 이 있 으 니 설명 을 하지 않 겠 습 니 다.
pids [PIDTYPE MAX] 는 이 task struct 와 관련 된 pid 구조 체 를 가리킨다.
pid link 의 정 의 는 다음 과 같 습 니 다.
struct pid_link
{
struct hlist_node node;
struct pid *pid;
};

Liux 커 널 에서 이 task struct 에 대응 하 는 pid 를 얻 으 려 면 task pid () 함 수 를 호출 할 수 있 습 니 다. 이 함수 의 실현 은 매우 간단 합 니 다.
static inline struct pid *task_pid(struct task_struct *task)
{
 return task->pids[PIDTYPE_PID].pid;
}

이로부터 저 는 pid 와 관련 된 데이터 구 조 를 소 개 했 습 니 다. 다음은 pid 와 관련 된 사용 을 다시 보 겠 습 니 다.
(1) fork 함수 에서 어떻게 새로운 pid 를 분배 합 니까?
fork (), vfork (), clone () 함 수 는 결국 do fork () 를 호출 하여 작업 을 진행 합 니 다. 새로운 pid 분 배 는 copy process () 함수 에서 이 루어 집 니 다. do fork () 함 수 는 copy process () 를 호출 합 니 다. 이들 의 관 계 는 다음 글 에서 소개 하 겠 습 니 다.
static struct task_struct *copy_process(unsigned long clone_flags,
                                        unsigned long stack_start,
                                        struct pt_regs *regs,
                                        unsigned long stack_size,
                                        int __user *child_tidptr,
                                        struct pid *pid,
                                        int trace)
{
...
if (pid != &init_struct_pid) {
    retval = -ENOMEM;
    pid = alloc_pid(p->nsproxy->pid_ns);
    if (!pid)
        goto bad_fork_cleanup_io;
}

p->pid = pid_nr(pid);
p->tgid = p->pid;
if (clone_flags & CLONE_THREAD)
    p->tgid = current->tgid;

...
}

나 는 pid 와 분 배 된 코드 만 열거 했다.
alloc pid 함 수 는 새로운 pid struct 를 할당 합 니 다. 쉽게 말 하면 이 함수 의 기능 은 pidmap 에서 사용 되 지 않 은 pid bit 를 찾 는 것 입 니 다. 찾 을 수 없 으 면 사용 가능 한 pid 가 없다 는 것 을 설명 합 니 다. 이 namespace 가 있 는 pid 를 모두 사용 한 다음 pid hash 의 해시 표 에 저장 한 다음 pid 구조 체 를 되 돌려 줍 니 다.
pid nr 함수 의 실현 도 간단 합 니 다.
static inline pid_t pid_nr(struct pid *pid)
 {
         pid_t nr = 0;
         if (pid)
                 nr = pid->numbers[0].nr;
         return nr;
 }
이 pid 가 있 는 global namespace 의 값 을 되 돌려 줍 니 다.
다음 몇 줄 의 코드 는 프로 세 스 와 스 레 드 의 tgid 값 을 구분 하 는 데 사 용 됩 니 다.
pid 와 관련 된 데이터 구조, 함수 정 의 는 include / linux / pid. h include / linux / pid namespace. h 및 kernel / pid. c kernel / pid namespace. c 에서 찾 을 수 있 습 니 다.
주:
(1) 본문 에서 어떤 잘못 이 발견 되면 지적 해 주세요. 감사합니다!
(2) 여러분 과 의 교 류 를 환영 합 니 다.
(3) 본 고 는 오리지널 이 므 로 전재 할 필요 가 있 으 면 출처 를 밝 혀 주 십시오.

좋은 웹페이지 즐겨찾기