Embedded/Linux Kernel

[Linux Kernel] 커널 스레드(프로세스) 생성 과정 소스 분석

다크엔지니어 2022. 2. 7. 22:19
반응형

systemd 프로세스는 유저 공간에서 생성된 프로세스의 부모 프로세스 역할을 수행한다.

보통은 init 프로세스라 부르기도 한다.

보통 유저 프로세스에서 부모 프로세스가 소멸 되면, init 프로세스가 부모 역할을 수행하게 된다.

ps -ejH

 

프로세스 생성 과정

크게 두가지로 분류 할 수 있다.

1. 유저 레벨에서 생성된 프로세스

라이브러리(GNU C : glibc) 의 도움을 받아 커널에게 프로세스 생성 요청

2. 커널 레벨에서 생성된 프로세스

커널 내부의 kthread_create() 함수를 호출하여 커널 프로세스 생성

대부분 이를 커널 스레드 라고 부른다.

 

둘의 공통점은 _do_fork() 함수를 호출한다는 점이다.

init 프로세스 : 유저 레벨 프로세스 생성

kthreadd 프로세스 : 커널 레벨 프로세스 생성

두 프로세스는 생성 역할을 맡게 되는데, 두 프로세스의 리소스를 copy 하여 만들기 때문이다.

이유는 속도 향상을 위해서 이다.

 

실제로 리눅스 커널에서는 위와같은 방식으로 속도 향상에 신경을 많이 쓴다.

바로 커널 메모리 할당자인 Slub Memory Allocator 도 이와 유사한 기법을 활용한다.

드라이버에서 메모리 할당을 요청할 때 자주쓰는 구조체를 정의해서

해당 구조체에 대한 메모리를 미리 확보해 놓는다.

 

아래 경로에 보면 유저영역에서 커널에 요청을 위한 라이브러리가 모여있다.

유저 코드는 이 라이브러리와 링킹되어 메모리에 적재돼 실행된다.

 

 

유저 레벨 프로세스 생성

위 그림은 이전 글에서 ftrace 로 분석한 유저 레벨에서의 프로세스 생성 과정 이다.

 

 

 

커널 레벨 프로세스 생성

위 그림을 간단히 설명하면, 크게 두 가지로

1. kthreadd 프로세스에게 커널 프로세스 생성 요청

   kthread_create() kthread_create_on_node()

2. kthreadd 프로세스는 깨어나 자신에게 커널 프로세스 생성 요청 점검 후 생성

kthreadd() create_kthread()

 

리눅스 드라이버에서 워크를 워크큐에 큐잉하면 커널은 커널 스레드의 종류인 워커 스레드를 더 생성한다.

커널에서 메모리가 부족하면 페이지를 확보하는 kswapd 스레드를 깨워 실행한다.

즉, 리눅스 커널 시스템이 많은 일을 할때, 커널 스레드를 생성한다.

커널 스레드는 커널 공간에서 리소스 관리로 메모리와 전원 부분을 관리한다.

커널 스레드는 커널 공간에서만 생성되며, 유저 공간과 상호작용 하지 않는다.

커널에서 직접 실행, 휴먼 동작을 직접 제어하고, 대부분 시스템 부팅 시 생성 되고, 종료 시 까지

백그라운드로 실행 된다.

 

 

커널 스레드 항목 확인

  • kthreadd 프로세스로 커널 스레드들의 부모 프로세스 이다.

      스레드 핸들러 함수는 kthreadd() 이다.

  • 워커 스레드는 워크큐에 큐잉된 워크를 실행하는 프로세스 이다.

      스레드 핸들러 함수는 worker_thread() 이다. process_one_work() 를 호출해 워크를 실행하는 기능 수행

  • ksoftirqd 프로세스는 soft irq 를 위해 실행하는 프로세스 이다.

     smp_boot 형태의 스레드 이며, run_ksoftirqd() 함수가 스레드 핸들러 이며, Soft irq 서비스를 실행

     _do_softirq()함수에서 ksoftirqd를 깨운다.

  • irq/86-mmc1 스레드는 irq 스레드 라고 하며, 인터럽트 후반부 처리를 위해 사용된다.

     이름으로 기능을 유추 할 수 있다. 86번 mmc1 인터럽드의 후반부 처리하는 irq 스레드 인 것 이다.

