2016년 11월 1일 화요일

가계부채 1200兆…숨겨진 '3대 폭탄'

한국은행은 1일 ‘통화신용정책보고서’에서 올해 1~8월 가계부채 증가세가 예년의 2배 이상이라고 밝혔다. 직전 4년 동안(2012~2015년)엔 평균 30조원 정도씩 늘던 것이, 올 들어 68조원 늘었다는 것이다. 또 가계부채가 은행보다 서민층이 많이 이용하는 저축은행·새마을금고 등 비(非)은행 대출을 통해 크게 늘고 있다고 한은은 밝혔다. 올해 1~8월 은행의 가계대출 증가 폭은 지난해 같은 기간보다 5조원 정도 줄었다. 반면 비은행 가계대출 증가 폭은 15조원가량 늘었다.

① 비은행권 ‘생계형 대출’ 급증
한은에 따르면 8월 말 비은행권 기타대출은 163조4342억원이다. 비은행 기타대출이란 저축은행·신협·새마을금고 등 서민형 금융회사에서 주택 담보 없이 빌려 주는 것으로 이른바 ‘생계형 대출’이다. 변변한 담보도 없고, 은행에서 돈을 빌리지 못하는 서민들이 주로 이용한다. 관련 통계가 처음 잡히기 시작한 2007년 말에는 비은행권의 기타대출 잔액이 63조3634억원이었다. 이게 10년도 안 돼 100조원 늘어난 것이다.
서민 금융회사를 통한 생계형 대출은 최근 1년 사이에 20조원 늘어 증가세가 더 가팔라졌다. 가계부채 증가세를 막기 위해 정부가 은행 대출을 조이자, 비은행 대출이 늘어나는 이른바 ‘풍선 효과’가 나타나고 있다는 평가다.
저축은행들의 ‘후순위 대출’ 영업 방식도 생계형 대출 증가세의 원인이다. 후순위 대출은 은행권에서 주택을 담보로 추가로 돈을 빌리기 어려운 사람의 주택담보대출을 저축은행으로 옮긴 뒤, 담보를 잡지 않는 신용대출 방식으로 은행에서 주택담보대출을 통해 빌린 액수보다 더 빌려 쓰는 방식이다. 금융업계 관계자는 “돈 빌려줄 곳이 마땅치 않은 저축은행들이 은행권의 대출을 저축은행 대출로 바꿔치기해 주는 것이 비은행권 생계형 대출액이 늘어나는 원인 중 하나”라고 말했다.
통상 비은행 대출금리는 은행대출의 2배 이상이다. 금리 인상기로 접어들면 빚을 못 갚는 경우가 속출할 수 있다는 경고가 나오는 이유다.
② 가계부채 ‘빈익빈 부익부’
저소득층이 빌리는 부채가 점차 악성(惡性)이 되어 가는 것도 문제라는 지적도 나온다. 최근 원승연 명지대 경영학과 교수 등이 발표한 ‘가계부채와 소득계층 이동’ 논문에 따르면 소득 하위 10% 가계의 2008년 소득 대비 부채비율은 2.09배였는데, 2014년에는 7.85배로 크게 높아졌다. 소득 하위 10% 계층의 빚 총액이 2008년만 해도 연소득의 2배를 약간 넘는 수준이었는데, 2014년에는 연소득의 7배를 넘었다는 뜻이다. 반면 소득 상위 10% 가계의 소득 대비 부채비율은 같은 기간 2.16배에서 1.78배로 줄었다. 이 수치는 개인신용정보업체 KCB(코리아크레딧뷰로)의 대출자료 20만 건을 분석한 결과다.
저소득층의 부채비율이 늘고 있는 것은 햇살론처럼 정부 정책자금을 활용해 서민들에게 대출을 많이 확대한 영향도 있다는 분석이다. 원 교수는 “내일 당장 먹고살 게 없어서 돈을 계속 빌려야 하는 저소득층에게 정부가 대출 상품을 마련해 준 결과”라고 말했다.
③가계부채 통계에도 안 잡히는 개인사업자 대출
국내 가구의 25%를 차지하는 자영업자들이 빌린 개인사업자 대출 또한 가계부채의 숨은 폭탄으로 지목된다. 가계대출 통계에는 함께 집계되지 않지만, 사실상 가계대출과 비슷한 역할을 하며 가계의 부담이 되기 때문이다.
한국기업평가가 지난 6월 말 현재 12개 시중은행의 개인사업자 대출을 집계한 결과, 총 185조5000억원으로 작년 말(177조7000억원)보다 9% 늘었다. 주택담보대출(344조1000억원)보다는 적지만, 은행권 총대출에서 차지하는 비중이 18%에 달한다.
개인사업자 대출은 내수 경기에 민감한 부동산 및 임대업(39.4%)이나 도소매·숙박·음식점(26.5%) 등에 몰려 있다. 경기가 가라앉거나 주택·부동산 시장에 찬바람이 불면 부실화할 위험이 도사리고 있다는 지적이다.
특히 은퇴한 50~60대 베이비부머 자영업자가 지고 있는 부채의 질에 대한 우려가 나온다. 금융연구원이 자영업자의 연령대별 소득 대비 부채비율을 따져 보니 50대가 2.86배로 전 연령대를 통틀어 가장 높았다. 50대 자영업자의 경우 연소득의 3배 가까운 빚을 이고 있는 셈이다. 50~60대 자영업자는 은행이 아닌 2금융권에서 빚을 낸 경우가 많다는 점도 우려할 만하다. 임진 한국금융연구원 거시경제연구실장은 “정부가 총대출 규모만 들여다보지 말고 소득 계층별로 개개인의 부채와 파산 리스크(위험)도 면밀히 따져야 한다”고 말했다.

모건스탠리 "한국, 2018년 양적완화 예상..5가지 이유"

30일 모건스탠리는 한국은행이 내년 1분기부터 매 분기 0.25%p씩 기준금리(현재 1.25%)를 인하해 3분기말에는 0.5%까지 낮출 것으로 전망했다. 또한 오는 2018년부터 방어적 양적완화(QE, Quantitative Easing)를 실시할 것으로 예상했다. 양적완화를 통한 본원통화 확대 규모는 연간 국내총생산(GDP)의 2%인 260억달러(약 32조원)로 추정했다.


© News1


모건스탠리는 양적완화까지 실시하게 될 배경으로 Δ 과잉부채 Δ 고령화 Δ 중국 등의 수요충격 Δ 비효율적 자원배분 Δ 선제적 정책의 부족 등 5가지를 꼽았다.
부채의 경우 지난 2007~2015년 한국의 GDP 대비 가계와 기업의 부채는 각각 15.6%와 20.7% 증가했다. 이는 미래의 성장 기반을 미리 당겨다 쓴 것으로, 민간섹터는 부채를 줄이기 위해 소비와 투자보다 저축에 치중해야 한다. 이는 성장률을 훼손할 것이라는 게 모건스탠리의 판단이다.
모건은 또한 “앞으로 10년간 한국의 생산가능인구(15~64세)는 올해를 정점으로 연평균 0.5%씩 감소할 전망이며, 생산가능인구의 부양비율(dependency ratio)은 가파르게 급증할 것”으로 내다봤다. 부양비율은 생산가능인구(15~64세)에 대한 유소년인구(0~14세)와 고령인구(65세 이상) 합계치의 배율이다.

© News1


모건은 또한 “중국 경제의 내수 중심 전환과 국영기업 인프라 투자형태의 부양책은 한국 등 아시아 국가들의 수출 경제에 도움을 줄 수 없다”고 지적했다. 더구나 중국의 비원자재-생산자물가(PPI) 하락은 한국에 디스인플레이션(물가상승률 둔화) 압력을 높일 것으로 평가했다. 최근 중국의 생산자물가 (+)전환은 원자재를 포함한 수치를 기준으로 한 것이다.
모건은 이어 “그동안 실시됐던 각종 비효율적 자원배분으로 중소기업과 서비스산업의 경쟁력이 취약해지고 이는 다시 고품질 청년일자리를 사라지게 만들었다”고 판단했다.
마지막으로 한국 경제의 문제점으로 모건스탠리는 정부 정책의 점진주의(incrementalism)를 지목했다. 선제적이고 공격적인 부양책을 실시하지 못하고 악화되는 상황에 후행해 찔끔찔금 대응했다는 것이다. 여기에 내년말 대통령선거 등 정치일정을 대입하면 적극적 부양책은 기대하기 더 힘들 수 있다고 지적했다. 차기 정부 출범 직후인 18~24개월 내에 양적완화를 실시할 것으로 점치는 배경이다.
따라서 한은의 올해와 내년 GDP성장률 전망치 2.7% 및 2.8%와 달리, 모건스탠리는 올해 성장률을 2.5%로, 내년엔 2.3%로 둔화되는 시나리오를 예상했다. 소비자물가(CPI)는 올해와 내년 각각 0.9%(종전 1.1%)와 1.2%(종전 1.6%)에 머물 것으로 모건은 관측했다.

© News1
한국에서의 자산전략과 관련, 모건스탠리는 채권의 경우 금리 하락시 활용하는 리시브(receive, 고정금리 수취·변동금리 지급)를 조언했다. 구체적으로 2년후 시작되는 2년물 선도스왑(2y2y) 형태의 차액결제 금리스왑(NDIRS) 리시브를 권고했다. 또한 달러/원 환율의 경우 내년말 달러당 1250원, 2018년말 1300원 이상을 기록할 것으로 예상했다.

그러나 증시의 경우, 양적완화 실시와 함께 외국인자금 유입, 원화 약세에 따른 기업이익 증가 등으로 상승세를 탈 것으로 기대했다. 기본 시나리오로 목표지수 2200p를 산출했다. 강세 시나리오시 2500p까지 상승할 수 있다고 분석했다. 다만 금리인하를 감안해 보험·은행 등 금융주를 피하고 산업재· IT· 에너지 매수를 추천했다. 투자 대안으로 코스피 콜옵션 매수도 유망하다고 권고했다.

© News1


2016년 10월 29일 토요일

[Linux Kernel] 161주차(2016.10.29) rest_init()

Neuromancer : 161 주차

일시 : 2016.10.29 (161 주차 스터디 진행)

모임명 : neuromancer.kr

장소 : 토즈 서현점

참여인원 : 2명

============

161주차 진도

  • 161차 시작 위치
    • start_kernel 1 ~/init/main.c
    • rest_init 968 ~/init/main.c
    • kernel_thread 453 ~/init/main.c
    • do_fork 2067 ~/kernel/fork.c
    • copy_process 2020 ~/kernel/fork.c
    • sched_fork 1734 ~/kernel/fork.c

