레이블이 arm인 게시물을 표시합니다. 모든 게시물 표시
레이블이 arm인 게시물을 표시합니다. 모든 게시물 표시

2022년 4월 14일 목요일

Native, Docker for Mac, Lima에서 실행 결과 비교

요약

Intel Core i7 13.780s Apple M1 Pro 9.733s

결론

Intel CPU 맥은 Docker for Mac과 Lima가 그다지 실행 시간이 차이가 크지 않지만, M1 Pro는 네이티브에 가까운 속도까지 성능이 나온다. 

결과

결과를 정리하면 아래 표와 같이 된다.

실행 방법CPUDocker platformTotal
NativeIntel Core i79.761s
Apple M1 Pro9.302s
Docker for MacIntel Core i7amd64,x8613.898s
Apple M1 Proamd64,x8633.557s
Apple M1 Proaach64,arm15.980s
LimaIntel Core i7amd64,x8613.780s
Apple M1 Proaach64,arm9.733s

M1 was running arm images, but as far as I know Docker Desktop on M1 use Qemu which is super slow anyway.

2022년 4월 7일 목요일

macOS (M1) 환경에서 Docker 를 대치할 만한 것들

 macOS 특히 M1을 사용했을 때 Docker for Mac이 왜 이리도 느릴까 싶습니다. 

x86에서도 Docker for Mac이 느렸지만,  M1과 결합하면 더욱 느립니다. 

개발 환경의 대세는 M1 air와 M1 Pro/Max/Ultra라고 생각합니다. 하지만 악화됩니다. M1 Pro로 애플리케이션의 벤치마크를 해보면 잡으면 4년 전 Intel Macbook Pro(i7) 보다 느리기에 Docker for Mac을 지웠습니다. 


하지만 docker가 없으면 일을 하기 어렵기 때문에 다른 방법을 찾았습니다. 


|도구 이름 |구조 |메리트|단점|Watch|Star|Issues|

도구특징좋은점안좋은점WatchStarIssues
Podman데몬을 필요로 하지 않고 컨테이너를 안전하게 실행할 수 있다. 설치가 쉽다.일부 docker 명령(예: 네트워크)을 지원하지 않는다.17811.2k190
MinikubeHyperkit나VirtualBox에서동작한다. Kubernetes를 사용할 수 있다. Kubernetes는 Docker를 더 이상 사용하지 않으므로 향후 어떻게 할지 모름46822.5k607
Multipass기본적으로 HyperKit, QEMU/KVM 등의 하이퍼바이저를 통해 실행한다. 이기종 환경을 지원한다. (Linux/Mac/Windows)
773.8k327
LimaDocker CLI + Docker REST API를 사용하여 Lima(VM)에서 Docker Engine을 사용Docker for Mac과 가장 비슷한 사용자 환경을 제공설정하는데 참조 자료가 아직은 적다. 485.1k62

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(-)