ps axjf

 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
    0     2     0     0 ?           -1 S        0   0:00 [kthreadd]
    2     3     0     0 ?           -1 I<       0   0:00  \_ [rcu_gp]
    2     4     0     0 ?           -1 I<       0   0:00  \_ [rcu_par_gp]
    2     8     0     0 ?           -1 I<       0   0:00  \_ [mm_percpu_wq]
    2     9     0     0 ?           -1 S        0   0:00  \_ [rcu_tasks_rude_]
    2    10     0     0 ?           -1 S        0   0:00  \_ [rcu_tasks_trace]
    2    11     0     0 ?           -1 S        0   0:00  \_ [ksoftirqd/0]
    2    12     0     0 ?           -1 I        0   0:02  \_ [rcu_sched]
    2    13     0     0 ?           -1 S        0   0:00  \_ [migration/0]
    2    14     0     0 ?           -1 S        0   0:00  \_ [cpuhp/0]
    2    15     0     0 ?           -1 S        0   0:00  \_ [cpuhp/1]
    2    16     0     0 ?           -1 S        0   0:00  \_ [migration/1]
    2    17     0     0 ?           -1 S        0   0:00  \_ [ksoftirqd/1]
    2    20     0     0 ?           -1 S        0   0:00  \_ [cpuhp/2]
    2    21     0     0 ?           -1 S        0   0:00  \_ [migration/2]
    2    22     0     0 ?           -1 S        0   0:00  \_ [ksoftirqd/2]
    2    25     0     0 ?           -1 S        0   0:00  \_ [cpuhp/3]
    2    26     0     0 ?           -1 S        0   0:00  \_ [migration/3]
    2    27     0     0 ?           -1 S        0   0:00  \_ [ksoftirqd/3]
    2    30     0     0 ?           -1 S        0   0:00  \_ [kdevtmpfs]
    2    31     0     0 ?           -1 I<       0   0:00  \_ [netns]
    2    34     0     0 ?           -1 S        0   0:00  \_ [kauditd]
    2    36     0     0 ?           -1 S        0   0:00  \_ [khungtaskd]
    2    37     0     0 ?           -1 S        0   0:00  \_ [oom_reaper]
    2    38     0     0 ?           -1 I<       0   0:00  \_ [writeback]
    2    39     0     0 ?           -1 S        0   0:00  \_ [kcompactd0]
    2    59     0     0 ?           -1 I<       0   0:00  \_ [kblockd]
    2    60     0     0 ?           -1 I<       0   0:00  \_ [blkcg_punt_bio]
    2    61     0     0 ?           -1 S        0   0:00  \_ [watchdogd]
    2    62     0     0 ?           -1 I<       0   0:00  \_ [kworker/0:1H-kblockd]
    2    63     0     0 ?           -1 I<       0   0:00  \_ [rpciod]
    2    64     0     0 ?           -1 I<       0   0:00  \_ [kworker/u9:0-hci0]
    2    65     0     0 ?           -1 I<       0   0:00  \_ [xprtiod]
    2    66     0     0 ?           -1 S        0   0:00  \_ [kswapd0]
    2    69     0     0 ?           -1 I<       0   0:00  \_ [nfsiod]
    2    70     0     0 ?           -1 I<       0   0:00  \_ [kthrotld]
    2    71     0     0 ?           -1 I<       0   0:00  \_ [iscsi_eh]
    2    72     0     0 ?           -1 I<       0   0:00  \_ [iscsi_destroy]
    2    73     0     0 ?           -1 I<       0   0:00  \_ [nvme-wq]
    2    74     0     0 ?           -1 I<       0   0:00  \_ [nvme-reset-wq]
    2    75     0     0 ?           -1 I<       0   0:00  \_ [nvme-delete-wq]
    2    78     0     0 ?           -1 I<       0   0:00  \_ [DWC Notificatio]
    2    79     0     0 ?           -1 I<       0   0:00  \_ [uas]
    2    80     0     0 ?           -1 S<       0   0:00  \_ [vchiq-slot/0]
    2    81     0     0 ?           -1 S<       0   0:00  \_ [vchiq-recy/0]
    2    82     0     0 ?           -1 S<       0   0:00  \_ [vchiq-sync/0]
    2    83     0     0 ?           -1 I<       0   0:00  \_ [zswap-shrink]
    2    87     0     0 ?           -1 I<       0   0:00  \_ [sdhci]
    2    88     0     0 ?           -1 S        0   0:00  \_ [irq/66-mmc0]
    2    90     0     0 ?           -1 I<       0   0:00  \_ [mmc_complete]
    2    91     0     0 ?           -1 I<       0   0:00  \_ [kworker/3:1H-kblockd]
    2    93     0     0 ?           -1 S        0   0:00  \_ [jbd2/mmcblk0p2-]
    2    94     0     0 ?           -1 I<       0   0:00  \_ [ext4-rsv-conver]
    2    96     0     0 ?           -1 I<       0   0:00  \_ [ipv6_addrconf]
    2    98     0     0 ?           -1 I<       0   0:00  \_ [kworker/2:1H-kblockd]
    2   102     0     0 ?           -1 I<       0   0:00  \_ [kworker/1:1H-kblockd]
    2   192     0     0 ?           -1 S        0   0:00  \_ [vchiq-keep/0]
    2   195     0     0 ?           -1 S<       0   0:00  \_ [SMIO]
    2   208     0     0 ?           -1 I<       0   0:00  \_ [mmal-vchiq]
    2   210     0     0 ?           -1 S        0   0:04  \_ [v3d_bin]
    2   212     0     0 ?           -1 S        0   0:05  \_ [v3d_render]
    2   215     0     0 ?           -1 S        0   0:00  \_ [v3d_tfu]
    2   216     0     0 ?           -1 I<       0   0:00  \_ [mmal-vchiq]
    2   217     0     0 ?           -1 S        0   0:00  \_ [v3d_csd]
    2   218     0     0 ?           -1 S        0   0:00  \_ [v3d_cache_clean]
    2   223     0     0 ?           -1 I<       0   0:00  \_ [mmal-vchiq]
    2   225     0     0 ?           -1 I<       0   0:00  \_ [mmal-vchiq]
    2   227     0     0 ?           -1 I<       0   0:00  \_ [mmal-vchiq]
    2   231     0     0 ?           -1 I<       0   0:00  \_ [mmal-vchiq]
    2   260     0     0 ?           -1 I<       0   0:00  \_ [cfg80211]
    2   271     0     0 ?           -1 I<       0   0:00  \_ [brcmf_wq/mmc1:0]
    2   273     0     0 ?           -1 S        0   0:00  \_ [brcmf_wdog/mmc1]
    2   470     0     0 ?           -1 S        0   0:00  \_ [irq/57-vc4 hdmi]
    2   471     0     0 ?           -1 S        0   0:00  \_ [irq/58-vc4 hdmi]
    2   473     0     0 ?           -1 S        0   0:00  \_ [cec-vc4]
    2   480     0     0 ?           -1 S        0   0:00  \_ [irq/54-vc4 hdmi]
    2   481     0     0 ?           -1 S        0   0:00  \_ [irq/53-vc4 hdmi]
    2   499     0     0 ?           -1 S        0   0:00  \_ [irq/63-vc4 hdmi]
    2   501     0     0 ?           -1 S        0   0:00  \_ [irq/64-vc4 hdmi]
    2   502     0     0 ?           -1 S        0   0:00  \_ [cec-vc4]
    2   503     0     0 ?           -1 S        0   0:00  \_ [irq/60-vc4 hdmi]
    2   508     0     0 ?           -1 S        0   0:00  \_ [irq/59-vc4 hdmi]
    2   511     0     0 ?           -1 S        0   0:00  \_ [card1-crtc0]
    2   513     0     0 ?           -1 S        0   0:00  \_ [card1-crtc1]
    2   514     0     0 ?           -1 S        0   0:00  \_ [card1-crtc2]
    2   515     0     0 ?           -1 S        0   0:00  \_ [card1-crtc3]
    2   516     0     0 ?           -1 S        0   0:00  \_ [card1-crtc4]
    2   517     0     0 ?           -1 S        0   0:00  \_ [card1-crtc5]
    2   712     0     0 ?           -1 I<       0   0:00  \_ [kworker/u9:2-hci0]
    2   774     0     0 ?           -1 I<       0   0:00  \_ [cryptd]
    2   817     0     0 ?           -1 S<       0   0:00  \_ [krfcommd]
    2  1029     0     0 ?           -1 I        0   0:00  \_ [kworker/2:0-mm_percpu_wq]
    2  1157     0     0 ?           -1 I        0   0:00  \_ [kworker/1:1-events]
    2  1385     0     0 ?           -1 I<       0   0:00  \_ [kworker/1:2H]
    2  1425     0     0 ?           -1 I<       0   0:00  \_ [kworker/2:0H]
    2  1593     0     0 ?           -1 I        0   0:00  \_ [kworker/u8:1-events_unbound]
    2  1596     0     0 ?           -1 I        0   0:00  \_ [kworker/1:0]
    2  1650     0     0 ?           -1 I<       0   0:00  \_ [kworker/0:0H]
    2  1651     0     0 ?           -1 I        0   0:00  \_ [kworker/3:2-events]
    2  1683     0     0 ?           -1 I        0   0:00  \_ [kworker/u8:3-events_unbound]
    2  1684     0     0 ?           -1 I        0   0:00  \_ [kworker/0:1-events]
    2  1685     0     0 ?           -1 I        0   0:00  \_ [kworker/3:1-events]
    2  1704     0     0 ?           -1 I        0   0:00  \_ [kworker/2:1]
    2  1705     0     0 ?           -1 I<       0   0:00  \_ [kworker/3:2H]
    2  1718     0     0 ?           -1 I        0   0:00  \_ [kworker/3:0-events]
    2  1720     0     0 ?           -1 I        0   0:00  \_ [kworker/0:0-events]
    2  1721     0     0 ?           -1 I        0   0:00  \_ [kworker/3:3-events]
    2  1734     0     0 ?           -1 I        0   0:00  \_ [kworker/0:2-events]
    2  1735     0     0 ?           -1 I        0   0:00  \_ [kworker/u8:0-brcmf_wq/mmc1:0001:1]
    2  1740     0     0 ?           -1 I        0   0:00  \_ [kworker/u8:2-events_unbound]
    0     1     1     1 ?           -1 Ss       0   0:03 /sbin/init splash
    1   130   130   130 ?           -1 Ss       0   0:01 /lib/systemd/systemd-journald
    1   161   161   161 ?           -1 Ss       0   0:00 /lib/systemd/systemd-udevd
    1   353   353   353 ?           -1 Ss     108   0:00 avahi-daemon: running [raspberrypi.local]
  353   359   353   353 ?           -1 S      108   0:00  \_ avahi-daemon: chroot helper
    1   354   354   354 ?           -1 Ss       0   0:00 /usr/sbin/cron -f
    1   355   355   355 ?           -1 Ss     104   0:00 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
    1   374   374   374 ?           -1 Ssl      0   0:00 /usr/libexec/polkitd --no-debug
    1   401   401   401 ?           -1 Ssl      0   0:00 /usr/sbin/rsyslogd -n -iNONE
    1   418   418   418 ?           -1 Ss       0   0:00 /usr/sbin/dhcpcd -b
    1   430   430   430 ?           -1 Ss       0   0:00 /lib/systemd/systemd-logind
    1   431   431   431 ?           -1 Ss   65534   0:00 /usr/sbin/thd --triggers /etc/triggerhappy/triggers.d/ --socket /run/thd.socket --user nobody --deviceglob /dev/input/event*
    1   434   434   434 ?           -1 Ssl      0   0:00 /usr/libexec/udisks2/udisksd
    1   436   436   436 ?           -1 Ss       0   0:00 /sbin/wpa_supplicant -u -s -O /run/wpa_supplicant
    1   486   486   486 ?           -1 Ssl      0   0:00 /usr/sbin/ModemManager
    1   496   496   496 ?           -1 Ss     115   0:00 /usr/bin/epmd -systemd
    1   504   504   504 ?           -1 SLsl     0   0:00 /usr/sbin/rngd -r /dev/hwrng
    1   528   528   528 ?           -1 Ssl      0   0:00 /usr/sbin/lightdm
  528   586   586   586 tty7       586 Ssl+     0   0:45  \_ /usr/lib/xorg/Xorg :0 -seat seat0 -auth /var/run/lightdm/root/:0 -nolisten tcp vt7 -novtswitch
  528   646   528   528 ?           -1 Sl       0   0:00  \_ lightdm --session-child 18 21
  646   672   672   672 ?           -1 Ssl    109   0:17  |   \_ /usr/sbin/pi-greeter
  528   697   528   528 ?           -1 S        0   0:00  \_ lightdm --session-child 14 21
    1   587   587   587 ?           -1 Ss       0   0:00 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
  587   918   918   918 ?           -1 Ss       0   0:00  \_ sshd: devk [priv]
  918   953   918   918 ?           -1 S     1001   0:03  |   \_ sshd: devk@pts/0
  953   956   956   956 pts/0     1743 Ss    1001   0:00  |       \_ -bash
  956   977   977   956 pts/0     1743 S        0   0:00  |           \_ sudo su
  977   978   977   956 pts/0     1743 S        0   0:00  |               \_ su
  978   979   979   956 pts/0     1743 S        0   0:00  |                   \_ bash
  979  1743  1743   956 pts/0     1743 R+       0   0:00  |                       \_ ps axjf
  587   920   920   920 ?           -1 Ss       0   0:00  \_ sshd: devk [priv]
  920   975   920   920 ?           -1 S     1001   0:00  |   \_ sshd: devk@notty
  975   976   976   976 ?           -1 Ss    1001   0:00  |       \_ /usr/lib/openssh/sftp-server
  587  1555  1555  1555 ?           -1 Ss       0   0:00  \_ sshd: devk [priv]
 1555  1562  1555  1555 ?           -1 S     1001   0:00  |   \_ sshd: devk@pts/1
 1562  1564  1564  1564 pts/1     1564 Ss+   1001   0:00  |       \_ -bash
  587  1557  1557  1557 ?           -1 Ss       0   0:00  \_ sshd: devk [priv]
 1557  1581  1557  1557 ?           -1 S     1001   0:00      \_ sshd: devk@notty
 1581  1582  1582  1582 ?           -1 Ss    1001   0:00          \_ /usr/lib/openssh/sftp-server
    1   603   603   603 ?           -1 Ss       0   0:00 /sbin/wpa_supplicant -s -B -P /run/wpa_supplicant.wlan0.pid -i wlan0 -D nl80211,wext -c /etc/wpa_supplicant/wpa_supplicant.conf
    1   650   650   650 ?           -1 Ss     109   0:00 /lib/systemd/systemd --user
  650   651   650   650 ?           -1 S      109   0:00  \_ (sd-pam)
  650   670   670   670 ?           -1 S<sl   109   0:00  \_ /usr/bin/pipewire
  670   679   670   670 ?           -1 S<l    109   0:00  |   \_ /usr/bin/pipewire-media-session
  650   671   671   671 ?           -1 S<sl   109   0:00  \_ /usr/bin/pulseaudio --daemonize=no --log-target=journal
  650   678   678   678 ?           -1 Ss     109   0:00  \_ /usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
  650   683   683   683 ?           -1 Ssl    109   0:00  \_ /usr/libexec/gvfsd
  650   688   683   683 ?           -1 Sl     109   0:00  \_ /usr/libexec/gvfsd-fuse /run/user/109/gvfs -f
    1   674   674   674 ?           -1 SNsl   110   0:00 /usr/libexec/rtkit-daemon
    1   713   370   370 ?           -1 S        0   0:00 /usr/bin/hciattach /dev/serial1 bcm43xx 3000000 flow -
    1   728   728   728 ?           -1 Ss       0   0:00 /usr/libexec/bluetooth/bluetoothd
    1   835   835   835 ?           -1 Ss       0   0:00 /usr/sbin/cupsd -l
  835   836   836   835 ?           -1 S        7   0:00  \_ /usr/lib/cups/notifier/dbus dbus://
    1   837   837   837 ?           -1 Ssl      0   0:00 /usr/sbin/cups-browsed
    1   922   922   922 ?           -1 Ss    1001   0:00 /lib/systemd/systemd --user
  922   924   922   922 ?           -1 S     1001   0:00  \_ (sd-pam)
  922   945   945   945 ?           -1 Ssl   1001   0:00  \_ /usr/bin/pipewire
  945   954   945   945 ?           -1 Sl    1001   0:00  |   \_ /usr/bin/pipewire-media-session
  922   946   946   946 ?           -1 Ssl   1001   0:00  \_ /usr/bin/pulseaudio --daemonize=no --log-target=journal
  922   951   951   951 ?           -1 Ss    1001   0:00  \_ /usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
    1  1702  1702  1702 ?           -1 Ssl    100   0:00 /lib/systemd/systemd-timesyncd