161주차 함수 호출 구조

  • call: start_kernel()
    • lockdep_init()
    • smp_setup_processor_id()
    • debug_objects_early_init()
    • boot_init_stack_canary()
    • cgroup_init_early()
    • local_irq_disable()
    • boot_cpu_init()
    • page_address_init()
    • pr_notice()
    • setup_arch()
    • mm_init_owner()
    • mm_init_cpumask()
    • setup_command_line
    • build_all_zonelists()
    • page_alloc_init()
    • pr_notice()
    • parse_early_param()
    • parse_args()
    • jump_label_init()
    • setup_log_buf()
    • pidhash_init()
    • vfs_caches_init_early()
    • sort_main_extable()
    • trap_init()
    • mm_init()
    • sched_init()
    • preempt_disable()
    • irqs_disabled()
    • local_irq_disabled()
    • idr_init_cache()
    • rcu_init()
    • tick_nohz_init()
    • contect_tracking_init()
    • radix_tree_init()
    • early_irq_init()
    • init_IRQ()
    • tick_init()
    • init_timers()
    • hrtimers_init()
    • softirq_init()
    • timekeeping_init()
    • time_init()
    • sched_clock_postinit()
    • pref_event_init()
    • profile_init()
    • call_function_init()
    • irqs_disabled()
    • local_irq_enabled()
    • kmem_cache_init_late()
    • console_init()
    • lockdep_init()
    • lockdep_info()
    • locking_selftest()
    • virt_to_page()
    • page_to_pfn()
    • page_cgroup_init()
    • debug_objects_mem_init()
    • kmemleak_init()
    • setup_per_cpu_pageset()
    • numa_policy_init()
    • sched_clock_init()
    • calibrate_delay()
    • pidmap_init()
    • anon_vma_init()
    • thread_info_cache_init()
    • cred_init()
    • fork_init()
    • proc_caches_init()
    • buffer_init()
    • key_init()
    • security_init()
    • dbg_late_init()
    • vfs_caches_init()
    • signals_init()
    • page_writeback_init()
    • proc_root_init()
    • cgroup_init()
    • cpuset_init()
    • taskstats_init_early()
    • delayacct_init()
    • check_bugs()
    • acpi_early_init()
    • sfi_init_late()
    • efi_enabled(EFI_RUNTIME_SERVICES)
    • ftrace_init()
    • rest_init()
  • call: rest_init()
    • rcu_scheduler_starting()
    • kernel_thread()
  • call: kernel_thread()
    • do_fork()
  • call: do_fork()
    • copy_process()
  • call: copy_process()
    • security_task_create()
    • dup_task_struct()
    • ftrace_graph_init_task(p); // null function
    • get_seccomp_filter(p); // null function
    • rt_mutex_init_task(p);
    • copy_creds(p, clone_flags);
    • try_module_get()
    • delayacct_tsk_init(p)
    • copy_flags()
    • INIT_LIST_HEAD(&p->children);
    • INIT_LIST_HEAD(&p->sibling);
    • rcu_copy_process(p);
    • spin_lock_init(&p->alloc_lock);
    • init_sigpending(&p->pending);
    • memset(&p->rss_stat, 0, sizeof(p->rss_stat));
    • task_io_accounting_init(&p->ioac); // null function
    • acct_clear_integrals(p); // null function
    • posix_cpu_timers_init(p);
    • do_posix_clock_monotonic_gettime(&p->start_time);
    • monotonic_to_bootbased(&p->real_start_time);
    • cgroup_fork(p);
    • sched_fork(clone_flags, p);
  • call: sched_fork(clone_flags, p);
    • get_cpu();
    • _schedfork(clone_flags, p);
    • rt_prio(p->prio)

start_kernel()

  • call: start_kernel()
    • lockdep_init()
    • smp_setup_processor_id()
    • debug_objects_early_init()
    • boot_init_stack_canary()
    • cgroup_init_early()
    • local_irq_disable()
    • boot_cpu_init()
    • page_address_init()
    • pr_notice()
    • setup_arch()
    • mm_init_owner()
    • mm_init_cpumask()
    • setup_command_line
    • build_all_zonelists()
    • page_alloc_init()
    • pr_notice()
    • parse_early_param()
    • parse_args()
    • jump_label_init()
    • setup_log_buf()
    • pidhash_init()
    • vfs_caches_init_early()
    • sort_main_extable()
    • trap_init()
    • mm_init()
    • sched_init()
    • preempt_disable()
    • irqs_disabled()
    • local_irq_disabled()
    • idr_init_cache()
    • rcu_init()
    • tick_nohz_init()
    • contect_tracking_init()
    • radix_tree_init()
    • early_irq_init()
    • init_IRQ()
    • tick_init()
    • init_timers()
    • hrtimers_init()
    • softirq_init()
    • timekeeping_init()
    • time_init()
    • sched_clock_postinit()
    • pref_event_init()
    • profile_init()
    • call_function_init()
    • irqs_disabled()
    • local_irq_enabled()
    • kmem_cache_init_late()
    • console_init()
    • lockdep_init()
    • lockdep_info()
    • locking_selftest()
    • virt_to_page()
    • page_to_pfn()
    • page_cgroup_init()
    • debug_objects_mem_init()
    • kmemleak_init()
    • setup_per_cpu_pageset()
    • numa_policy_init()
    • sched_clock_init()
    • calibrate_delay()
    • pidmap_init()
    • anon_vma_init()
    • thread_info_cache_init()
    • cred_init()
    • fork_init()
    • proc_caches_init()
    • buffer_init()
    • key_init()
    • security_init()
    • dbg_late_init()
    • vfs_caches_init()
    • signals_init()
    • page_writeback_init()
    • proc_root_init()
    • cgroup_init()
    • cpuset_init()
    • taskstats_init_early()
    • delayacct_init()
    • check_bugs()
    • acpi_early_init()
    • sfi_init_late()
    • efi_enabled()
    • efi_late_init()
    • efi_free_boot_services()
    • ftrace_init()
    • rest_init()
