【TIPS】iexの裏で動いているプロセス

この記事は、[Elixir Advent Calendar 2023 シリーズ14](https://qiita.com/advent-calendar/2023/elixir) の17日目です

---

【本コラムは、3分で読め、3分で試せます】

[piacere](https://twitter.com/piacere_ex) です、ご覧いただいてありがとございます :bow:

iexの裏で動いているプロセスを拾ってみます

# プロセスのリストアップ

現在、生きているプロセスをリストアップします

```elixir
iex> list = Process.list |> Enum.map(& {&1, Process.info(&1)}) 
[
  {#PID<0.0.0>,
   [
     registered_name: :init,
     current_function: {:init, :loop, 1},
     initial_call: {:erl_init, :start, 2},
     status: :waiting,
     message_queue_len: 0,
     links: [#PID<0.42.0>, #PID<0.44.0>, #PID<0.10.0>],
     dictionary: [],
     trap_exit: true,
     error_handler: :error_handler,
     priority: :normal,
     group_leader: #PID<0.0.0>,
     total_heap_size: 3196,
     heap_size: 1598,
     stack_size: 2,
     reductions: 9495,
     garbage_collection: [
       max_heap_size: %{error_logger: true, kill: true, size: 0},
       min_bin_vheap_size: 46422,
       min_heap_size: 233,
       fullsweep_after: 65535,
       minor_gcs: 3
     ],
     suspending: []
   ]},
  {#PID<0.1.0>,
   [
     registered_name: :erts_code_purger,
     current_function: {:erlang, :hibernate, 3},
     initial_call: {:erts_code_purger, :start, 0},
     status: :waiting,
     message_queue_len: 0,
     links: [],
     dictionary: [],
     trap_exit: true,
     error_handler: :error_handler,
     priority: :high,
     group_leader: #PID<0.0.0>,
     total_heap_size: 4,
     heap_size: 4,
     stack_size: 1,
     reductions: 22482,
     garbage_collection: [
       max_heap_size: %{error_logger: true, kill: true, size: 0},
       min_bin_vheap_size: 46422,
       min_heap_size: 233,
       fullsweep_after: 65535,
       minor_gcs: 2
     ],
     suspending: []
   ]}
  …
```

`:registered_name` のみ拾ってみます

```elixir
iex> list |> Enum.map(& &1 |> elem(1) |> Keyword.get(:registered_name)) 
[:init, :erts_code_purger, nil, nil, nil, nil, nil, :socket_registry,
 :erl_prim_loader, :logger, :application_controller, nil, nil, :kernel_sup,
 :code_server, :inet_db, :rex, nil, :global_name_server, nil, nil,
 :global_group, :file_server_2, :erl_signal_server, :standard_error_sup,
 :standard_error, nil, :user_drv, :user, nil, nil, :kernel_refc,
 :kernel_safe_sup, :logger_sup, :logger_handler_watcher, :logger_proxy, nil,
 nil, nil, :elixir_sup, :elixir_config, :elixir_code_server, nil, nil,
 IEx.Supervisor, IEx.Config, IEx.Broker, IEx.Pry, nil, nil, ...]
```

nil以外を拾います

```elixir 
iex> list |> Enum.map(& &1 |> elem(1) |> Keyword.get(:registered_name)) |> Enum.reject(& &1 == nil)
[:init, :erts_code_purger, :socket_registry, :erl_prim_loader, :logger,
 :application_controller, :kernel_sup, :code_server, :inet_db, :rex,
 :global_name_server, :global_group, :file_server_2, :erl_signal_server,
 :standard_error_sup, :standard_error, :user_drv, :user, :kernel_refc,
 :kernel_safe_sup, :logger_sup, :logger_handler_watcher, :logger_proxy,
 :elixir_sup, :elixir_config, :elixir_code_server, IEx.Supervisor, IEx.Config,
 IEx.Broker, IEx.Pry, Logger.Supervisor, :logger_std_h_default]
```

# プロセスの詳細を調べる

拾ったプロセス名から、適当なプロセスをピックアップして、詳細を見てみます（ここでは `:global_name_server` を選択しました）

```elixir
iex> list |> Enum.filter(& &1 |> elem(1) |> Keyword.get(:registered_name) == :global_name_server)
[
  {#PID<0.55.0>,
   [
     registered_name: :global_name_server,
     current_function: {:gen_server, :loop, 7},
     initial_call: {:proc_lib, :init_p, 5},
     status: :waiting,
     message_queue_len: 0,
     links: [#PID<0.56.0>, #PID<0.57.0>, #PID<0.49.0>],
     dictionary: [
       rand_seed: {%{
          bits: 58,
          jump: #Function<3.34006561/1 in :rand.exsplus_jump>,
          next: #Function<0.34006561/1 in :rand.exsss_next>,
          type: :exsss,
          uniform: #Function<1.34006561/1 in :rand.exsss_uniform>,
          uniform_n: #Function<2.34006561/2 in :rand.exsss_uniform>
        }, [94824658367563367 | 25895920018195810]},
       "$initial_call": {:global, :init, 1},
       "$ancestors": [:kernel_sup, #PID<0.47.0>],
       creation_extension: 591010589673783296
     ],
     trap_exit: true,
     error_handler: :error_handler,
     priority: :normal,
     group_leader: #PID<0.46.0>,
     total_heap_size: 1597,
     heap_size: 987,
     stack_size: 11,
     reductions: 904,
     garbage_collection: [
       max_heap_size: %{error_logger: true, kill: true, size: 0},
       min_bin_vheap_size: 46422,
       min_heap_size: 233,
       fullsweep_after: 65535,
       minor_gcs: 2
     ],
     suspending: []
   ]}
]
```

`:global_name_server` は、下記に解説ある通り、Erlangノードの名前解決を司るサーバです

https://www.erlang.org/doc/man/global.html

`:global.register_name` や `:global.whereis_name` を使った分散の要で、色々な遊び方があるのですが、これはまた別のコラムに預けるとします