위에서 대표적인 커널스레드를 소개했으니, 아래에서는 생성 과정을 소스로 알아가 보자.

 

 

커널 스레드 생성 과정 소스 분석

kthread 프로세스에게 커널 스레드 생성 요청

실제 kthread_create 함수에 커널 스레드 핸들러 함수를 지정해야 한다.

kthread_create() 함수 분석

매크로 형태로 작성 되어있다. 이는 스텍프레임을 안 사용하여 실행 속도 증가를 위함이다.

하지만 실행파일이 커지는 단점을 가지고 있다. 참고하면 좋다.

인자값들을 보면

threadfn 을 통해 스레드 핸들러 함수를 전달하고, data 는 스레드 핸들러 함수로 전달하는

데이터 이다. node 는 말 그대로 node 정보를 전달, name은 커널 스레드 이름 이다.

/include/linux/kthread.h

 

아래는 커널 레벨에서 커널 스레드 생성 코드 이다.

vhost_worker 스레드 핸들러 함수로 vhost_dev data 를 같이 전달한다.

name 은 vhost-pid 인 것을 확인 할 수 있다.

drivers/vhost/vhost.c

 

아래 매개변수로 void* 캐스팅을 되는 것을 확인 할 수 있다.

drivers/vhost/vhost.c

 