// ARM10C 20130824
asmlinkage void __init start_kernel(void)
{
 char * command_line;
 extern const struct kernel_param __start___param[], __stop___param[];
 // ATAG,DTB 정보로 사용

 /*
  * Need to run as early as possible, to initialize the
  * lockdep hash:
  */
 lockdep_init();
 smp_setup_processor_id();
 debug_objects_early_init();

 /*
  * Set up the the initial canary ASAP:
  */
 boot_init_stack_canary();

 cgroup_init_early();
 // cgroup 를 사용하기 위한 cgroup_dummy_root, cgroup_subsys 의 구조체 초기화 수행

 local_irq_disable();
 // IRQ를 disable 함

 early_boot_irqs_disabled = true;
 // early_boot_irqs_disabled: true

/*
 * Interrupts are still disabled. Do necessary setups, then
 * enable them
 */
 boot_cpu_init();
 // 현재 cpu(core id)를 얻어서 cpu_XXX_bits[] 의 cpu를 셋한다.
 
 page_address_init();
 // 128개의 page_address_htable 배열을 초기화

 pr_notice("%s", linux_banner);
 // 배너:
 // Linux version 2.6.37_DM385_IPNC_3.50.00
 //  (a0875405@bangvideoapps01) (gcc version 4.5.3 20110311
 //  (prerelease) (GCC) ) #1 Fri Dec 21 17:27:08 IST 2012

 setup_arch(&command_line);

 mm_init_owner(&init_mm, &init_task); // null function
 mm_init_cpumask(&init_mm); // null function

 // command_line: exynos5420-smdk5420.dts 파일의 chosen node 의 bootarg 값
 // "console=ttySAC2,115200 init=/linuxrc"
 setup_command_line(command_line);
 // saved_command_line 및 static_command_line 할당

 setup_nr_cpu_ids();
 setup_per_cpu_areas();
 // pcpu 구조체를 만들어 줌 (mm/percpu.c)

 smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
 // boot cpu 0의 pcpu 영역의 base주소를 core register에 설정해줌

 build_all_zonelists(NULL, NULL);

 page_alloc_init();
 // cpu_chain에 page_alloc_cpu_notify를 연결함 (mutex lock/unlock 사용)

 // boot_command_line: "console=ttySAC2,115200 init=/linuxrc"
 pr_notice("Kernel command line: %s\n", boot_command_line);
 // "Kernel command line: console=ttySAC2,115200 init=/linuxrc"

 parse_early_param();
 // setup_arch에서 수행했던 작업 다시 수행
 // command arg에서 각 요소들을 파싱하여 early init section으로 설정된 디바이스 초기화.
 // 우리는 serial device가 검색이 되지만 config설정은 없어서 아무것도 안함.

 // static_command_line: "console=ttySAC2,115200 init=/linuxrc"
 parse_args("Booting kernel", static_command_line, __start___param,
     __stop___param - __start___param,
     -1, -1, &unknown_bootoption);
 // DTB에서 넘어온 bootargs를 파싱하여 param, val을 뽑아내고 그에 대응되는
 // kernel_param 구조체에 값을 등록함.

 jump_label_init();
 // HAVE_JUMP_LABEL 이 undefined 이므로 NULL 함수

 /*
  * These use large bootmem allocations and must precede
  * kmem_cache_init()
  */
 setup_log_buf(0);
 // defalut log_buf의 크기는 __LOG_BUF_LEN: 0x20000 (128KB) 임
 // early_param 에서 호출했던 log_buf_len 값이 있다면 log_buf의 크기를 넘어온 크기로 만듬

 pidhash_init();
 // pidhash의 크기를 16kB만큼 할당 받고 4096개의 hash list를 만듬

 vfs_caches_init_early();
 // Dentry cache, Inode-cache용 hash를 위한 메모리 공간을 각각 512kB, 256kB만큼 할당 받고,
 // 131072, 65536개 만큼 hash table을 각각 만듬

 sort_main_extable();
 // extable 을 cmp_ex를 이용하여 sort수행

 trap_init(); // null function

 mm_init();
 // buddy와 slab 을 활성화 하고 기존 할당 받은 bootmem 은 buddy,
 // pcpu 메모리, vmlist 는 slab으로 이관

 /*
  * Set up the scheduler prior starting any interrupts (such as the
  * timer interrupt). Full topology setup happens at smp_init()
  * time - but meanwhile we still have a functioning scheduler.
  */
 sched_init();
 // scheduler가 사용하는 자료 구조 초기화, idle_threads를 init_task로 세팅

 /*
  * Disable preemption - early bootup scheduling is extremely
  * fragile until we cpu_idle() for the first time.
  */
 preempt_disable();
 // preempt count를 증가시켜 preemption 못하도록 막음

 // irqs_disabled(): 1
 if (WARN(!irqs_disabled(), "Interrupts were enabled *very* early, fixing it\n"))
  local_irq_disable();

 idr_init_cache();
 // integer ID management로 사용하는 idr_layer_cache에 kmem_cache#21 을 생성 및 초기화 후 할당

 rcu_init();
 // rcu 자료구조 bh, sched, preempt 를 각각 초기화 수행함

 tick_nohz_init(); // null function
 context_tracking_init(); // null function

 radix_tree_init();
 // radix tree로 사용하는 radix_tree_node_cachep에 kmem_cache#20을 생성 및 초기화 후 할당하고
 // height_to_maxindex을 초기화 수행

 /* init some links before init_ISA_irqs() */
 early_irq_init();
 // irq_desc 0 ~ 15 까지의 object을 할당 받고 초기화를 수행
 // allocated_irqs에 bit를 1로 세팅하고 radix tree에 각 irq_desc를 노트로 추가

 init_IRQ();
 // gic, combiner이 사용할 메모리 할당과 자료 구조 설정,
 // gic irq (0~15), combiner irq (32~63) interrupt 를 enable 시킴

 tick_init();
 // tick 관련 mask 변수를 0으로 초기화 수행

 init_timers();
 // boot_tvec_bases의 맴버 값을 초기화하고 timers_nb를 cpu_notifier 에 등록,
 // softirq_vec[1] 에 run_timer_softirq 등록하여 초기화 수행

 hrtimers_init();
 // hrtimer_bases의 맴버 값을 초기화하고 hrtimers_nb를 cpu_notifier 에 등록,
 // softirq_vec[8] 에 run_hrtimer_softirq 등록하여 초기화 수행

 softirq_init();
 // tasklet_vec, tasklet_hi_vec 맴버 값을 초기화하고,
 // softirq_vec[6]에 tasklet_action, softirq_vec[0]에 tasklet_hi_action 등록하여 초기화 수행

 timekeeping_init();
 // ntp 관련 전역변수 초기화, timekeeper, shadow_timekeeper의 맴버값 초기화 수행

 time_init();
 // timer 를 사용하기 위한 clk source, clk_table 메모리 할당 및 초기화,
 // timer event를 위한 timer irq (MCT) 초기화 수행

 sched_clock_postinit();
 // sched_clock_timer을 초기화 수행

 perf_event_init(); // null function
 profile_init(); // null function
 call_function_init();
 // 각 cpu core에서 사용할 call_single_queue를 맴버값 초기화
 // cfd_data 맴버값을 초기화하고 pcp에서 사용할 메모리 공간 할당
 // cpu_chain에 hotplug_cfd_notifier 를 등록함

 // irqs_disabled(): 1
 WARN(!irqs_disabled(), "Interrupts were enabled early\n");

 // early_boot_irqs_disabled: true
 early_boot_irqs_disabled = false;
 // early_boot_irqs_disabled: false

 local_irq_enable();
 // IRQ를 enable 함

 kmem_cache_init_late(); // null function

 /*
  * HACK ALERT! This is early. We're enabling the console before
  * we've done PCI setups etc, and console_init() must be aware of
  * this. But we do want output early, in case something goes wrong.
  */
 console_init();

 // panic_later: NULL
 if (panic_later)
  panic(panic_later, panic_param);

 lockdep_info(); // null function

 /*
  * Need to run this when irqs are enabled, because it wants
  * to self-test [hard/soft]-irqs on/off lock inversion bugs
  * too:
  */
 locking_selftest(); // null function

#ifdef CONFIG_BLK_DEV_INITRD // CONFIG_BLK_DEV_INITRD=y
 // initrd_start: NULL, initrd_below_start_ok: 0
 if (initrd_start && !initrd_below_start_ok &&
     page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {
  pr_crit("initrd overwritten (0x%08lx < 0x%08lx) - disabling it.\n",
      page_to_pfn(virt_to_page((void *)initrd_start)),
      min_low_pfn);
  initrd_start = 0;
 }
#endif

 page_cgroup_init(); // null function
 debug_objects_mem_init(); // null function
 kmemleak_init(); // null function

 setup_per_cpu_pageset();
 // per cpu가 사용하는 pageset의 각각의 zone 맴버값 초기화 수행

 numa_policy_init(); // null function

 // late_time_init: NULL
 if (late_time_init)
  late_time_init();

 sched_clock_init();
 // sched_clock_running 값을 1 로 초기화 수행

 calibrate_delay();
 // BogoMIPS값을 결정하기위한 계산을 수행하고 결과를 출력함

 pidmap_init();
 // pidmap 을 사용하기 위한 초기화 수행

 anon_vma_init();
 // anon vma 를 사용하기 위한 kmem_cache 할당자 초기화 수행

#ifdef CONFIG_X86 // CONFIG_X86=n
 if (efi_enabled(EFI_RUNTIME_SERVICES))
  efi_enter_virtual_mode();
#endif
 thread_info_cache_init(); // null function
 cred_init();
 // credentials 를 사용하기 위한 kmem_cache 할당자 초기화 수행

 // totalram_pages: 총 free된 page 수
 fork_init(totalram_pages);
 // task_struct 를 사용하기 위한 kmem_cache 할당자 초기화 수행
 // max_threads값을 계산하여 init_task에 threads값의 limit 값 설정함

 proc_caches_init();
 // sighand_struct, signal_struct, files_struct, fs_struct, mm_struct, vm_area_struct, nsproxy
 // 를 사용하기 위한 kmem_cache 할당자 및 percpu list 초기화 수행

 buffer_init();
 // buffer_head 를 사용하기 위한 kmem_cache 할당자 및 max_buffer_heads 값 초기화 수행

 key_init(); // null funtion
 security_init(); // null funtion
 dbg_late_init(); // null funtion

 // totalram_pages: 총 free된 page 수
 vfs_caches_init(totalram_pages);
 // virtual file system을 위한 names, dentry, inode, filp, mount cache 생성 후
 // file system 을 위한 초기화 수행 및 mount 수행, block, char dev 사용을 위한 초기화 수행

 signals_init();
 // signal을 사용하기 위한 kmem_cache 를 생성

 /* rootfs populating might need page-writeback */
 page_writeback_init();
 // page writeback을 위한 global_dirty_limit, ratelimit_pages 값을 초기화 수행

#ifdef CONFIG_PROC_FS // CONFIG_PROC_FS=y
 proc_root_init();
 // proc filesystem을 등록 하고 proc을 사용하기 위한 dentry, inode 생성 후
 // sysctl_base_table 에 등록된 kernel, vm, fs, debug, dev의 dir, files 를 recursive 하게 RB Tree 를 구성함
#endif
 cgroup_init();
 // cgroup에서 사용하는 sub system 인 debug_subsys, cpu_cgroup_subsys, cpuacct_subsys, freezer_subsys 를 등록 하고
 // init_css_set.subsys 를 이용하여 hash key 값 생성, cgroup 을 위한 kobject 를 생성, cgroup용 fils system type을 추가 하여
 // filesystem 에 등록함, cgroup 을 위한 proc 생성.

 cpuset_init(); // null function
 taskstats_init_early(); // null function
 delayacct_init(); // null function

 check_bugs();
 // page 2개를 할당 받고 할당 받은 메모리에값을 쓰고 비교하여
 // 메모리 동작을 테스트 수행한 이후 다시 메모리를 반환함

 acpi_early_init(); /* before LAPIC and SMP init */  // null function
 sfi_init_late(); // null function

 // efi_enabled(EFI_RUNTIME_SERVICES): 1
 if (efi_enabled(EFI_RUNTIME_SERVICES)) {
  efi_late_init(); // null function
  efi_free_boot_services(); // null function
 }

 ftrace_init(); // null function

 /* Do the rest non-__init'ed, we're now alive */
 rest_init();
}

rest_init()

  • start_kernel()
    • rest_init()
  • call: rest_init()
// ARM10C 20160827
static noinline void __init_refok rest_init(void)
{
 int pid;

 rcu_scheduler_starting(); // null function
 /*
  * We need to spawn init first so that it obtains pid 1, however
  * the init task will end up wanting to create kthreads, which, if
  * we schedule it before we create kthreadd, will OOPS.
  */
 // CLONE_FS: 0x00000200, CLONE_SIGHAND: 0x00000800
 kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);

kernel_thread()

  • start_kernel()
    • rest_init()
  • call: rest_init()
    • rcu_scheduler_starting()
    • kernel_thread()
// ARM10C 20160827
// kernel_init, NULL, 0x00000A00
pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
{
 // flags: 0x00000A00, CLONE_VM: 0x00000100, CLONE_UNTRACED: 0x00800000,
 // fn: kernel_init, arg: NULL
 return do_fork(flags|CLONE_VM|CLONE_UNTRACED, (unsigned long)fn,
  (unsigned long)arg, NULL, NULL);
}

do_fork()

  • start_kernel()
    • rest_init()
  • call: rest_init()
    • rcu_scheduler_starring()
    • kernel_thread()
  • call: kernel_thread()
    • do_fork()
  • call: do_fork()
// ARM10C 20160827
// flags: 0x00800B00, fn: kernel_init, arg: NULL, NULL, NULL
long do_fork(unsigned long clone_flags,
       unsigned long stack_start,
       unsigned long stack_size,
       int __user *parent_tidptr,
       int __user *child_tidptr)
{
 struct task_struct *p;
 int trace = 0;
 // trace: 0

 long nr;

 /*
  * Determine whether and which event to report to ptracer.  When
  * called from kernel_thread or CLONE_UNTRACED is explicitly
  * requested, no event is reported; otherwise, report if the event
  * for the type of forking is enabled.
  */
 // clone_flags: 0x00800B00, CLONE_UNTRACED: 0x00800000
 if (!(clone_flags & CLONE_UNTRACED)) {
  if (clone_flags & CLONE_VFORK)
   trace = PTRACE_EVENT_VFORK;
  else if ((clone_flags & CSIGNAL) != SIGCHLD)
   trace = PTRACE_EVENT_CLONE;
  else
   trace = PTRACE_EVENT_FORK;

  if (likely(!ptrace_event_enabled(current, trace)))
   trace = 0;
 }

 // clone_flags: 0x00800B00, stack_start: kernel_init, stack_size: 0, child_tidptr: 0, trace: 0
 p = copy_process(clone_flags, stack_start, stack_size,
    child_tidptr, NULL, trace);

do_fork()

  • start_kernel()
    • rest_init()
  • call: rest_init()
    • rcu_scheduler_starring()
    • kernel_thread()
  • call: kernel_thread()
    • do_fork()
  • call: do_fork()
    • copy_process()
  • call: copy_process()
// ARM10C 20160827
// clone_flags: 0x00800B00, stack_start: kernel_init, stack_size: 0, child_tidptr: 0, NULL, trace: 0
static struct task_struct *copy_process(unsigned long clone_flags,
  unsigned long stack_start,
  unsigned long stack_size,
  int __user *child_tidptr,
  struct pid *pid,
  int trace)
{
 int retval;
 struct task_struct *p;

 // clone_flags: 0x00800B00, CLONE_NEWNS: 0x00020000, CLONE_FS: 0x00000200
 if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS))
  return ERR_PTR(-EINVAL);

 // clone_flags: 0x00800B00, CLONE_NEWUSER: 0x10000000, CLONE_FS: 0x00000200
 if ((clone_flags & (CLONE_NEWUSER|CLONE_FS)) == (CLONE_NEWUSER|CLONE_FS))
  return ERR_PTR(-EINVAL);

 /*
  * Thread groups must share signals as well, and detached threads
  * can only be started up within the thread group.
  */
 // clone_flags: 0x00800B00, CLONE_THREAD: 0x00010000, CLONE_SIGHAND: 0x00000800
 if ((clone_flags & CLONE_THREAD) && !(clone_flags & CLONE_SIGHAND))
  return ERR_PTR(-EINVAL);

 /*
  * Shared signal handlers imply shared VM. By way of the above,
  * thread groups also imply shared VM. Blocking this case allows
  * for various simplifications in other code.
  */
 // clone_flags: 0x00800B00, CLONE_SIGHAND: 0x00000800, CLONE_VM: 0x00000100
 if ((clone_flags & CLONE_SIGHAND) && !(clone_flags & CLONE_VM))
  return ERR_PTR(-EINVAL);

// 2016/08/27 종료
// 2016/09/03 시작

 /*
  * Siblings of global init remain as zombies on exit since they are
  * not reaped by their parent (swapper). To solve this and to avoid
  * multi-rooted process trees, prevent global and container-inits
  * from creating siblings.
  */
 // clone_flags: 0x00800B00, CLONE_PARENT: 0x00008000, SIGNAL_UNKILLABLE: 0x00000040
 // current: &init_task, current->signal: &init_signals
 // current->signal->flags: (&init_signals)->flags: 0
 if ((clone_flags & CLONE_PARENT) &&
   current->signal->flags & SIGNAL_UNKILLABLE)
  return ERR_PTR(-EINVAL);

 /*
  * If the new process will be in a different pid or user namespace
  * do not allow it to share a thread group or signal handlers or
  * parent with the forking task.
  */
 // clone_flags: 0x00800B00, CLONE_SIGHAND: 0x00000800
 if (clone_flags & CLONE_SIGHAND) {
  // clone_flags: 0x00800B00, CLONE_NEWUSER: 0x10000000, CLONE_NEWPID: 0x20000000
  // current: &init_task, task_active_pid_ns(&init_task): &init_pid_ns,
  // current->nsproxy: (&init_task)->nsproxy: &init_nsproxy,
  // current->nsproxy->pid_ns_for_children: (&init_nsproxy)->pid_ns_for_children: &init_pid_ns
  if ((clone_flags & (CLONE_NEWUSER | CLONE_NEWPID)) ||
    (task_active_pid_ns(current) !=
     current->nsproxy->pid_ns_for_children))
   return ERR_PTR(-EINVAL);
 }

 // clone_flags: 0x00800B00, security_task_create(0x00800B00): 0
 retval = security_task_create(clone_flags);
 // retval: 0

 // retval: 0
 if (retval)
  goto fork_out;

 // ENOMEM: 12
 retval = -ENOMEM;
 // retval: -12

 // current: &init_task
 // dup_task_struct(&init_task): kmem_cache#15-oX (struct task_struct)
 p = dup_task_struct(current);
 // p: kmem_cache#15-oX (struct task_struct)

 // dup_task_struct 에서 한일:
 // struct task_struct 만큼의 메모리를 할당 받음
 // kmem_cache#15-oX (struct task_struct)
 //
 // struct thread_info 를 구성 하기 위한 메모리를 할당 받음 (8K)
 // 할당 받은 page 2개의 메로리의 가상 주소
 //
 // 할당 받은 kmem_cache#15-oX (struct task_struct) 메모리에 init_task 값을 전부 할당함
 //
 // (kmem_cache#15-oX (struct task_struct))->stack: 할당 받은 page 2개의 메로리의 가상 주소
 //
 // 할당 받은 kmem_cache#15-oX (struct task_struct) 의 stack의 값을 init_task 의 stack 값에서 전부 복사함
 // 복사된 struct thread_info 의 task 주소값을 할당 받은 kmem_cache#15-oX (struct task_struct)로 변경함
 // *(할당 받은 page 2개의 메로리의 가상 주소): init_thread_info
 // ((struct thread_info *) 할당 받은 page 2개의 메로리의 가상 주소)->task: kmem_cache#15-oX (struct task_struct)
 //
 // (((struct thread_info *)(할당 받은 page 2개의 메로리의 가상 주소))->flags 의 1 bit 값을 clear 수행
 //
 // *((unsigned long *)(할당 받은 page 2개의 메로리의 가상 주소 + 1)): 0x57AC6E9D
 //
 // (&(kmem_cache#15-oX (struct task_struct))->usage)->counter: 2
 // (kmem_cache#15-oX (struct task_struct))->splice_pipe: NULL
 // (kmem_cache#15-oX (struct task_struct))->task_frag.page: NULL
 //
 // (&contig_page_data)->node_zones[0].vm_stat[16]: 1 을 더함
 // vmstat.c의 vm_stat[16] 전역 변수에도 1을 더함

 // p: kmem_cache#15-oX (struct task_struct)
 if (!p)
  goto fork_out;

 // p: kmem_cache#15-oX (struct task_struct)
 ftrace_graph_init_task(p); // null function

 // p: kmem_cache#15-oX (struct task_struct)
 get_seccomp_filter(p); // null function

 // p: kmem_cache#15-oX (struct task_struct)
 rt_mutex_init_task(p);

 // rt_mutex_init_task 한일:
 // &(kmem_cache#15-oX (struct task_struct))->pi_lock을 사용한 spinlock 초기화
 // &(kmem_cache#15-oX (struct task_struct))->pi_waiters 리스트 초기화
 // (kmem_cache#15-oX (struct task_struct))->pi_blocked_on: NULL

#ifdef CONFIG_PROVE_LOCKING // CONFIG_PROVE_LOCKING=n
 DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled);
 DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);
