Top > FreeBSD > システムプロセス


システムプロセス

  • FreeBSD の全てのユーザプロセスは、起動時に立ち上げられる init プロセスから作成される
  • init プロセスのプロセス識別子は、伝統的に 1 が割り当てられる
  • initプロセスの役割
    • 接続されている端末毎に getty プロセスを起動
    • ゾンビプロセスの終了ステータスを受け取る
    • マルチユーザからシングルユーザへ移行する通常のシャットダウン
    • カーネルの外部で動作(ユーザプロセスモード)


常駐カーネルプロセス

  • 起動直後に作られ常に存在するプロセス
  • 下記のプロセスは、完全にカーネル内で動作
  • 実行コードは、カーネルのロードイメージに含まれており、カーネルの特権モードで動作
プロセス名役割
idel他に何もすることが無い時に実行される
swapperプロセスを 2 次記憶から主記憶に読み込む
vmdaemonプロセス全体を主記憶から 2 次記憶に待避
pagedaemon仮想記憶システムのページング機能をサポートする為に、プロセスアドレス空間の一部を 2 次記憶に書き出す
pagezeroゼロ充填ページの準備
bufdaemonダーティバッファを書き出すことでクリーンバッファを確保
syncerダーティファイルデータが 30 秒以内に書き出されることを保証
ktraceシステムコールの実行履歴を出力ファイルに書き出す
vnlruLRU 方式によって、フリー vnode を確保する
randomカーネルと /dev/random で使用する乱数発生のためにエントロピーデータを収集する
g_event新しいデバイスの取り付けや取り外しなどによる構成変更を処理する
g_upデバイスドライバからプロセスに流れるデータを処理する
g_downプロセスからプロセスに流れるデータを処理する


idle プロセス

idle_setup()
  • idle_setup() は、CPU を休止させる為のスレッドを作る
  • kproc_kthread_add() を呼び出し、sched_idletd() を実行するスレッドを作る
  • FreeBSD では、アイドルスレッドをランキューではなく、pcpu 構造体の変数pc_idlethread に登録する
  • kproc_kthread_add() の中で RFSTOPPED フラグを指定
  • プロセススケジューラは、ランキューに登録されているプロセスの中から次に実行するものを選択して CPU を割り当てるが、
    実行可能なプロセスが存在しない場合は、pcpu 構造体からアイドルスレッドを取り出して CPU を割り当てる
    すべてを展開すべてを収束
      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
    
     
     
     
    -
    |
    |
    |
    |
    |
    |
    -
    |
    |
    |
    |
    |
    |
    |
    |
    |
    |
    |
    |
    |
    !
    !
    
    /* sys/kern/kern_idle.c */
    static void
    idle_setup(void *dummy)
    {
      struct pcpu *pc;
      struct proc *p;
      struct thread *td;
      int error;
     
      p = NULL; /* start with no idle process */
      SLIST_FOREACH(pc, &cpuhead, pc_allcpu) {
        error = kproc_kthread_add(sched_idletd, NULL, &p, &td,
                                  RFSTOPPED | RFHIGHPID, 0, "idle", "idle: cpu%d",
                                  pc->pc_cpuid);
        pc->pc_idlethread = td;
        if (error)
          panic("idle_setup: kproc_create error %d\n", error);
     
        thread_lock(td);
        TD_SET_CAN_RUN(td);
        td->td_flags |= TDF_IDLETD | TDF_NOLOAD;
        sched_class(td, PRI_IDLE);
        sched_prio(td, PRI_MAX_IDLE);
        thread_unlock(td);
      }
    }


sched_idletd()
  • 実際にアイドルスレッドが実行するサブルーチン
  • 実行可能状態のプロセスが存在しないときに実行され、実行可能状態のプロセスが現れると、コンテキストスイッチを行って、CPUを明け渡す
  • mi_switch() が次に実行するプロセスを選択し、コンテキストスイッチを行うサブルーチン
    すべてを展開すべてを収束
      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
    
     
     
     
    -
    |
    |
    |
    |
    |
    |
    |
    |
    -
    |
    |
    |
    |
    |
    |
    |
    |
    |
    |
    |
    -
    -
    |
    |
    |
    !
    !
    |
    |
    |
    -
    |
    |
    |
    !
    !
    !
    
    /* sys/kern/sched_ule.c */
    void
    sched_idletd(void *dummy)
    {
      struct thread *td;
      struct tdq *tdq;
      int switchcnt;
      int i;
     
      mtx_assert(&Giant, MA_NOTOWNED);
      td = curthread;
      tdq = TDQ_SELF();
      for (;;) {
        if (tdq_idled(tdq) == 0)
          continue;
     
        switchcnt = tdq->tdq_switchcnt + tdq->tdq_oldswitchcnt;
        /*
         * If we're switching very frequently, spin while checking
         * for load rather than entering a low power state that 
         * may require an IPI.  However, don't do any busy
         * loops while on SMT machines as this simply steals
         * cycles from cores doing useful work.
         */
        if (TDQ_IDLESPIN(tdq) && switchcnt > sched_idlespinthresh) {
          for (i = 0; i < sched_idlespins; i++) {
            if (tdq->tdq_load)
              break;
            cpu_spinwait();
          }
        }
        switchcnt = tdq->tdq_switchcnt + tdq->tdq_oldswitchcnt;
        if (tdq->tdq_load == 0)
          cpu_idle(switchcnt > 1);
        if (tdq->tdq_load) {
          thread_lock(td);
          mi_switch(SW_VOL | SWT_IDLE, NULL);
          thread_unlock(td);
        }
      }
    }


cpu_idle()
  • sched_idletd() の中で呼び出されている cpu_idle()は、CPUを休止させ、アイドル状態にするサブルーチン
  • 現在の実装では、XEN コンパイルオプションにより、cpu_idle_hlt() の関数がセットされている
  • cpu_idle_hlt() は、HLT 命令を実行してCPUを休止させる
  • そのままだと完全に停止してしまう為、前もって STI 命令によって割込み可能な状態にしている
  • CPU が外部から割込み信号を受けとると、再び動き始める
    すべてを展開すべてを収束
      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
    
     
     
     
    -
    |
    |
    |
    |
    |
    |
    |
    |
    |
    !
    
    /* sys/i386/i386/machdep.c */
    static void
    cpu_idle_hlt(int busy)
    {
      /*
       * we must absolutely guarentee that hlt is the next instruction
       * after sti or we introduce a timing window.
       */
      disable_intr();
      if (sched_runnable())
        enable_intr();
      else
        __asm __volatile("sti; hlt");
    }


参考


リロード   凍結解除 コピー 名前変更   ホーム 一覧 検索 最終更新 バックアップ リンク元   ヘルプ   最終更新のRSS
Last-modified: Mon, 03 Jun 2019 14:37:49 UTC (912d)