kthread_create_on_ndoe() 함수 분석

아래 함수는 특별한 역할을 하지는 않는다. 단지, task_struct 리턴 값을 전달하주며,

va_start va_end로 va_list를 전달한다.

kernel/kthread.c 

 

__kthread_create_on_ndoe() 함수 분석

실제 아래 함수가 호출이 되고, kthread_create_info 에 스레드 핸들러 함수를 heap 메모리에 할당하여 처리한다.

kfree 로 해제는 당연하다.

주요 깊게 봐야 될 부분은 list_add_tail을 통해 커널 스레드 생성 요청을 관리하는 kthread_create_list 연결 리스트에

&create->list 를 추가한다는 점이다. kthread 프로세스는 kthread_create_list 연결 리스트를 확인해

커널 스레드 생성 요청이 있었는지 확인 한다.

그리고 kthread 프로세스의 테스크 디스크립터인 kthread_task를 인자로 kthread 프로세스를 깨운다.

 

 

kthread 프로세스가 커널 스레드를 생성

kthreadd() 함수 분석

이렇게 위의 과정으로 kthread 프로세스를 깨우게 되면, 스레드 핸들러 kthreadd()함수가 실행이 된다.

kthreadd() 함술의 핵심 기능은 다음과 같다.

  • kthread_create_lnfo 연결 리스트를 확인해 프로세스 요청 확인
  • create_kthread() 함수를 호출해 프로세스 생성