#endif
 // EAGAIN: 11
 retval = -EAGAIN;
 // retval: -11

 // p: kmem_cache#15-oX (struct task_struct)
 // p->real_cred: (kmem_cache#15-oX (struct task_struct))->real_cred: &init_cred,
 // p->real_cred->user: (&init_cred)->user: &root_user,
 // &p->real_cred->user->processes: &(&root_user)->processes, atomic_read(&(&root_user)->processes): 1
 // RLIMIT_NPROC: 6, task_rlimit(kmem_cache#15-oX (struct task_struct), 6): 0
 if (atomic_read(&p->real_cred->user->processes) >=
   task_rlimit(p, RLIMIT_NPROC)) {
  // p->real_cred->user: (&init_cred)->user: &root_user, INIT_USER: (&root_user)
  // CAP_SYS_RESOURCE: 24, capable(24): true, CAP_SYS_ADMIN: 21, capable(21): true
  if (p->real_cred->user != INIT_USER &&
      !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN))
   goto bad_fork_free;

  // capable 에서 한일:
  // (&init_task)->flags: 0x00200100
 }

 // current->flags: (&init_task)->flags: 0x00200100, PF_NPROC_EXCEEDED: 0x00001000
 current->flags &= ~PF_NPROC_EXCEEDED;
 // current->flags: (&init_task)->flags: 0x00200100

 // retval: -11, p: kmem_cache#15-oX (struct task_struct), clone_flags: 0x00800B00
 // copy_creds(kmem_cache#15-oX (struct task_struct), 0x00800B00): 0
 retval = copy_creds(p, clone_flags);
 // retval: 0

 // copy_creds 에서 한일:
 // struct cred 만큼의 메모리를 할당 받음
 // kmem_cache#16-oX (struct cred)
 //
 // kmem_cache#16-oX (struct cred) 에 init_cred 에 있는 맴버값 전부를 복사함
 // (&(kmem_cache#16-oX (struct cred))->usage)->counter: 1
 // (&(&init_groups)->usage)->counter: 3
 // (&(&root_user)->__count)->counter: 2
 // (&(&root_user)->processes)->counter: 2
 //
 // (&(kmem_cache#16-oX (struct cred))->usage)->counter: 2
 //
 // (kmem_cache#15-oX (struct task_struct))->cred: kmem_cache#16-oX (struct cred)
 // (kmem_cache#15-oX (struct task_struct))->real_cred: kmem_cache#16-oX (struct cred)

 // retval: 0
 if (retval < 0)
  goto bad_fork_free;

 /*
  * If multiple threads are within copy_process(), then this check
  * triggers too late. This doesn't hurt, the check is only there
  * to stop root fork bombs.
  */
 // EAGAIN: 11
 retval = -EAGAIN;
 // retval: -11

 // nr_threads: 0, max_threads: 총 free된 page 수 / 16
 if (nr_threads >= max_threads)
  goto bad_fork_cleanup_count;

 // p: kmem_cache#15-oX (struct task_struct),
 // task_thread_info(kmem_cache#15-oX (struct task_struct)):
 // (kmem_cache#15-oX (struct task_struct))->stack: 할당 받은 page 2개의 메로리의 가상 주소,
 // task_thread_info(kmem_cache#15-oX (struct task_struct)->exec_domain:
 // ((struct thread_info *) 할당 받은 page 2개의 메로리의 가상 주소)->exec_domain: &default_exec_domain,
 // task_thread_info(kmem_cache#15-oX (struct task_struct)->exec_domain->module:
 // (&default_exec_domain)->module: NULL,
 // try_module_get(NULL): true
 if (!try_module_get(task_thread_info(p)->exec_domain->module))
  goto bad_fork_cleanup_count;

 // p->did_exec: (kmem_cache#15-oX (struct task_struct))->did_exec
 p->did_exec = 0;
 // p->did_exec: (kmem_cache#15-oX (struct task_struct))->did_exec: 0

 // p: kmem_cache#15-oX (struct task_struct)
 delayacct_tsk_init(p); /* Must remain after dup_task_struct() */ // null function

 // clone_flags: 0x00800B00, p: kmem_cache#15-oX (struct task_struct)
 copy_flags(clone_flags, p);

 // copy_flags 에서 한일:
 // (kmem_cache#15-oX (struct task_struct))->flags: 0x00200040

 // &p->children: &(kmem_cache#15-oX (struct task_struct))->children
 INIT_LIST_HEAD(&p->children);

 // INIT_LIST_HEAD 에서 한일:
 // (&(kmem_cache#15-oX (struct task_struct))->children)->next: &(kmem_cache#15-oX (struct task_struct))->children
 // (&(kmem_cache#15-oX (struct task_struct))->children)->prev: &(kmem_cache#15-oX (struct task_struct))->children

 // &p->sibling: &(kmem_cache#15-oX (struct task_struct))->sibling
 INIT_LIST_HEAD(&p->sibling);

 // INIT_LIST_HEAD 에서 한일:
 // (&(kmem_cache#15-oX (struct task_struct))->sibling)->next: &(kmem_cache#15-oX (struct task_struct))->sibling
 // (&(kmem_cache#15-oX (struct task_struct))->sibling)->prev: &(kmem_cache#15-oX (struct task_struct))->sibling

 // p: kmem_cache#15-oX (struct task_struct)
 rcu_copy_process(p);

 // rcu_copy_process 에서 한일:
 // (kmem_cache#15-oX (struct task_struct))->rcu_read_lock_nesting: 0
 // (kmem_cache#15-oX (struct task_struct))->rcu_read_unlock_special: 0
 // (kmem_cache#15-oX (struct task_struct))->rcu_blocked_node: NULL
 // (&(kmem_cache#15-oX (struct task_struct))->rcu_node_entry)->next: &(kmem_cache#15-oX (struct task_struct))->rcu_node_entry
 // (&(kmem_cache#15-oX (struct task_struct))->rcu_node_entry)->prev: &(kmem_cache#15-oX (struct task_struct))->rcu_node_entry

 // p->vfork_done: (kmem_cache#15-oX (struct task_struct))->vfork_done
 p->vfork_done = NULL;
 // p->vfork_done: (kmem_cache#15-oX (struct task_struct))->vfork_done: NULL

 // &p->alloc_lock: &(kmem_cache#15-oX (struct task_struct))->alloc_lock
 spin_lock_init(&p->alloc_lock);

 // spin_lock_init에서 한일:
 // (&(kmem_cache#15-oX (struct task_struct))->alloc_lock)->raw_lock: { { 0 } }
 // (&(kmem_cache#15-oX (struct task_struct))->alloc_lock)->magic: 0xdead4ead
 // (&(kmem_cache#15-oX (struct task_struct))->alloc_lock)->owner: 0xffffffff
 // (&(kmem_cache#15-oX (struct task_struct))->alloc_lock)->owner_cpu: 0xffffffff

 // &p->pending: &(kmem_cache#15-oX (struct task_struct))->pending
 init_sigpending(&p->pending);

 // init_sigpending 에서 한일:
 // (&(&(kmem_cache#15-oX (struct task_struct))->pending)->signal)->sig[0]: 0
 // (&(&(kmem_cache#15-oX (struct task_struct))->pending)->signal)->sig[1]: 0
 // (&(&(kmem_cache#15-oX (struct task_struct))->pending)->list)->next: &(&(kmem_cache#15-oX (struct task_struct))->pending)->list
 // (&(&(kmem_cache#15-oX (struct task_struct))->pending)->list)->prev: &(&(kmem_cache#15-oX (struct task_struct))->pending)->list

 // p->utime: (kmem_cache#15-oX (struct task_struct))->utime,
 // p->stime: (kmem_cache#15-oX (struct task_struct))->stime,
 // p->gtime: (kmem_cache#15-oX (struct task_struct))->gtime
 p->utime = p->stime = p->gtime = 0;
 // p->utime: (kmem_cache#15-oX (struct task_struct))->utime: 0
 // p->stime: (kmem_cache#15-oX (struct task_struct))->stime: 0
 // p->gtime: (kmem_cache#15-oX (struct task_struct))->gtime: 0

 // p->utimescaled: (kmem_cache#15-oX (struct task_struct))->utimescaled,
 // p->stimescaled: (kmem_cache#15-oX (struct task_struct))->stimescaled
 p->utimescaled = p->stimescaled = 0;
 // p->utimescaled: (kmem_cache#15-oX (struct task_struct))->utimescaled: 0
 // p->stimescaled: (kmem_cache#15-oX (struct task_struct))->stimescaled: 0

