Skip to content

Commit

Permalink
return OTP 27 process labels in debug adapter threads response
Browse files Browse the repository at this point in the history
  • Loading branch information
lukaszsamson committed Jun 4, 2024
1 parent 505a50f commit 37c7019
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 6 deletions.
26 changes: 20 additions & 6 deletions apps/debug_adapter/lib/debug_adapter/server.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2278,13 +2278,27 @@ defmodule ElixirLS.DebugAdapter.Server do
end

defp process_name(process_info) do
registered_name = Keyword.get(process_info, :registered_name)
# if present registered_name is na atom
registered_name = Keyword.fetch(process_info, :registered_name)
# OTP 27+ process label may be any term
# it's not documented but :proc_lib.get_label reads `:$process_label` key from process dictionary
# https://github.com/erlang/otp/blob/601a012837ea0a5c8095bf24223132824177124d/lib/stdlib/src/proc_lib.erl#L876
# we have already read it so can get it directly
label = process_info |> Keyword.fetch!(:dictionary) |> Keyword.fetch(:"$process_label")

if registered_name do
inspect(registered_name)
else
{mod, func, arity} = Keyword.fetch!(process_info, :initial_call)
"#{inspect(mod)}.#{to_string(func)}/#{arity}"
case {registered_name, label} do
{{:ok, registered_name}, {:ok, label}} ->
"#{registered_name}: #{inspect(label)}"

{{:ok, registered_name}, _} ->
to_string(registered_name)

{_, {:ok, label}} ->
inspect(label)

_ ->
{mod, func, arity} = Keyword.fetch!(process_info, :initial_call)
"#{inspect(mod)}.#{to_string(func)}/#{arity}"
end
end

Expand Down
72 changes: 72 additions & 0 deletions apps/debug_adapter/test/debugger_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -3303,6 +3303,78 @@ defmodule ElixirLS.DebugAdapter.ServerTest do
end)
end

if System.otp_release() |> String.to_integer() >= 27 do
@tag :fixture
test "returns process label", %{server: server} do
in_fixture(__DIR__, "mix_project", fn ->
Server.receive_packet(server, initialize_req(1, %{}))

assert_receive(
response(_, 1, "initialize", %{"supportsConfigurationDoneRequest" => true})
)

Server.receive_packet(
server,
launch_req(2, %{
"request" => "launch",
"type" => "mix_task",
"task" => "run",
"taskArgs" => ["-e", "MixProject.Some.sleep()"],
"projectDir" => File.cwd!()
})
)

assert_receive(response(_, 2, "launch", %{}), 5000)
assert_receive(event(_, "initialized", %{}))

Server.receive_packet(server, request(5, "configurationDone", %{}))
assert_receive(response(_, 5, "configurationDone", %{}))
Process.sleep(1000)

{:ok, pid} =
Task.start(fn ->
:proc_lib.set_label("foo")

receive do
:done -> :ok
end
end)

Process.monitor(pid)

send(server, :update_threads)
state = :sys.get_state(server)

thread_id = state.pids_to_thread_ids[pid]
assert thread_id
assert state.thread_ids_to_pids[thread_id] == pid

Server.receive_packet(server, request(6, "threads", %{}))
assert_receive(response(_, 6, "threads", %{"threads" => threads}), 1_000)

assert Enum.find(threads, &(&1["id"] == thread_id))["name"] ==
"\"foo\" #{:erlang.pid_to_list(pid)}"

send(pid, :done)

receive do
{:DOWN, _, _, ^pid, _} -> :ok
end

send(server, :update_threads)
state = :sys.get_state(server)

refute Map.has_key?(state.pids_to_thread_ids, pid)
refute Map.has_key?(state.thread_ids_to_pids, thread_id)

Server.receive_packet(server, request(6, "threads", %{}))
assert_receive(response(_, 6, "threads", %{"threads" => threads}), 1_000)

refute Enum.find(threads, &(&1["id"] == thread_id))
end)
end
end

describe "evaluate" do
defp gen_watch_expression_packet(seq, expr) do
%{
Expand Down

0 comments on commit 37c7019

Please sign in to comment.