list에 요청 건이 없다면, schdule()함수로 진입해 휴면상태에 진입 하고

요청이 있다면, __set_current_state 를 실행한다.

 

연결리스트 알고리즘에서 _list 는 head, 로서 info 정보를 담고있는 구조체에 next 로 접근한다.

_list의 next 로 마지막 _info 의 list_head 를 가리키게 된다.

바로 info 구조체에서 list 필드의 offset 을 계산해 info 구조체의 시작 주소를 알 수 있다.

 

그리고 create_kthread(create) 함수를 호출해 커널 스레드를 생성한다.

 

create_kthread() 함수 분석

kernel_thread 호출 시 CLONE_FS CLONE_FILES SIGCHLD flag OR 연산으로 설정한다.

즉, 리소스에 3개 해당 항목을 추가하게 된다.

 

kernel_thread() 함수 분석

kernel/fork.c

kernel_clone 함수 호출이 되며, 이는 유저 레벨 생성 시 에도 동일하게 호출되는 함수이다.

 

 

여기까지를 정리하자면,

kthread_create 를 통해 스레드 핸들러함수와 핸들러에 전달할 매개변수 그리고 이름을 지정하고,

kthraedd 프로세스가 깨어나면, list 와 info 연결리스트를 통해 요청 된 프로세스를 생성하게 된다.

 