#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE // CONFIG_VIRT_CPU_ACCOUNTING_NATIVE=n
 p->prev_cputime.utime = p->prev_cputime.stime = 0;
#endif
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN // CONFIG_VIRT_CPU_ACCOUNTING_GEN=n
 seqlock_init(&p->vtime_seqlock);
 p->vtime_snap = 0;
 p->vtime_snap_whence = VTIME_SLEEPING;
#endif

#if defined(SPLIT_RSS_COUNTING)
 // &p->rss_stat: &(kmem_cache#15-oX (struct task_struct))->rss_stat
 memset(&p->rss_stat, 0, sizeof(p->rss_stat));

 // memset 에서 한일:
 // &(kmem_cache#15-oX (struct task_struct))->rss_stat 값을 0 으로 초기화 수행
#endif

 // p->default_timer_slack_ns: (kmem_cache#15-oX (struct task_struct))->default_timer_slack_ns,
 // current->timer_slack_ns: (&init_task)->timer_slack_ns: 50000
 p->default_timer_slack_ns = current->timer_slack_ns;
 // p->default_timer_slack_ns: (kmem_cache#15-oX (struct task_struct))->default_timer_slack_ns: 50000

 // p->ioac: (kmem_cache#15-oX (struct task_struct))->ioac
 task_io_accounting_init(&p->ioac); // null function

 // p: kmem_cache#15-oX (struct task_struct)
 acct_clear_integrals(p); // null function

 // p: kmem_cache#15-oX (struct task_struct)
 posix_cpu_timers_init(p);

 // posix_cpu_timers_init 에서 한일:
 // (kmem_cache#15-oX (struct task_struct))->cputime_expires.prof_exp: 0
 // (kmem_cache#15-oX (struct task_struct))->cputime_expires.virt_exp: 0
 // (kmem_cache#15-oX (struct task_struct))->cputime_expires.sched_exp: 0
 // (&(kmem_cache#15-oX (struct task_struct))->cpu_timers[0])->next: &(kmem_cache#15-oX (struct task_struct))->cpu_timers[0]
 // (&(kmem_cache#15-oX (struct task_struct))->cpu_timers[0])->prev: &(kmem_cache#15-oX (struct task_struct))->cpu_timers[0]
 // (&(kmem_cache#15-oX (struct task_struct))->cpu_timers[1])->next: &(kmem_cache#15-oX (struct task_struct))->cpu_timers[1]
 // (&(kmem_cache#15-oX (struct task_struct))->cpu_timers[1])->prev: &(kmem_cache#15-oX (struct task_struct))->cpu_timers[1]
 // (&(kmem_cache#15-oX (struct task_struct))->cpu_timers[2])->next: &(kmem_cache#15-oX (struct task_struct))->cpu_timers[2]
 // (&(kmem_cache#15-oX (struct task_struct))->cpu_timers[2])->prev: &(kmem_cache#15-oX (struct task_struct))->cpu_timers[2]

 // &p->start_time: &(kmem_cache#15-oX (struct task_struct))->start_time
 do_posix_clock_monotonic_gettime(&p->start_time);

 // do_posix_clock_monotonic_gettime 에서 한일:
 // (kmem_cache#15-oX (struct task_struct))->start_time 에 현재 시간 값을 가져옴
 //
 // (&(kmem_cache#15-oX (struct task_struct))->start_time)->tv_sec: 현재의 sec 값 + 현재의 nsec 값 / 1000000000L
 // (&(kmem_cache#15-oX (struct task_struct))->start_time)->tv_nsec: 현재의 nsec 값 % 1000000000L

 // p->real_start_time: (kmem_cache#15-oX (struct task_struct))->real_start_time,
 // p->start_time: (kmem_cache#15-oX (struct task_struct))->start_time
 p->real_start_time = p->start_time;
 // (&(kmem_cache#15-oX (struct task_struct))->real_start_time)->tv_sec: 현재의 sec 값 + 현재의 nsec 값 / 1000000000L
 // (&(kmem_cache#15-oX (struct task_struct))->real_start_time)->tv_nsec: 현재의 nsec 값 % 1000000000L

 // &p->real_start_time: &(kmem_cache#15-oX (struct task_struct))->real_start_time
 monotonic_to_bootbased(&p->real_start_time);

 // monotonic_to_bootbased 에서 한일:
 // (kmem_cache#15-oX (struct task_struct))->real_start_time.tv_sec: normalized 된 sec 값
 // (kmem_cache#15-oX (struct task_struct))->real_start_time.tv_nsec: normalized 된 nsec 값

 // p->io_context: (kmem_cache#15-oX (struct task_struct))->io_context
 p->io_context = NULL;
 // p->io_context: (kmem_cache#15-oX (struct task_struct))->io_context: NULL

 // p->audit_context: (kmem_cache#15-oX (struct task_struct))->audit_context
 p->audit_context = NULL;
 // p->audit_context: (kmem_cache#15-oX (struct task_struct))->audit_context: NULL

 if (clone_flags & CLONE_THREAD)
  threadgroup_change_begin(current);
 cgroup_fork(p);

copy_process()

  • start_kernel()
    • rest_init()
  • call: rest_init()
    • rcu_scheduler_starting()
    • kernel_thread()
  • call: kernel_thread()
    • do_fork()
  • call: do_fork()
    • copy_process()
// ARM10C 20160827
// clone_flags: 0x00800B00, stack_start: kernel_init, stack_size: 0, child_tidptr: 0, NULL, trace: 0
static struct task_struct *copy_process(unsigned long clone_flags,
  unsigned long stack_start,
  unsigned long stack_size,
  int __user *child_tidptr,
  struct pid *pid,
  int trace)
{

 int retval;
 struct task_struct *p;

 // clone_flags: 0x00800B00, CLONE_NEWNS: 0x00020000, CLONE_FS: 0x00000200
 if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS))
  return ERR_PTR(-EINVAL);

 // clone_flags: 0x00800B00, CLONE_NEWUSER: 0x10000000, CLONE_FS: 0x00000200
 if ((clone_flags & (CLONE_NEWUSER|CLONE_FS)) == (CLONE_NEWUSER|CLONE_FS))
  return ERR_PTR(-EINVAL);

 /*
  * Thread groups must share signals as well, and detached threads
  * can only be started up within the thread group.
  */
 // clone_flags: 0x00800B00, CLONE_THREAD: 0x00010000, CLONE_SIGHAND: 0x00000800
 if ((clone_flags & CLONE_THREAD) && !(clone_flags & CLONE_SIGHAND))
  return ERR_PTR(-EINVAL);

 /*
  * Shared signal handlers imply shared VM. By way of the above,
  * thread groups also imply shared VM. Blocking this case allows
  * for various simplifications in other code.
  */
 // clone_flags: 0x00800B00, CLONE_SIGHAND: 0x00000800, CLONE_VM: 0x00000100
 if ((clone_flags & CLONE_SIGHAND) && !(clone_flags & CLONE_VM))
  return ERR_PTR(-EINVAL);

// 2016/08/27 종료
// 2016/09/03 시작

 /*
  * Siblings of global init remain as zombies on exit since they are
  * not reaped by their parent (swapper). To solve this and to avoid
  * multi-rooted process trees, prevent global and container-inits
  * from creating siblings.
  */
 // clone_flags: 0x00800B00, CLONE_PARENT: 0x00008000, SIGNAL_UNKILLABLE: 0x00000040
 // current: &init_task, current->signal: &init_signals
 // current->signal->flags: (&init_signals)->flags: 0
 if ((clone_flags & CLONE_PARENT) &&
   current->signal->flags & SIGNAL_UNKILLABLE)
  return ERR_PTR(-EINVAL);

 /*
  * If the new process will be in a different pid or user namespace
  * do not allow it to share a thread group or signal handlers or
  * parent with the forking task.
  */
 // clone_flags: 0x00800B00, CLONE_SIGHAND: 0x00000800
 if (clone_flags & CLONE_SIGHAND) {
  // clone_flags: 0x00800B00, CLONE_NEWUSER: 0x10000000, CLONE_NEWPID: 0x20000000
  // current: &init_task, task_active_pid_ns(&init_task): &init_pid_ns,
  // current->nsproxy: (&init_task)->nsproxy: &init_nsproxy,
  // current->nsproxy->pid_ns_for_children: (&init_nsproxy)->pid_ns_for_children: &init_pid_ns
  if ((clone_flags & (CLONE_NEWUSER | CLONE_NEWPID)) ||
    (task_active_pid_ns(current) !=
     current->nsproxy->pid_ns_for_children))
   return ERR_PTR(-EINVAL);
 }

 // clone_flags: 0x00800B00, security_task_create(0x00800B00): 0
 retval = security_task_create(clone_flags);
 // retval: 0

 // retval: 0
 if (retval)
  goto fork_out;

 // ENOMEM: 12
 retval = -ENOMEM;
 // retval: -12

 // current: &init_task
 // dup_task_struct(&init_task): kmem_cache#15-oX (struct task_struct)
 p = dup_task_struct(current);
 // p: kmem_cache#15-oX (struct task_struct)

 // dup_task_struct 에서 한일:
 // struct task_struct 만큼의 메모리를 할당 받음
 // kmem_cache#15-oX (struct task_struct)
 //
 // struct thread_info 를 구성 하기 위한 메모리를 할당 받음 (8K)
 // 할당 받은 page 2개의 메로리의 가상 주소
 //
 // 할당 받은 kmem_cache#15-oX (struct task_struct) 메모리에 init_task 값을 전부 할당함
 //
 // (kmem_cache#15-oX (struct task_struct))->stack: 할당 받은 page 2개의 메로리의 가상 주소
 //
 // 할당 받은 kmem_cache#15-oX (struct task_struct) 의 stack의 값을 init_task 의 stack 값에서 전부 복사함
 // 복사된 struct thread_info 의 task 주소값을 할당 받은 kmem_cache#15-oX (struct task_struct)로 변경함
 // *(할당 받은 page 2개의 메로리의 가상 주소): init_thread_info
 // ((struct thread_info *) 할당 받은 page 2개의 메로리의 가상 주소)->task: kmem_cache#15-oX (struct task_struct)
 //
 // (((struct thread_info *)(할당 받은 page 2개의 메로리의 가상 주소))->flags 의 1 bit 값을 clear 수행
 //
 // *((unsigned long *)(할당 받은 page 2개의 메로리의 가상 주소 + 1)): 0x57AC6E9D
 //
 // (&(kmem_cache#15-oX (struct task_struct))->usage)->counter: 2
 // (kmem_cache#15-oX (struct task_struct))->splice_pipe: NULL
 // (kmem_cache#15-oX (struct task_struct))->task_frag.page: NULL
 //
 // (&contig_page_data)->node_zones[0].vm_stat[16]: 1 을 더함
 // vmstat.c의 vm_stat[16] 전역 변수에도 1을 더함

 // p: kmem_cache#15-oX (struct task_struct)
 if (!p)
  goto fork_out;

 // p: kmem_cache#15-oX (struct task_struct)
 ftrace_graph_init_task(p); // null function

 // p: kmem_cache#15-oX (struct task_struct)
 get_seccomp_filter(p); // null function

 // p: kmem_cache#15-oX (struct task_struct)
 rt_mutex_init_task(p);

 // rt_mutex_init_task 한일:
 // &(kmem_cache#15-oX (struct task_struct))->pi_lock을 사용한 spinlock 초기화
 // &(kmem_cache#15-oX (struct task_struct))->pi_waiters 리스트 초기화
 // (kmem_cache#15-oX (struct task_struct))->pi_blocked_on: NULL

