3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Linux - copy_mm()あたりを眺めてみる

Last updated at Posted at 2020-01-19

Tux_Enhanced.svg.png

概要

マルチプロセス/スレッドあたりの違いの雰囲気を掴むために読んでみたのでまとめ。
見るバージョンは5.4を読んでみる
torvalds/linux

Linuxにおけるスレッドとプロセス

グリーンスレッド/ネイティブスレッド

  • グリーンスレッド

OSではなく仮想マシンなどよってスケジュールされるスレッド。
OSの機能によらずにマルチスレッド環境をエミュレートする。

  • ネイティブスレッド(軽量プロセス,LWP)

スレッドの実行スケジュールはOSのスケジューラが行う
(psコマンドでは-Lを付けて表示可能)

(余談)スレッドモデルの話

M:NスレッドとはカーネルスレッドがMに対しユーザースレッドがNとなるそれぞれが非対称なスレッドモデル
複数のユーザスレッドに対して、複数のカーネルスレッドをマップして動作する
golangではこちらを採用していてスイッチコストがとても低いらしい。

カーネルソースを眺めてみた

基本的にはfork(2)でもpthred_create()でも内部的にはdo_fork()を呼び出している。
cloneは呼び出された後はdo_forkを呼び出す。
プロセスとスレッドの生成の違いはこのdo_fork()を呼び出す際のフラグに差異があって区別されている模様。

long sys_clone(unsigned long clone_flags, unsigned long newsp,
	       void __user *parent_tid, void __user *child_tid)
{
	long ret;

	if (!newsp)
		newsp = UPT_SP(&current->thread.regs.regs);
	current->thread.forking = 1;
	ret = do_fork(clone_flags, newsp, &current->thread.regs, 0, parent_tid,
		      child_tid);
	current->thread.forking = 0;
	return ret;
}

処理の流れの概要

do_fork()
_do_fork()
copy_process()
copy_mm()
⑤ [dup_mmap()] (https://github.com/torvalds/linux/blob/v5.4/kernel/fork.c#L477-L627) (LWPではない場合は以下でcowの処理をする)
copy_page_range()
copy_one_pte() vmエリアを1つのタスクから別のタスクにコピー

static int copy_mm(unsigned long clone_flags, struct task_struct *tsk)
{
    struct mm_struct *mm, *oldmm;
    int retval;

    tsk->min_flt = tsk->maj_flt = 0;
    tsk->nvcsw = tsk->nivcsw = 0;
# ifdef CONFIG_DETECT_HUNG_TASK
    tsk->last_switch_count = tsk->nvcsw + tsk->nivcsw;
    tsk->last_switch_time = 0;
# endif

    tsk->mm = NULL;
    tsk->active_mm = NULL;

    oldmm = current->mm;
    if (!oldmm)
        return 0;

    // vmacacheエントリの初期化
    vmacache_flush(tsk);

    // CLONE_VM が設定された場合、呼び出し元のプロセスと子プロセスは
    // 同じメモリー空間で 実行される。
    if (clone_flags & CLONE_VM) {
        mmget(oldmm);
        // 親プロセスのmmを子にセットしgood_mmへ
        mm = oldmm;
        goto good_mm;
    }

    retval = -ENOMEM;
    // CLONE_VMがセットされていない場合は既存のmm構造体を複製する
    mm = dup_mm(tsk, current->mm);
    if (!mm)
        goto fail_nomem;

good_mm:
    tsk->mm = mm;
    tsk->active_mm = mm;
    return 0;

fail_nomem:
    return retval;
}

clone(2)の先で呼ばれるcopy_mmの処理。
CLONE_VMが設定されている(スレッド生成時のフラグ)場合は親プロセスとアドレスを共有していることがわかった。
https://linuxjm.osdn.jp/html/LDP_man-pages/man2/clone.2.html

static struct mm_struct *dup_mm(struct task_struct *tsk,
                struct mm_struct *oldmm)
{
    struct mm_struct *mm;
    int err;

    mm = allocate_mm();
    if (!mm)
        goto fail_nomem;

    // 親プロセス のメモリを生成されるプロセスへコピー
    memcpy(mm, oldmm, sizeof(*mm));

    if (!mm_init(mm, tsk, mm->user_ns))
        goto fail_nomem;

    err = dup_mmap(mm, oldmm);
    if (err)
        goto free_pt;

    mm->hiwater_rss = get_mm_rss(mm);
    mm->hiwater_vm = mm->total_vm;

    if (mm->binfmt && !try_module_get(mm->binfmt->module))
        goto free_pt;

    return mm;

free_pt:
    /* don't put binfmt in mmput, we haven't got module yet */
    mm->binfmt = NULL;
    mm_init_owner(mm, NULL);
    mmput(mm);

fail_nomem:
    return NULL;
}

copy_mmのメインの処理。
前段の処理の時点でCLONE_VM(スレッド)が設定されている場合はここの処理は行われない。
スレッドはスレッド作成元のデータにアクセスが可能。プロセスの場合は親プロセスのメモリをコピーしていく処理を行なっていく。(後述予定。。)

補足

mm_struct - アドレス空間の情報を管理する構造体

項目 概要
mmap vm_area_struct の先頭を保持する
mm_rb メモリエリアを高速に探すための red-black tree を保持する
mmap_cache メモリ参照の局所生(locality)を生かして高速化するためのもの
mm_count この構造体の参照カウンタ。0ならどのオブジェクトがも指されていない
mm_list mm_struct 構造体のリストを作るためのフィールド
start_code, end_code テキストセグメントの開始番地と終了番地
start_brk, brk ヒープの開始番地と終了番地
start_stack スタックの開始番地

参考

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?