kernel_clone, do_fork() 함수 분석

Armv8 부턴 do_fork 에서 kernel_clone 으로 변경 되었다.

kernel_clone 함수의 동작은 크게 두 가지가 있다.

  • copy_process 함수를 호출해서 프로세스를 생성, 부모 프로세스의 리소스를 자식 프로세스에게 복제
  • copy_process 함수 호출해 프로세스를 만든 후 wake up new task 함수로 프로세스를 꺠우고, 깨운다는 것은 스케줄러에게 프로세스 실행을 요청하는 것이다.

copy_process에서 리턴된 p 값으로 테스크 디스크립터의 주소를 담고 있는 변수로 오류가 있는지 검사한다.

그리고 ftrace 이벤트 중 sched_process_fork 를 활성화 해주는 함수가 trace_shced_process_fork 함수 이다.

wake_up_new_task 함수를 통해 생성한 프로세스를 깨운다. 그리고 생성한 PID 반환

 

copy_process() 함수 분석

사실 프로세스를 생성하는 핵심 동작이 이 함수에 구현되어 있다.

양이 많아서 핵심 부분만 설명 하자면,

아래 함수로 생성할 프로세스의 테스크 디스크립터인 task_struct 구조체와 프로세스가 실행 될 스택공간을 할당한다.