#ifdef CONFIG_PROVE_LOCKING // CONFIG_PROVE_LOCKING=n
 DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled);
 DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);
#endif
 // EAGAIN: 11
 retval = -EAGAIN;
 // retval: -11

 // p: kmem_cache#15-oX (struct task_struct)
 // p->real_cred: (kmem_cache#15-oX (struct task_struct))->real_cred: &init_cred,
 // p->real_cred->user: (&init_cred)->user: &root_user,
 // &p->real_cred->user->processes: &(&root_user)->processes, atomic_read(&(&root_user)->processes): 1
 // RLIMIT_NPROC: 6, task_rlimit(kmem_cache#15-oX (struct task_struct), 6): 0
 if (atomic_read(&p->real_cred->user->processes) >=
   task_rlimit(p, RLIMIT_NPROC)) {
  // p->real_cred->user: (&init_cred)->user: &root_user, INIT_USER: (&root_user)
  // CAP_SYS_RESOURCE: 24, capable(24): true, CAP_SYS_ADMIN: 21, capable(21): true
  if (p->real_cred->user != INIT_USER &&
      !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN))
   goto bad_fork_free;

  // capable 에서 한일:
  // (&init_task)->flags: 0x00200100
 }

 // current->flags: (&init_task)->flags: 0x00200100, PF_NPROC_EXCEEDED: 0x00001000
 current->flags &= ~PF_NPROC_EXCEEDED;
 // current->flags: (&init_task)->flags: 0x00200100

 // retval: -11, p: kmem_cache#15-oX (struct task_struct), clone_flags: 0x00800B00
 // copy_creds(kmem_cache#15-oX (struct task_struct), 0x00800B00): 0
 retval = copy_creds(p, clone_flags);
 // retval: 0

 // copy_creds 에서 한일:
 // struct cred 만큼의 메모리를 할당 받음
 // kmem_cache#16-oX (struct cred)
 //
 // kmem_cache#16-oX (struct cred) 에 init_cred 에 있는 맴버값 전부를 복사함
 // (&(kmem_cache#16-oX (struct cred))->usage)->counter: 1
 // (&(&init_groups)->usage)->counter: 3
 // (&(&root_user)->__count)->counter: 2
 // (&(&root_user)->processes)->counter: 2
 //
 // (&(kmem_cache#16-oX (struct cred))->usage)->counter: 2
 //
 // (kmem_cache#15-oX (struct task_struct))->cred: kmem_cache#16-oX (struct cred)
 // (kmem_cache#15-oX (struct task_struct))->real_cred: kmem_cache#16-oX (struct cred)

 // retval: 0
 if (retval < 0)
  goto bad_fork_free;

 /*
  * If multiple threads are within copy_process(), then this check
  * triggers too late. This doesn't hurt, the check is only there
  * to stop root fork bombs.
  */
 // EAGAIN: 11
 retval = -EAGAIN;
 // retval: -11

 // nr_threads: 0, max_threads: 총 free된 page 수 / 16
 if (nr_threads >= max_threads)
  goto bad_fork_cleanup_count;

 // p: kmem_cache#15-oX (struct task_struct),
 // task_thread_info(kmem_cache#15-oX (struct task_struct)):
 // (kmem_cache#15-oX (struct task_struct))->stack: 할당 받은 page 2개의 메로리의 가상 주소,
 // task_thread_info(kmem_cache#15-oX (struct task_struct)->exec_domain:
 // ((struct thread_info *) 할당 받은 page 2개의 메로리의 가상 주소)->exec_domain: &default_exec_domain,
 // task_thread_info(kmem_cache#15-oX (struct task_struct)->exec_domain->module:
 // (&default_exec_domain)->module: NULL,
 // try_module_get(NULL): true
 if (!try_module_get(task_thread_info(p)->exec_domain->module))
  goto bad_fork_cleanup_count;

 // p->did_exec: (kmem_cache#15-oX (struct task_struct))->did_exec
 p->did_exec = 0;
 // p->did_exec: (kmem_cache#15-oX (struct task_struct))->did_exec: 0

 // p: kmem_cache#15-oX (struct task_struct)
 delayacct_tsk_init(p); /* Must remain after dup_task_struct() */ // null function

 // clone_flags: 0x00800B00, p: kmem_cache#15-oX (struct task_struct)
 copy_flags(clone_flags, p);

 // copy_flags 에서 한일:
 // (kmem_cache#15-oX (struct task_struct))->flags: 0x00200040

 // &p->children: &(kmem_cache#15-oX (struct task_struct))->children
 INIT_LIST_HEAD(&p->children);

 // INIT_LIST_HEAD 에서 한일:
 // (&(kmem_cache#15-oX (struct task_struct))->children)->next: &(kmem_cache#15-oX (struct task_struct))->children
 // (&(kmem_cache#15-oX (struct task_struct))->children)->prev: &(kmem_cache#15-oX (struct task_struct))->children

 // &p->sibling: &(kmem_cache#15-oX (struct task_struct))->sibling
 INIT_LIST_HEAD(&p->sibling);

 // INIT_LIST_HEAD 에서 한일:
 // (&(kmem_cache#15-oX (struct task_struct))->sibling)->next: &(kmem_cache#15-oX (struct task_struct))->sibling
 // (&(kmem_cache#15-oX (struct task_struct))->sibling)->prev: &(kmem_cache#15-oX (struct task_struct))->sibling

 // p: kmem_cache#15-oX (struct task_struct)
 rcu_copy_process(p);

 // rcu_copy_process 에서 한일:
 // (kmem_cache#15-oX (struct task_struct))->rcu_read_lock_nesting: 0
 // (kmem_cache#15-oX (struct task_struct))->rcu_read_unlock_special: 0
 // (kmem_cache#15-oX (struct task_struct))->rcu_blocked_node: NULL
 // (&(kmem_cache#15-oX (struct task_struct))->rcu_node_entry)->next: &(kmem_cache#15-oX (struct task_struct))->rcu_node_entry
 // (&(kmem_cache#15-oX (struct task_struct))->rcu_node_entry)->prev: &(kmem_cache#15-oX (struct task_struct))->rcu_node_entry

 // p->vfork_done: (kmem_cache#15-oX (struct task_struct))->vfork_done
 p->vfork_done = NULL;
 // p->vfork_done: (kmem_cache#15-oX (struct task_struct))->vfork_done: NULL

 // &p->alloc_lock: &(kmem_cache#15-oX (struct task_struct))->alloc_lock
 spin_lock_init(&p->alloc_lock);

 // spin_lock_init에서 한일:
 // (&(kmem_cache#15-oX (struct task_struct))->alloc_lock)->raw_lock: { { 0 } }
 // (&(kmem_cache#15-oX (struct task_struct))->alloc_lock)->magic: 0xdead4ead
 // (&(kmem_cache#15-oX (struct task_struct))->alloc_lock)->owner: 0xffffffff
 // (&(kmem_cache#15-oX (struct task_struct))->alloc_lock)->owner_cpu: 0xffffffff

 // &p->pending: &(kmem_cache#15-oX (struct task_struct))->pending
 init_sigpending(&p->pending);

 // init_sigpending 에서 한일:
 // (&(&(kmem_cache#15-oX (struct task_struct))->pending)->signal)->sig[0]: 0
 // (&(&(kmem_cache#15-oX (struct task_struct))->pending)->signal)->sig[1]: 0
 // (&(&(kmem_cache#15-oX (struct task_struct))->pending)->list)->next: &(&(kmem_cache#15-oX (struct task_struct))->pending)->list
 // (&(&(kmem_cache#15-oX (struct task_struct))->pending)->list)->prev: &(&(kmem_cache#15-oX (struct task_struct))->pending)->list

 // p->utime: (kmem_cache#15-oX (struct task_struct))->utime,
 // p->stime: (kmem_cache#15-oX (struct task_struct))->stime,
 // p->gtime: (kmem_cache#15-oX (struct task_struct))->gtime
 p->utime = p->stime = p->gtime = 0;
 // p->utime: (kmem_cache#15-oX (struct task_struct))->utime: 0
 // p->stime: (kmem_cache#15-oX (struct task_struct))->stime: 0
 // p->gtime: (kmem_cache#15-oX (struct task_struct))->gtime: 0

 // p->utimescaled: (kmem_cache#15-oX (struct task_struct))->utimescaled,
 // p->stimescaled: (kmem_cache#15-oX (struct task_struct))->stimescaled
 p->utimescaled = p->stimescaled = 0;
 // p->utimescaled: (kmem_cache#15-oX (struct task_struct))->utimescaled: 0
 // p->stimescaled: (kmem_cache#15-oX (struct task_struct))->stimescaled: 0

#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE // CONFIG_VIRT_CPU_ACCOUNTING_NATIVE=n
 p->prev_cputime.utime = p->prev_cputime.stime = 0;
#endif
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN // CONFIG_VIRT_CPU_ACCOUNTING_GEN=n
 seqlock_init(&p->vtime_seqlock);
 p->vtime_snap = 0;
 p->vtime_snap_whence = VTIME_SLEEPING;
#endif

