1. 커널 코딩 스타일
1. 공식 문서
2. 정리
- 8칸 탭을 사용한다.
- 한 줄에 80열을 넘지 않는다.
- statement는 해당 문이 시작하는 줄에서 중괄호를 연다.
- 이름 있는 함수는 다음 줄에서 시작한다.
- 한 문장으로 충분할 때 불필요하게 중괄호를 사용하지 않는다.
- 조건문의 한 블록이 여러 줄일 경우는 모든 조건에 중괄호를 사용한다.
- sizeof, typeof, alignof 및 __attribute__를 제외하고 대부분의 경우 키워드 뒤에 공백을 사용한다.
- 포인터는 함수나 변수 이름에 인접하고 타입과 인접하지 않는다.
- 함수는 짧고 간결해야 하며 한 가지 기능만 수행해야 한다.
-지역 변수의 수가 5~10개를 넘지 않도록 한다.
- EXPORT 매크로는 함수 바로 다음 줄에 작성한다.
- 주석은 코드가 어떻게 작동하는지가 아닌 무엇을 하는지 알려주어야 한다.
- 하나의 타입에 여러 변수를 선언하지 않도록 한다.
- 매크로는 대문자로 지정하는 것이 좋지만, 함수와 유사한 경우 소문자로 지정할 수 있다.
- 여러 문이 포함된 매크로는 do-while 블록으로 묶어야 한다.
- 조건이 포함된 매크로는 사용하지 않는 것이 좋다. - 인라인 키워드를 많이 사용하면 커널이 커져 페이지 캐시에 사용할 수 있는 메모리가 줄기 때문에 시스템 전체 속도가 느려진다. 3줄 이상의 코드가 포함된 함수에 인라인을 넣지 않도록 한다.
- 함수 이름이 액션 혹은 명령인 경우 오류 코드 정수를 반환하고 술어인 경우 성공 여부(bool)를 반환하도록 한다.
- bool은 컴파일된 아키텍처에 따라 값의 크기와 정렬이 달라지므로 캐시 레이아웃이나 값의 크기가 중요한 경우 사용하지 않도록 한다.
- 커널 헤더에는 적절한 매크로들이 선언되어 있으므로, 필요한 경우 가져다 사용하면 좋다.
- 인라인 어셈블리를 사용할 수도 있으나, 가능하면 어셈블리 함수는 .S 파일에 넣고 C 프로토타입은 C 헤더 파일에 정의한다.
- .c 파일에 전처리 조건문을 사용하면 코드를 읽기 어렵기 때문에 사용하지 않는 것이 좋다. 대신 헤더 파일에 사용하고 이를 .c 파일에서 호출하도록 한다.
- 잠재적으로 사용되지 않을 수 있는 함수나 변수는 전처리기 조건부로 래핑하는 대신 __maybe_unused로 표시하는 것이 좋다.
2. include/linux/sched.h 자료구조분석
1. sched_entity
1. 코드
struct sched_entity {
struct load_weight load;
struct rb_node run_node;
struct list_head group_node;
unsigned int on_rq;
u64 exec_start;
u64 sum_exec_runtime;
u64 vruntime;
u64 prev_sum_exec_runtime;
u64 nr_migrations;
int depth;
struct sched_entity *parent;
struct cfs_rq *cfs_rq;
struct cfs_rq *my_q;
unsigned long runnable_weight;
struct sched_avg avg;
};
2. 분석
- schded_entity 가 처음 생성 된 이후, depth 와 부모 sched_entity 포인터와, rq 그룹과 스스로의 cache value를 갖는 cfs_rq 구조체 생성.
2. task_struct
1. 코드
struct task_struct {
#ifdef CONFIG_THREAD_INFO_IN_TASK
struct thread_info thread_info;
#endif
unsigned int __state;
void *stack;
refcount_t usage;
unsigned int flags;
unsigned int ptrace;
...
int on_rq;
int prio;
int static_prio;
int normal_prio;
unsigned int rt_priority;
struct sched_entity se;
struct sched_rt_entity rt;
struct sched_dl_entity dl;
const struct sched_class *sched_class;
...
#ifdef CONFIG_CGROUP_SCHED
struct task_group *sched_task_group;
#endif
...
struct sched_info sched_info;
struct list_head tasks;
...
unsigned long atomic_flags;
struct restart_block restart_block;
pid_t pid;
pid_t tgid;
struct task_struct *real_parent;
struct task_struct *parent;
struct list_head children;
struct list_head sibling;
struct task_struct *group_leader;
...
struct fs_struct *fs;
struct files_struct *files;
...
struct seccomp seccomp;
struct syscall_user_dispatch syscall_dispatch;
...
struct thread_struct thread;
};
3. rq
1. 코드
struct rq {
raw_spinlock_t lock;
unsigned int nr_running;
...
u64 nr_switches;
...
struct cfs_rq cfs;
struct rt_rq rt;
struct dl_rq dl;
...
unsigned long nr_uninterruptible;
struct task_struct *curr;
};
4. cfs_rq
1. 코드
struct cfs_rq {
struct load_weight load;
unsigned int nr_running;
unsigned int h_nr_running;
unsigned int idle_h_nr_running;
u64 exec_clock;
u64 min_vruntime;
...
struct rb_root_cached tasks_timeline;
struct sched_entity *curr;
struct sched_entity *next;
struct sched_entity *last;
struct sched_entity *skip;
...
};
3. 소스 디버깅
1. task_tick_fair()

- gic_handle_irq -> timer_handelr -> scheduler_tick() 순으로 호출
- 위의 호출 순서를 보았을때, timer interrupt 로 인해 발생한 것을 확인 할 수 있다.
2. dequeue_task_rt()
3. chech_preempt_curr_rt()
4. task_tick_rt()