아래 함수를 통해 task_struct 스케줄링 정보를 초기화 한다.

부모 프로세스의 리소스들을 복사 한다.

 

wake_up_new_task() 함수 분석

프로세스 생성의 마지막 단계로 kernel/sched/core.c

다행히 길지 않다.. ㅎ

p->state 에 TASK_RUNNING 으로 상태 전환 후

__set_task_cpu 로 thread_info 구조체의 cpu 필드에 현재 실행 중인 cpu 번호를 할당한다.

나중에 모든 프로세스의 cpu 번호 출력은 thread_info 구조체를 통해 리스트 업 되어진다.

 

그리고 __task_rq_lock 을 시작으로 런큐 주소를 읽은 다음, activate_task 함수를 호출해

런큐에 새롭게 추가된 프로세스를 삽입한다.

 

이로서 커널 레벨에서의 커널 스레드 생성 과정을 소스로 알아보았다.

유저 레벨에서도 Armv8 기준인 kernel_clone 은 공통적으로 호출이 되어지는 것으로 보아

두 과정 모두 부모 프로세스가 다를뿐 부모의 리소스를 그대로 복제하여 자식 프로세스가 생성 됨을

알 수 있다.

 

 

아래는 참고를 위해 ftrace 에서 본 생성 종료 콜 스텍이다.

ftrace 를 통한 프로세스 생성 및 종료 함수 흐름(콜 스텍) process 1424

1. 프로세스 생성 단계의 함수 흐름

 

2. 프로세스 종료 단계의 함수 흐름

 

반응형