#if defined(SPLIT_RSS_COUNTING)
 // &p->rss_stat: &(kmem_cache#15-oX (struct task_struct))->rss_stat
 memset(&p->rss_stat, 0, sizeof(p->rss_stat));

 // memset 에서 한일:
 // &(kmem_cache#15-oX (struct task_struct))->rss_stat 값을 0 으로 초기화 수행
#endif

 // p->default_timer_slack_ns: (kmem_cache#15-oX (struct task_struct))->default_timer_slack_ns,
 // current->timer_slack_ns: (&init_task)->timer_slack_ns: 50000
 p->default_timer_slack_ns = current->timer_slack_ns;
 // p->default_timer_slack_ns: (kmem_cache#15-oX (struct task_struct))->default_timer_slack_ns: 50000

 // p->ioac: (kmem_cache#15-oX (struct task_struct))->ioac
 task_io_accounting_init(&p->ioac); // null function

 // p: kmem_cache#15-oX (struct task_struct)
 acct_clear_integrals(p); // null function

 // p: kmem_cache#15-oX (struct task_struct)
 posix_cpu_timers_init(p);

 // posix_cpu_timers_init 에서 한일:
 // (kmem_cache#15-oX (struct task_struct))->cputime_expires.prof_exp: 0
 // (kmem_cache#15-oX (struct task_struct))->cputime_expires.virt_exp: 0
 // (kmem_cache#15-oX (struct task_struct))->cputime_expires.sched_exp: 0
 // (&(kmem_cache#15-oX (struct task_struct))->cpu_timers[0])->next: &(kmem_cache#15-oX (struct task_struct))->cpu_timers[0]
 // (&(kmem_cache#15-oX (struct task_struct))->cpu_timers[0])->prev: &(kmem_cache#15-oX (struct task_struct))->cpu_timers[0]
 // (&(kmem_cache#15-oX (struct task_struct))->cpu_timers[1])->next: &(kmem_cache#15-oX (struct task_struct))->cpu_timers[1]
 // (&(kmem_cache#15-oX (struct task_struct))->cpu_timers[1])->prev: &(kmem_cache#15-oX (struct task_struct))->cpu_timers[1]
 // (&(kmem_cache#15-oX (struct task_struct))->cpu_timers[2])->next: &(kmem_cache#15-oX (struct task_struct))->cpu_timers[2]
 // (&(kmem_cache#15-oX (struct task_struct))->cpu_timers[2])->prev: &(kmem_cache#15-oX (struct task_struct))->cpu_timers[2]

 // &p->start_time: &(kmem_cache#15-oX (struct task_struct))->start_time
 do_posix_clock_monotonic_gettime(&p->start_time);

 // do_posix_clock_monotonic_gettime 에서 한일:
 // (kmem_cache#15-oX (struct task_struct))->start_time 에 현재 시간 값을 가져옴
 //
 // (&(kmem_cache#15-oX (struct task_struct))->start_time)->tv_sec: 현재의 sec 값 + 현재의 nsec 값 / 1000000000L
 // (&(kmem_cache#15-oX (struct task_struct))->start_time)->tv_nsec: 현재의 nsec 값 % 1000000000L

 // p->real_start_time: (kmem_cache#15-oX (struct task_struct))->real_start_time,
 // p->start_time: (kmem_cache#15-oX (struct task_struct))->start_time
 p->real_start_time = p->start_time;
 // (&(kmem_cache#15-oX (struct task_struct))->real_start_time)->tv_sec: 현재의 sec 값 + 현재의 nsec 값 / 1000000000L
 // (&(kmem_cache#15-oX (struct task_struct))->real_start_time)->tv_nsec: 현재의 nsec 값 % 1000000000L

 // &p->real_start_time: &(kmem_cache#15-oX (struct task_struct))->real_start_time
 monotonic_to_bootbased(&p->real_start_time);

 // monotonic_to_bootbased 에서 한일:
 // (kmem_cache#15-oX (struct task_struct))->real_start_time.tv_sec: normalized 된 sec 값
 // (kmem_cache#15-oX (struct task_struct))->real_start_time.tv_nsec: normalized 된 nsec 값

 // p->io_context: (kmem_cache#15-oX (struct task_struct))->io_context
 p->io_context = NULL;
 // p->io_context: (kmem_cache#15-oX (struct task_struct))->io_context: NULL

 // p->audit_context: (kmem_cache#15-oX (struct task_struct))->audit_context
 p->audit_context = NULL;
 // p->audit_context: (kmem_cache#15-oX (struct task_struct))->audit_context: NULL

// 2016/09/10 종료
// 2016/10/08 시작

 // clone_flags: 0x00800B00, CLONE_THREAD: 0x00010000
 if (clone_flags & CLONE_THREAD)
  threadgroup_change_begin(current);

 // p: kmem_cache#15-oX (struct task_struct)
 cgroup_fork(p);

 // cgroup_fork 에서 한일:
 // rcu reference의 값 (&init_task)->cgroups 이 유요한지 체크하고 그 값을 리턴함
 // ((&init_task)->cgroups)->refcount: 1
 // (kmem_cache#15-oX (struct task_struct))->cgroups: (&init_task)->cgroups
 //
 // (&(kmem_cache#15-oX (struct task_struct))->cg_list)->next: &(kmem_cache#15-oX (struct task_struct))->cg_list
 // (&(kmem_cache#15-oX (struct task_struct))->cg_list)->prev: &(kmem_cache#15-oX (struct task_struct))->cg_list

#ifdef CONFIG_NUMA // CONFIG_NUMA=n
 p->mempolicy = mpol_dup(p->mempolicy);
 if (IS_ERR(p->mempolicy)) {
  retval = PTR_ERR(p->mempolicy);
  p->mempolicy = NULL;
  goto bad_fork_cleanup_cgroup;
 }
 mpol_fix_fork_child_flag(p);
#endif
#ifdef CONFIG_CPUSETS // CONFIG_CPUSETS=n
 p->cpuset_mem_spread_rotor = NUMA_NO_NODE;
 p->cpuset_slab_spread_rotor = NUMA_NO_NODE;
 seqcount_init(&p->mems_allowed_seq);
#endif
#ifdef CONFIG_TRACE_IRQFLAGS // CONFIG_TRACE_IRQFLAGS=n
 p->irq_events = 0;
 p->hardirqs_enabled = 0;
 p->hardirq_enable_ip = 0;
 p->hardirq_enable_event = 0;
 p->hardirq_disable_ip = _THIS_IP_;
 p->hardirq_disable_event = 0;
 p->softirqs_enabled = 1;
 p->softirq_enable_ip = _THIS_IP_;
 p->softirq_enable_event = 0;
 p->softirq_disable_ip = 0;
 p->softirq_disable_event = 0;
 p->hardirq_context = 0;
 p->softirq_context = 0;
#endif
#ifdef CONFIG_LOCKDEP // CONFIG_LOCKDEP=n
 p->lockdep_depth = 0; /* no locks held yet */
 p->curr_chain_key = 0;
 p->lockdep_recursion = 0;
#endif

#ifdef CONFIG_DEBUG_MUTEXES // CONFIG_DEBUG_MUTEXES=y
 // p->blocked_on: (kmem_cache#15-oX (struct task_struct))->blocked_on
 p->blocked_on = NULL; /* not blocked yet */
 // p->blocked_on: (kmem_cache#15-oX (struct task_struct))->blocked_on: NULL
#endif
#ifdef CONFIG_MEMCG // CONFIG_MEMCG=n
 p->memcg_batch.do_batch = 0;
 p->memcg_batch.memcg = NULL;
#endif
#ifdef CONFIG_BCACHE // CONFIG_BCACHE=n
 p->sequential_io = 0;
 p->sequential_io_avg = 0;
#endif

 /* Perform scheduler related setup. Assign this task to a CPU. */
 // clone_flags: 0x00800B00, p: kmem_cache#15-oX (struct task_struct)
 sched_fork(clone_flags, p);

sched_fork()

  • start_kernel()
    • rest_init()
  • call: rest_init()
    • rcu_scheduler_starting()
    • kernel_thread()
  • call: kernel_thread()
    • do_fork()
  • call: do_fork()
    • copy_process()
  • call: copy_process()
    • security_task_create()
    • dup_task_struct()
    • ftrace_graph_init_task(p); // null function
    • get_seccomp_filter(p); // null function
    • rt_mutex_init_task(p);
    • copy_creds(p, clone_flags);
    • try_module_get()
    • delayacct_tsk_init(p)
    • copy_flags()
    • INIT_LIST_HEAD(&p->children);
    • INIT_LIST_HEAD(&p->sibling);
    • rcu_copy_process(p);
    • spin_lock_init(&p->alloc_lock);
    • init_sigpending(&p->pending);
    • memset(&p->rss_stat, 0, sizeof(p->rss_stat));
    • task_io_accounting_init(&p->ioac); // null function
    • acct_clear_integrals(p); // null function
    • posix_cpu_timers_init(p);
    • do_posix_clock_monotonic_gettime(&p->start_time);
    • monotonic_to_bootbased(&p->real_start_time);
    • cgroup_fork(p);
    • sched_fork(clone_flags, p);
