Process #1
SIOR 15th Choi, In-choon
1. Introduction
커널의 중요한 객체이며 실행중인 프로그램인 프로세스는 리눅스에서는 테스크(task)
와 동일한 의미로 사용된다. 프로세스는 파일 시스템에서 메모리로 로드한 코드, 데이터(프로그램)와 이를 커널에서 관리하기 위한
task_struct 구조체를 말하며 커널이 제공하는 방법을 통하지 않고서는 다른 프로세스와 상호작용하지 않으며 한 프로세스의
잘못된 동작이 다른 프로세스에 영향을 미치지 않는 각각의 테스크이다.
2. Task Structure
프로세스는 메인
fork 루틴인 do_fork()에 의해서 생성되며, 이때 시스템 프로세스 정보를 복사하고 필요한 레지스터들을 설정한다.
프로세스가 생성될 때마다 alloc_kernel_stack() 함수
(include/asm-m68knommu/processer.h)에서 _get_free_pages() 함수를 호출하여 이 구조체의
메모리를 할당되며 이 스택의 주소는 task_struct의 kernel_stack_page 변수에 담겨있다. 현재
수행중인(TASK_RUNNING 상태) 프로세스의 task_struct를 가리키는 current 전역 변수가
include/asm/current.h 에 정의되어 있다. 한 가지 용어상 주의할 것이 있다면, 다른 OS에서는 다른 문맥으로
사용하는 경우가 있지만 리눅스에서는 태스크(task)와 프로세스(process)를 가리킨다는 것이다. 심볼에서나 소스의
주석에서나 혼용해 사용하기 때문에 이 연재에서도 혼용하여 사용할 것이다. 혼동하지 않기를 바란다.
|
volatile long state; (init = 0) /* -1 unrunnable, 0 runnable, >0 stopped */ |
State
변수는 프로세스의 현재 스케줄링 상태를 나타내기 위한 코드를 포함한다. 이 변수에 대한 값은 같은 파일인
include/linux/sched.h 파일에 정의되어 있는 다음과 같은 값을 가진다. volatile로 선언된 것은 인터럽트
루틴에서 이 값을 바꿀 수 있기 때문이다. 비동기적으로 변하는 것이 반영되도록 하기 위해서이다.
|
#define TASK_RUNNING 0 실행중 #define TASK_INTERRUPTIBLE 1 휴식상태-시그널로 실행중으로 변환가능 #define TASK_UNINTERRUPTIBLE 2 휴식상태-조건이 맞을때까지 대기 #define TASK_ZOMBIE 3 소멸되었지만 테스크 구조가 남아있음 #define TASK_STOPPED 4 시그널에 의해 정지상태에 있음 #define TASK_SWAPPING 5 사용되지 않음 |
스케줄링과 관련하여 프로세스가 스케줄링될 필요가 있음을 나타내는 need_resched 변수가 있다. 이 변수는 참과 거짓의 1과 0의 값을 갖는다.
extern long need_resched;
|
long counter; (init = DEF_ PRIORITY) |
이 변수는 프로세스가 스케줄링되기 전에 실행될 수 있는
tick 시간값을 가지고 있고, 스케줄러는 counter의 값이 큰 프로세스를 실행하도록 선택하는 경향이
있다(kernel/sched.c 파일에 정의된 goodness() 함수 참조). 이는 스케줄링에서 동적인 우선순위처럼 사용된다.
|
long priority; (init = DEF_ PRIORITY) |
프로세스에 할당된 정적 우선순위 값을 가지고 있다.
기본 우선순위는
#define DEF_ PRIORITY (20*HZ/100) 로 정의되어 있는데, ColdFire의 경우 HZ의 값은 100이기
때문에(include/asm-m68knommu/param.h 파일에 정의되어 있다) 기본 우선순위 값은 20이다.
우선순위는
1부터 DEF_PRIORITY*2까지의 값을 가지며 이 정적인 우선순위는 nice() 시스템 콜에 의해서 변경될 수 있다. 이
시스템 콜은 kernel/sched.c 파일에 sys_nice() 함수로 정의되어 있다. 또한 sys_setpriority()
함수로도 변경 가능하다. 이 함수는 kernel/sys.c 파일에 정의되어 있다.
|
unsigned long signal; (init = 0) unsigned long blocked; (init = 0) /* bitmap of masked signals */ |
signal, blocked 변수는 프로세스가 받은 시그널과 받지 않도록 설정한 시그널을 나타내기 위한 변수이다. 이들 변수의 한 비트는 한 시그널에 대한 마스크로 사용된다.
|
unsigned long flags; (init = 0) |
flag
변수는 프로세스가 어떠한 동작을 하고 있는 중인지 좀 더 상세한 정보를 가지고 있는 변수로 이에 해당하는 값 또한
include/linux/sched.h 파일에 다음과 같은 상수로 정의되어 있다. 이 값들은 앞의 state 변수의 값들과 달리
여러 개가 조합으로 설정될 수 있다.
|
* Per process flags #define PF_ALIGNWARN 0x00000001 /* Print alignment warning msgs */ /* Not implemented yet, only for 486*/ #define PF_PTRACED 0x00000010 /* set if ptrace (0) has been called. */ #define PF_TRACESYS 0x00000020 /* tracing system calls */ #define PF_FORKNOEXEC 0x00000040 /* forked but didn't exec */ #define PF_SUPERPRIV 0x00000100 /* used super-user privileges */ #define PF_DUMPCORE 0x00000200 /* dumped core */ #define PF_SIGNALED 0x00000400 /* killed by a signal */ #define PF_STARTING 0x00000002 /* being created */ #define PF_EXITING 0x00000004 /* getting shut down */ #define PF_USEDFPU 0x00100000 /* Process used the FPU this quantum (SMP only) */ #define PF_DTRACE 0x00200000 /* delayed trace (used on m68k) */ #define PF_ONSIGSTK 0x00400000 /* works on signal stack (m68k only) */ |
|
int errno; (init = 0) |
error변수는 가장 최근의 잘못된 시스템 호출을 위한 에러코드를 담고 있다. 이는 시스템 호출로부터 빠져나가기 전 errno 변수에 복사된다.
|
long debugreg[8]; (init = {0,}) |
디버깅 레지스터들의 값을 포함한다. 이는 시스템 호출 ptrace에 의해서만 사용된다.
|
struct exec_domain *exec_domain; (init = &default_exec_domain) |
리눅스는
i386 및 iBCS2(Intel Binary Compliance Standard) 표준을 따르는 시스템에서 프로그램을 실행시킬
수 있는데, 여러 iBCS2 시스템들이 조금씩 차이를 보이기 때문에 iBCS2호환의 다른 운영체계를 에뮬레이션하여 바이너리를
바로 실행할 수 있다. 프로세스가 어떤 운영체계의 에뮬레이션에서 수행되는지를 exec_domain 변수로 나타낸다. 이에 관련된
부분은 include/linux/personality.h과 kernel/exec_domain.c 파일에 정의되어 있다.
|
struct exec_domain default_exec_domain = { "Linux", /* name */ no_lcall7, /* lcall7 causes a seg fault. */ 0, 0xff, /* All personalities. */ ident_map, /* Identity map signals. */ ident_map, /* - both ways. */ NULL, /* No usage counter. */ NULL /* Nothing after this in the list. */ }; |
|
struct linux_binfmt *binfmt; (init = NULL) |
리눅스는 현재 커널 수준에서
9가지의 실행 파일 형식을 지원하고 있다. 즉, elf, elf32, irix, aout, aout32, script,
java, em86, misc이다(2.2.X의 경우). 이 실행 파일 형식에 대한 모듈, 메모리로 로드하는 함수와 메모리 덤프를
하는 함수들에 대한 포인터를 가지고 있는 것이 linux_binfmt 구조체이다.
include/linux/binfmts.h 파일에 다음과 같이 정의되어 있다.
|
struct linux_binfmt { struct linux_binfmt * next; long *use_count; int (*load_binary)(struct linux_binprm *, struct pt_regs * regs); int (*load_shlib)(int fd); int (*core_dump)(long signr, struct pt_regs * regs); }; |
|
struct task_struct *next_task, *prev_task; (init = &init_task, &init_task) struct task_struct *next_run, *prev_run; (init = &init_task, &init_task) |
리스트의 시작과 끝은 전역변수 init_task안에 포함되며, 유닉스 시스템에서 프로세스들은 서로 독립적으로 존재하지 않는다.
모든 프로세스는 init_task부터 시작하여 next_task, prev_task 포인터에 따라 일렬로 연결된다. 이를 이용하여 모든 프로세스에 대한 검색을 할 필요가 있을 때는 다음과 같은 매크로를 사용한다.
#define for_each_task(p) \
for(p=&init_task ; (p=p->next_task) !=&init_task ;)
|
unsigned long saved_kernel_stack; (init = 0) |
|
unsigned long kernel_stack_page; (init = (unsigned long) &init_kernel_stack) |
프로세스가 사용하는 스택의 주소를 담고 있다.
|
int exit_code, exit_signal; (init = 0) |
프로세스가 종료하는 시점에 exit_code 변수는 프로세스의 종료값을 가지고, exit_signal 변수는 SIGCHLD 시그널값을 가진다. 이 SIGCHLD 시그널은 종료하는 프로세스의 부모 프로세스에 전해진다.
|
unsigned long personality; (init = 0) |
personality
변수는 include/linux/personality.h 파일 정의된 PER_ 접두어의 상수값을 갖는다. 당연히 기본
exec_domain은 리눅스이고 이는 kernel/exec_domain.c 파일에 default_exec_domain 변수로
정의되어 있다. personality의 기본값은 PER_ LINUX이다.
|
int dumpable:1; (init = 0) |
dumpable 변수는 프로세스의 euid와 uid, egid와 gid가 같은 때 1로 설정되어 프로세스에 대한 메모리 덤프를 가능하도록 한다.
|
int did_exec:1; (init = 0) |
did_exec 변수는 프로세스가 exec 되었음을 나타내며, 그래서 exec() 시스템 콜에 의해서 1로 설정된다. 이는 setpgid() 시스템 콜에서 이미 exec이 된 프로세스의 pgid를 변경하지 못하게 한다.
|
int pid; (init = 0) int pgrp; (init = 0) int tty_old_pgrp; (init = 0) int session; (init = 0) /* boolean value for session group leader */ int leader; (init = 0) |
모든 프로세스는 자신만의 ID번호, pid를 가지고 있다. 이것들은 프로세스 그룹, pgrp, 그리고 session에 할당된다. 모든 세션은 하나의 리더 프로세스, leader을 가진다.
pid
변수는 프로세스의 ID, pgrp 변수는 프로세스 그룹 ID, session 변수는 세션 ID이고 leader 변수는 세션
리더인지를 나타내는 변수이다. 프로세스 그룹이나 세션에 대한 자세한 사항은 참고 자료에 언급한 Stevens의 책을 참조하기
바란다.
|
int groups[NGROUPS]; (init = {NOGROUP,}) |
groups[]
배열은 이 프로세스가 추가로 속하는 그룹 ID를 가지고 있으며, NGROUPS 변수는 그 최대 그룹의 수이다. 대부분의 유닉스
시스템처럼 리눅스도 프로세스가 동시에 여러 사용자 그룹에 할당되는 것을 허용한다. NGROUPS가 –1 이면 이 항목은 사용되지
않음을 뜻한다.
|
struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr; (init = &init_task, &init_task, NULL, NULL, NULL) |
포인터
p_opptr(original parent), p_pptr(parent), p_cptr(child), p_ysptr(young
sibling), p_osptr(old sibling) 변수에 의해 각 프로세스들은 부모, 자식, 형제간의 가족 관계가
형성된다. runqueue라는 실행중인 프로세스의 연결 리스트가 있다. 이는 init_task 에서 시작하여 next_run,
prev_run 포인터로 연결되어 있으며 이 리스트에는 프로세스가 스케줄러에 의해 실행 상태가 될때 추가된다. 이 리스트를
관리하는 add_to_runqueue(), del_from_runqueue(), move_last_runqueue(), move_first_runqueue() 함수가 kernel/sched.c 파일에 정의되어 있다.
|
struct wait_queue *wait_chldexit; (init = NULL) |
시스템 호출
wait4를 실행하는 프로세스는 자식 프로세스가 소멸할 때까지 정지해야만 한다. 그것은 자신 소유의 작업구조체 안에
wait_chldexit 대기큐를 포함시키고, 상태 플러그의 값을 TASK_INTERRUPTABLE 로 설정하고, 컨트롤을
스케줄러에게 넘긴다. 프로세스가 소멸될 때, 이 큐를 통해서 소멸되는 프로세스의 부모 프로세스에게 신호를 보내게 된다.
sys_wait4() 함수가 kernel/exit.c에 정의되어 있다.
|
unsigned short uid,euid,suid,fsuid; (init = 0, 0, 0, 0) unsigned short gid,egid,sgid,fsgid; (init = 0, 0, 0, 0) |
접근을 제어하기 위해서 모든 프로세스는 사용자
ID인 uid와 그룹 ID인 gid를 가진다. 이것들은 새로운 프로세스가 fork 시스템 호출에 의해서 생성될 때, 부모
프로세스로부터 자식 프로세스에게 상속되어진다. 그러나 실제적인 접근제어를 위해 effective 사용자 ID인 euid,
effective 그룹 ID인 egid가 사용된다.
fsuid 변수는 파일 시스템 검사를 위한 set 사용자 ID로 access() 시스템 콜과 NFS 데몬에서 사용된다
|
unsigned long timeout, policy, rt_priority; (init = 0,SCHED_OTHER,0) |
policy 변수는 스케줄링 정책에 대한 설정으로 다음의 값을 가질 수 있다.
|
* Scheduling policies #define SCHED_OTHER 0 #define SCHED_FIFO 1 #define SCHED_RR 2 |
rt_priority
변수는 실시간 스케줄링을 위해 리눅스 1.3.81에서부터 지원하는 우선순위 설정값이다. 이는
sched_setsecheduler(), sched_setparam() 시스템 콜로 설정할 수 있다. 이 두 함수에 대한 구현은
kernel/sched.c 파일의 sys_sched_setscheduler(), sys_sched_setparam(),
setscheduler() 함수이다.
|
unsigned long it_real_value, it_prof_value, it_virt_value; (init = 0, 0, 0) unsigned long it_real_incr, it_prof_incr, it_virt_incr; (init = 0, 0, 0) |
프로세스가 가지고 있는 세 개의 타이머가 있다.
리얼(real) 타이머, 프로파일(profile) 타이머, 가상(virtual) 타이머이다. 각 타이머의 주기값은 _incr
접미어 변수에 저장되고 현재 시간이 다 될 때까지 남은 값은 _value 접미어 변수가 가지고 있다. 사용자의 입장에서는 리얼
타이머에 타이머 핸들러를 등록하여 시간이 다 되면 특정 동작을 하게 할 수 있다. 이 타이머 핸들러에 대한 정보를 담고 있는
것이 real_timer 변수이다. struct timer_list는 include/linux/timer.h 파일에 정의되어
있다.
|
long utime, stime, cutime, cstime, start_time; (init 0, 0, 0, 0, 0) |
다양한 시간들이 프로세스들을 의해서 사용된다. 리눅스 하에서 시간들은 항상 ‘ticks’안에서 측정된다. 이 틱들은 10밀리 초마다 타이머 칩에 의해서 생성되며, 타이머 인터럽트에 의해서 카운트된다.
utime
과 stime은 각각 프로세스가 사용자 모드와 시스템 모드에서 소비한 시간을 담고 있으며, cutime과 cstime은 모든
자식 프로세스들을 위한 각각의 대응하는 시간들의 총합을 담고 있다. start_time은 현재 실행중인 프로세스가 생성된 시간을
담고 있다.
|
unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap; (init = 0, 0, 0, 0, 0, 0) unsigned long swap_address; (init = 0) unsigned long old_maj_flt; (init = 0) /* old value of maj_flt */ unsigned long dec_flt; (init = 0) /* page fault count of the last time */ unsigned long swap_cnt; (init = 0) /* number of pages to swap on next pass */ |
중요한 메모리관련 변수로 min_flt, maj_flt, nswap, cmin _flt, cmaj_flt, cnswap 변수는 메모리 사용 통계를 가지는 변수로 getrusage() 시스템 콜로 그 값을 알 수 있다.
swappable 변수는 mm/vmscan.c 파일의 swap_out() 함수에서 프로세스가 스왑될 수 있는지 검사하는 데 사용된다. 이 값은 fork시에 프로세스의 초기화 도중에 스왑되지 않게 한다
|
struct rlimit rlim[RLIM_NLIMITS]; (init = INIT_RLIMIT) |
모든 프로세스들은 시스템 호출
setrlimit()와 getrlimit()를 이용하여 자원 사용에 대한 제한을 체크 할 수 있다. rlim_max 변수는
하드(hard) 최대값이고, rlim_cur 변수는 소프트(soft) 최대값이다(현재 각 자원의 사용 상황은 같은 파일의
struct rusage 구조체에 의해 정의된다).
struct rlimit는 include/linux/resource.h 파일에 다음과 같이 정의되어 있다.
|
struct rlimit { long rlim_cur; long rlim_max; }; |
rlim 변수는 각 자원에 대한 항목으로 구성된 배열로 어떠한 자원의 종류가 있는지는 include/asm/resources.h 파일의 RLIM_ 접두어 상수들을 보면 알 수 있다.
|
* Resource limits #define RLIMIT_CPU 0 /* CPU time in ms */ #define RLIMIT_FSIZE 1 /* Maximum filesize */ #define RLIMIT_DATA 2 /* max data size */ #define RLIMIT_STACK 3 /* max stack size */ #define RLIMIT_CORE 4 /* max core file size */ #define RLIMIT_RSS 5 /* max resident set size */ #define RLIMIT_NPROC 6 /* max number of processes */ #define RLIMIT_NOFILE 7 /* max number of open files */ #define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space*/ #define RLIMIT_AS 9 /* address space limit */ #define RLIM_NLIMITS 10 |
이 자원에 대한 제한 사항은 setrlimit() 시스템 콜로 변경을 할 수 있다. 이 함수는 kernel/sys.c 파일에 sys_setrlimit() 함수로 구현되어 있다.
|
unsigned short used_math; (init = 0) char comm[16]; (init = “swapper”) |
used_math
변수는 FPU 에뮬레이션을 할 경우 1로 설정되고 그렇지 않으면 0값을 갖는다. 이 에뮬레이션을 사용할 지는 커널 컴파일
설정에서 선택할 수 있다. 현재는 대부분 FPU는 기본적으로 제공되기 때문에 사용되지 않는다.
comm 배열은 프로세스의 이름 중 첫 15자만을 저장한다. exec시에 설정되며(fs/exec.c 파일의 flush_old_exec() 함수에서) 경로명은 제외된다.
|
int link_count; (init = 0) struct tty_struct *tty; /* NULL if no tty */ (init = NULL) |
link_count 변수는 실행 파일이 심볼릭 링크로 연결되어 있는 경우, 그 중첩된 링크의 수가 5를 넘지 않도록 링크 수를 저장하는 역할을 한다. fs/namei.c 파일의 do_follow_link() 함수에서 사용된다.
tty 변수는 이 프로세스에서 사용하는 제어 터미널에 대한 struct tty_struct 구조체 변수이다. 데몬과 같은 프로세스의 경우 제어 터미널을 가지고 있지 않기 때문에 tty는 NULL 값을 갖는다.
|
struct sem_undo *semundo; (init = NULL) struct sem_queue *semsleeping; (init = NULL) |
리눅스는 커널에서
System V와 호환되는 Interprocess Communication을 사용한다. 다른 프로세스들과 세마포어를 이용하여
자원을 공유하는데, semundo 변수는 프로세스가 종료할 때, 그 프로세스가 잡고 풀지 않고 남겨둔 세마포어를 풀어주는 데
필요하다.
프로세스가 세마포어에 의해서 블럭이 될 때
struct sem_queue 구조체가 하나 할당이 되어, 그 세마포어의 대기 큐에 삽입된다. 이 새로 할당된
struct_queue 구조체를 가리키는 것이 semsleeping 변수이다. 이 동작은 ipc/sem.c 파일의
sys_semop() 함수에서 확인할 수 있다.
|
struct desc_struct *ldt; (init = NULL) |
이 항목은 표준 리눅스 프로그램과 비교해서 더 많은 정보와 다른 메모리 관리 루틴들을 필요로 하는 Wine 윈도우 에뮬레이터를 위해서 특별히 포함되었다.
|
struct thread_struct tss; (init = INIT_TSS) |
struct
thread_struct 구조체는 include/asm/processor.h 파일에 정의되어 있으며, 사용자 모드에서 커널모드로
진입할 때 현재 프로세스에 대한 모든 정보를 저장한다. 이 구조체는 쓰레드에 해당되는 레지스터 값과 세그먼트, 디버깅 레지스터,
부동 소수점 정보 등을 담고 있다.
|
struct thread_struct { unsigned long ksp; /* kernel stack pointer */ unsigned long usp; /* user stack pointer */ unsigned short sr; /* saved status register */ unsigned short fs; /* saved fs (sfc, dfc) */ unsigned long crp[2]; /* cpu root pointer */ unsigned long esp0; /* points to SR of stack frame */ unsigned long fp[8*3]; unsigned long fpcntl[3]; /* fp control regs */ unsigned char fpstate[FPSTATESIZE]; /* floating point state */ }; #define INIT_TSS { \ sizeof(init_kernel_stack) + (long) init_kernel_stack, 0, \ PS_S, KERNEL_DS, \ {0, 0}, 0, {0,}, {0, 0, 0}, {0,} \ } |
|
struct fs_struct *fs; (init = &init_fs) |
같은 sched.h 파일에 정의되어 있는 struct files_struct 구조체의 변수인 files는 오픈 파일 테이블이라고 불리는 것이다. 프로세스가 사용하기 위해서 연 파일의 디스크립터와 그 밖의 정보들을 담고 있다.
struct fs_struct 구조체 또한 sched.h 파일에 정의되어 있으며 이 프로세스의 루트 디렉토리와 현재 디렉토리 정보를 가지고 있다. 이 두 구조체의 정의는 다음과 같다.
|
struct files_struct { int count; fd_set close_on_exec; fd_set open_fds; struct file * fd[NR_OPEN]; }; #define INIT_FILES { \ 1, \ { { 0, } }, \ { { 0, } }, \ { NULL, } \ } struct fs_struct { int count; unsigned short umask; struct inode * root, * pwd; }; #define INIT_FS { \ 1, \ 0022, \ NULL, NULL \ } |
|
struct mm_struct *mm; (init = &init_mm) |
include/linux/sched.h
파일에 정의된 mm_struct는 프로세스의 메모리 상에서의 위치를 나타내는 메모리 맵 정보를 가지고 있다. 다음과 같이
정의되어 있다. 이 구조체의 첫 세 멤버 변수의 형식인 struct vm_area_struct는 가상 메모리에 대한 정보이다.
이는 리스트와 AVL 트리로 관리된다.
|
struct mm_rblock_struct { int size; int refcount; void * kblock; }; struct mm_tblock_struct { struct mm_rblock_struct * rblock; struct mm_tblock_struct * next; }; struct mm_struct { int count; unsigned long context; unsigned long start_code, end_code, start_data, end_data; unsigned long start_brk, brk, start_stack, start_mmap; unsigned long arg_start, arg_end, env_start, env_end; unsigned long rss, total_vm, locked_vm; unsigned long def_flags; struct wait_queue * vforkwait; struct inode * executable; struct mm_tblock_struct tblock; }; #define INIT_MM { \ 1, \ 0, \ 0, 0, 0, 0, \ 0, 0, 0, 0, \ 0, 0, 0, 0, \ 0, 0, 0, \ 0, \ 0, \ 0, \ { 0, 0} } |
|
struct signal_struct *sig; (init = &init_signals) |
sig 변수는 각 시그널에 등록된 핸들러 정보를 가지고 있는 struct signal_struct 구조체 변수이다. 이 구조체는 task_struct 구조체가 정의된 바로 앞에 다음과 같이 정의되어 있다.
|
struct signal_struct { int count; struct sigaction action[NSIG]; }; #define INIT_SIGNALS { \ 1, \ { {0,}, } } |
|
#ifdef __SMP__ int processor; int last_processor; int lock_depth; /* Lock depth. We can context switch in and out of holding a syscall kernel lock... */ #endif |
이 세 변수는
SMP 구현과 관련이 있다. lock_depth는 프로세서 lock의 중첩된 깊이를 나타낸다. 아무런 lock이 걸리지 않으면
-1의 값을 갖는다. 현재 프로세스가 실행되고 있는 프로세서 번호가 processor 변수, 이전에 마지막으로 실행된 프로세스
번호가 last_processor 변수에 저장된다. SMP를 사용하지 않는다면 이 변수들 또한 사용되지 않기 때문에 신경 쓸
필요가 없다.
|
참고문헌 프로그램 세계 Linux world 3월호 기사 “프로세스의 구조와 생성, 소멸” (임종균) Linux Kernel Internal 2nd Ed. (Michael Beck 등, Addison-Wesley) Linux Kernel 2.0.38 Source uClinux Kernel 2.0.38 Source The Linux Kernel (David A. Rusling, LDP) |
* struct task_struct
struct task_struct {
/* these are hardcoded - don't touch */
volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
long counter;
long priority;
unsigned long signal;
unsigned long blocked; /* bitmap of masked signals */
unsigned long flags; /* per process flags, defined below */
int errno;
long debugreg[8]; /* Hardware debugging registers */
struct exec_domain *exec_domain;
/* various fields */
struct linux_binfmt *binfmt;
struct task_struct *next_task, *prev_task;
struct task_struct *next_run, *prev_run;
unsigned long saved_kernel_stack;
unsigned long kernel_stack_page;
int exit_code, exit_signal;
/* ??? */
unsigned long personality;
int dumpable:1;
int did_exec:1;
/* shouldn't this be pid_t? */
int pid;
int pgrp;
int tty_old_pgrp;
int session;
/* boolean value for session group leader */
int leader;
int groups[NGROUPS];
/*
* pointers to (original) parent process, youngest child, younger sibling,
* older sibling, respectively. (p->father can be replaced with
* p->p_pptr->pid)
*/
struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr;
struct wait_queue *wait_chldexit; /* for wait4() */
unsigned short uid,euid,suid,fsuid;
unsigned short gid,egid,sgid,fsgid;
unsigned long timeout, policy, rt_priority;
unsigned long it_real_value, it_prof_value, it_virt_value;
unsigned long it_real_incr, it_prof_incr, it_virt_incr;
struct timer_list real_timer;
long utime, stime, cutime, cstime, start_time;
/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;
int swappable:1;
unsigned long swap_address;
unsigned long old_maj_flt; /* old value of maj_flt */
unsigned long dec_flt; /* page fault count of the last time */
unsigned long swap_cnt; /* number of pages to swap on next pass */
/* limits */
struct rlimit rlim[RLIM_NLIMITS];
unsigned short used_math;
char comm[16];
/* file system info */
int link_count;
struct tty_struct *tty; /* NULL if no tty */
/* ipc stuff */
struct sem_undo *semundo;
struct sem_queue *semsleeping;
/* ldt for this task - used by Wine. If NULL, default_ldt is used */
struct desc_struct *ldt;
/* tss for this task */
struct thread_struct tss;
/* filesystem information */
struct fs_struct *fs;
/* open file information */
struct files_struct *files;
/* memory management info */
struct mm_struct *mm;
/* signal handlers */
struct signal_struct *sig;
#ifdef __SMP__
int processor;
int last_processor;
int lock_depth; /* Lock depth. We can context switch in and out of holding a syscall kernel lock... */
#endif