// ARM10C 20161008
// clone_flags: 0x00800B00, p: kmem_cache#15-oX (struct task_struct)
void sched_fork(unsigned long clone_flags, struct task_struct *p)
{
 unsigned long flags;

 // get_cpu(): 0
 int cpu = get_cpu();
 // cpu: 0

 // clone_flags: 0x00800B00, p: kmem_cache#15-oX (struct task_struct)
 __sched_fork(clone_flags, p);

 // __sched_fork에서 한일:
 // (&kmem_cache#15-oX (struct task_struct))->on_rq: 0
 // (&kmem_cache#15-oX (struct task_struct))->se.on_rq: 0
 // (&kmem_cache#15-oX (struct task_struct))->se.exec_start: 0
 // (&kmem_cache#15-oX (struct task_struct))->se.sum_exec_runtime: 0
 // (&kmem_cache#15-oX (struct task_struct))->se.prev_sum_exec_runtime: 0
 // (&kmem_cache#15-oX (struct task_struct))->se.nr_migrations: 0
 // (&kmem_cache#15-oX (struct task_struct))->se.vruntime: 0
 // &(&kmem_cache#15-oX (struct task_struct))->se.group_node의 리스트 초기화
 // &(&kmem_cache#15-oX (struct task_struct))->rt.run_list의 리스트 초기화

 /*
  * We mark the process as running here. This guarantees that
  * nobody will actually run it, and a signal or other external
  * event cannot wake it up and insert it on the runqueue either.
  */

 // p->state: (kmem_cache#15-oX (struct task_struct))->state, TASK_RUNNING: 0
 p->state = TASK_RUNNING;
 // p->state: (kmem_cache#15-oX (struct task_struct))->state: 0

 /*
  * Make sure we do not leak PI boosting priority to the child.
  */
 // p->prio: (kmem_cache#15-oX (struct task_struct))->prio,
 // current: &init_task, current->normal_prio: (&init_task)->normal_prio: 120
 p->prio = current->normal_prio;
 // p->prio: (kmem_cache#15-oX (struct task_struct))->prio: 120

 /*
  * Revert to default priority/policy on fork if requested.
  */
 // p->>sched_reset_on_fork: (kmem_cache#15-oX (struct task_struct))->sched_reset_on_fork: 0
 if (unlikely(p->sched_reset_on_fork)) {
  if (task_has_rt_policy(p)) {
   p->policy = SCHED_NORMAL;
   p->static_prio = NICE_TO_PRIO(0);
   p->rt_priority = 0;
  } else if (PRIO_TO_NICE(p->static_prio) < 0)
   p->static_prio = NICE_TO_PRIO(0);

  p->prio = p->normal_prio = __normal_prio(p);
  set_load_weight(p);

  /*
   * We don't need the reset flag anymore after the fork. It has
   * fulfilled its duty:
   */
  p->sched_reset_on_fork = 0;
 }

 // p->prio: (kmem_cache#15-oX (struct task_struct))->prio: 120, rt_prio(120): 0
 if (!rt_prio(p->prio))
  // p->sched_class: (kmem_cache#15-oX (struct task_struct))->sched_class
  p->sched_class = &fair_sched_class;
  // p->sched_class: (kmem_cache#15-oX (struct task_struct))->sched_class: &fair_sched_class

// 2016/10/15 종료

 // p->sched_class: (kmem_cache#15-oX (struct task_struct))->sched_class: &fair_sched_class,
 // p->sched_class->task_fork: (&fair_sched_class)->task_fork: task_fork_fair
 if (p->sched_class->task_fork)
  // p->sched_class->task_fork: (&fair_sched_class)->task_fork: task_fork_fair,
  // p: kmem_cache#15-oX (struct task_struct),
  // task_fork_fair(kmem_cache#15-oX (struct task_struct))
  p->sched_class->task_fork(p);

  // task_fork_fair 에서 한일:

 /*
  * The child is not yet in the pid-hash so no cgroup attach races,
  * and the cgroup is pinned to this child due to cgroup_fork()
  * is ran before sched_fork().
  *
  * Silence PROVE_RCU.
  */
 raw_spin_lock_irqsave(&p->pi_lock, flags);
 set_task_cpu(p, cpu);

set_task_cpu()

void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
{
#ifdef CONFIG_SCHED_DEBUG
 /*
  * We should never call set_task_cpu() on a blocked task,
  * ttwu() will sort out the placement.
  */
 WARN_ON_ONCE(p->state != TASK_RUNNING && p->state != TASK_WAKING &&
   !(task_preempt_count(p) & PREEMPT_ACTIVE));

#ifdef CONFIG_LOCKDEP
 /*
  * The caller should hold either p->pi_lock or rq->lock, when changing
  * a task's CPU. ->pi_lock for waking tasks, rq->lock for runnable tasks.
  *
  * sched_move_task() holds both and thus holding either pins the cgroup,
  * see task_group().
  *
  * Furthermore, all task_rq users should acquire both locks, see
  * task_rq_lock().
  */
 WARN_ON_ONCE(debug_locks && !(lockdep_is_held(&p->pi_lock) ||
          lockdep_is_held(&task_rq(p)->lock)));
#endif
#endif

 trace_sched_migrate_task(p, new_cpu);

 if (task_cpu(p) != new_cpu) {
  if (p->sched_class->migrate_task_rq)
   p->sched_class->migrate_task_rq(p, new_cpu);
  p->se.nr_migrations++;
  perf_sw_event(PERF_COUNT_SW_CPU_MIGRATIONS, 1, NULL, 0);
 }

 __set_task_cpu(p, new_cpu);
}

_settask_cpu()

// ARM10C 20140913
// idle: &init_task, cpu: 0
// ARM10C 20161015
// p: kmem_cache#15-oX (struct task_struct), this_cpu: 0
static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu)
{
 // p: &init_task, cpu: 0
 set_task_rq(p, cpu);

 // set_task_rq 에서 한일:
 // (&init_task)->se.cfs_rq: [pcp0] &(&runqueues)->cfs
 // (&init_task)->se.parent: NULL
 // (&init_task)->rt.rt_rq: [pcp0] &(&runqueues)->rt
 // (&init_task)->rt.parent: NULL

#ifdef CONFIG_SMP // CONFIG_SMP=y
 /*
  * After ->cpu is set up to a new value, task_rq_lock(p, ...) can be
  * successfuly executed on another CPU. We must ensure that updates of
  * per-task data have been completed by this moment.
  */
 smp_wmb();
 // memory barrier 수행

 // p: &init_task, cpu: 0
 // (&init_task)->stack: &init_thread_info
 // task_thread_info(&init_task)->cpu: ((struct thread_info *)(&init_task)->stack)->cpu
 task_thread_info(p)->cpu = cpu;
 // task_thread_info(&init_task)->cpu: ((struct thread_info *)(&init_task)->stack)->cpu: 0

 // p->wake_cpu: (&init_task)->wake_cpu, cpu: 0
 p->wake_cpu = cpu;
 // p->wake_cpu: (&init_task)->wake_cpu: 0
#endif
}

sched_fork()

// ARM10C 20161008
// clone_flags: 0x00800B00, p: kmem_cache#15-oX (struct task_struct)
void sched_fork(unsigned long clone_flags, struct task_struct *p)
{
 unsigned long flags;

 // get_cpu(): 0
 int cpu = get_cpu();
 // cpu: 0

 // clone_flags: 0x00800B00, p: kmem_cache#15-oX (struct task_struct)
 __sched_fork(clone_flags, p);

 // __sched_fork에서 한일:
 // (&kmem_cache#15-oX (struct task_struct))->on_rq: 0
 // (&kmem_cache#15-oX (struct task_struct))->se.on_rq: 0
 // (&kmem_cache#15-oX (struct task_struct))->se.exec_start: 0
 // (&kmem_cache#15-oX (struct task_struct))->se.sum_exec_runtime: 0
 // (&kmem_cache#15-oX (struct task_struct))->se.prev_sum_exec_runtime: 0
 // (&kmem_cache#15-oX (struct task_struct))->se.nr_migrations: 0
 // (&kmem_cache#15-oX (struct task_struct))->se.vruntime: 0
 // &(&kmem_cache#15-oX (struct task_struct))->se.group_node의 리스트 초기화
 // &(&kmem_cache#15-oX (struct task_struct))->rt.run_list의 리스트 초기화

 /*
  * We mark the process as running here. This guarantees that
  * nobody will actually run it, and a signal or other external
  * event cannot wake it up and insert it on the runqueue either.
  */

 // p->state: (kmem_cache#15-oX (struct task_struct))->state, TASK_RUNNING: 0
 p->state = TASK_RUNNING;
 // p->state: (kmem_cache#15-oX (struct task_struct))->state: 0

 /*
  * Make sure we do not leak PI boosting priority to the child.
  */
 // p->prio: (kmem_cache#15-oX (struct task_struct))->prio,
 // current: &init_task, current->normal_prio: (&init_task)->normal_prio: 120
 p->prio = current->normal_prio;
 // p->prio: (kmem_cache#15-oX (struct task_struct))->prio: 120

 /*
  * Revert to default priority/policy on fork if requested.
  */
 // p->>sched_reset_on_fork: (kmem_cache#15-oX (struct task_struct))->sched_reset_on_fork: 0
 if (unlikely(p->sched_reset_on_fork)) {
  if (task_has_rt_policy(p)) {
   p->policy = SCHED_NORMAL;
   p->static_prio = NICE_TO_PRIO(0);
   p->rt_priority = 0;
  } else if (PRIO_TO_NICE(p->static_prio) < 0)
   p->static_prio = NICE_TO_PRIO(0);

  p->prio = p->normal_prio = __normal_prio(p);
  set_load_weight(p);

  /*
   * We don't need the reset flag anymore after the fork. It has
   * fulfilled its duty:
   */
  p->sched_reset_on_fork = 0;
 }

 // p->prio: (kmem_cache#15-oX (struct task_struct))->prio: 120, rt_prio(120): 0
 if (!rt_prio(p->prio))
  // p->sched_class: (kmem_cache#15-oX (struct task_struct))->sched_class
  p->sched_class = &fair_sched_class;
  // p->sched_class: (kmem_cache#15-oX (struct task_struct))->sched_class: &fair_sched_class

// 2016/10/15 종료

 // p->sched_class: (kmem_cache#15-oX (struct task_struct))->sched_class: &fair_sched_class,
 // p->sched_class->task_fork: (&fair_sched_class)->task_fork: task_fork_fair
 if (p->sched_class->task_fork)
  // p->sched_class->task_fork: (&fair_sched_class)->task_fork: task_fork_fair,
  // p: kmem_cache#15-oX (struct task_struct),
  // task_fork_fair(kmem_cache#15-oX (struct task_struct))
  p->sched_class->task_fork(p);

  // task_fork_fair 에서 한일:

 /*
  * The child is not yet in the pid-hash so no cgroup attach races,
  * and the cgroup is pinned to this child due to cgroup_fork()
  * is ran before sched_fork().
  *
  * Silence PROVE_RCU.
  */
 raw_spin_lock_irqsave(&p->pi_lock, flags);
 set_task_cpu(p, cpu);
 raw_spin_unlock_irqrestore(&p->pi_lock, flags);

#if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
 if (likely(sched_info_on()))
  memset(&p->sched_info, 0, sizeof(p->sched_info));
#endif
#if defined(CONFIG_SMP)
 p->on_cpu = 0;
#endif
 init_task_preempt_count(p);
#ifdef CONFIG_SMP
 plist_node_init(&p->pushable_tasks, MAX_PRIO);
#endif

 put_cpu();
}

log

  • 1st log
bcc0aa2..af56134  master     -> origin/master
Updating bcc0aa2..af56134
Fast-forward
arch/arm/include/asm/atomic.h           |   4 +
arch/arm/include/asm/thread_info.h      |   1 +
fs/file.c                               | 135 +++++++++++++++++++++++++++
include/asm-generic/bitops/non-atomic.h |   2 +
include/asm-generic/bitsperlong.h       |   1 +
include/asm-generic/current.h           |   1 +
include/asm-generic/preempt.h           |  13 +++
include/linux/audit.h                   |   4 +-
include/linux/compiler-gcc.h            |   1 +
include/linux/fdtable.h                 |   8 ++
include/linux/fs.h                      |   1 +
include/linux/gfp.h                     |   1 +
include/linux/list.h                    |   4 +
include/linux/lockdep.h                 |   2 +
include/linux/perf_event.h              |   2 +
include/linux/plist.h                   |  16 ++++
include/linux/preempt.h                 |   4 +
include/linux/preempt_mask.h            |  15 +++
include/linux/rcupdate.h                |  29 +++++-
include/linux/sched.h                   |  17 +++-
include/linux/sched/rt.h                |   1 +
include/linux/sem.h                     |   2 +
include/linux/smp.h                     |   1 +
include/linux/spinlock.h                |   8 ++
include/linux/thread_info.h             |   3 +
include/trace/events/sched.h            |   2 +
include/uapi/asm-generic/errno-base.h   |   1 +
include/uapi/linux/sched.h              |   4 +
ipc/sem.c                               |   7 ++
kernel/fork.c                           | 159 +++++++++++++++++++++++++++++++-
kernel/locking/lockdep.c                |   2 +
kernel/rcu/update.c                     |   2 +-
kernel/sched/core.c                     |  79 ++++++++++++++--
kernel/sched/fair.c                     |   2 +-
kernel/sched/sched.h                    |   2 +
mm/slub.c                               |   2 +
36 files changed, 524 insertions(+), 14 deletions(-)