Current section

Files

Jump to
codex_sdk lib codex process_exit.ex
Raw

lib/codex/process_exit.ex

defmodule Codex.ProcessExit do
@moduledoc false
alias CliSubprocessCore.ProcessExit, as: CoreProcessExit
@spec exit_status(term()) :: {:ok, integer()} | :unknown
def exit_status(reason)
def exit_status(:normal), do: {:ok, 0}
def exit_status({:exit_code, status}) when is_integer(status), do: {:ok, status}
def exit_status({:exit_status, status}) when is_integer(status) do
{:ok, normalize_wait_status(status)}
end
def exit_status({:signal, signal, _core?}) do
{:ok, 128 + signal_to_int(signal)}
end
def exit_status(status) when is_integer(status) do
{:ok, normalize_wait_status(status)}
end
def exit_status(reason) do
if CoreProcessExit.match?(reason) do
exit_status_from_core(reason)
else
exit_status_fallback(reason)
end
end
defp exit_status_from_core(reason) do
case {CoreProcessExit.status(reason), CoreProcessExit.code(reason),
CoreProcessExit.signal(reason)} do
{:success, _code, _signal} -> {:ok, 0}
{:exit, status, _signal} when is_integer(status) -> {:ok, status}
{:signal, _code, signal} -> {:ok, 128 + signal_to_int(signal)}
_other -> exit_status(CoreProcessExit.reason(reason))
end
end
defp exit_status_fallback({:shutdown, reason}), do: exit_status(reason)
defp exit_status_fallback({:transport, reason}), do: exit_status(reason)
defp exit_status_fallback({:send_failed, reason}), do: exit_status(reason)
defp exit_status_fallback({:call_exit, reason}), do: exit_status(reason)
defp exit_status_fallback({:error, reason}), do: exit_status(reason)
defp exit_status_fallback({:exit, reason}), do: exit_status(reason)
defp exit_status_fallback({:EXIT, _pid, reason}), do: exit_status(reason)
defp exit_status_fallback({reason, {GenServer, :call, _}}), do: exit_status(reason)
defp exit_status_fallback({reason, _meta}) do
if wrapped_exit_reason?(reason) do
exit_status(reason)
else
:unknown
end
end
defp exit_status_fallback(_reason), do: :unknown
@spec normalize_reason(term()) :: :normal | {:exit_code, integer()} | term()
def normalize_reason(reason) do
case exit_status(reason) do
{:ok, 0} -> :normal
{:ok, status} -> {:exit_code, status}
:unknown -> reason
end
end
@spec normalize_wait_status(integer()) :: integer()
def normalize_wait_status(raw_status) when is_integer(raw_status) do
exit = CoreProcessExit.from_reason(raw_status)
cond do
CoreProcessExit.status(exit) == :success ->
0
CoreProcessExit.status(exit) == :exit and is_integer(CoreProcessExit.code(exit)) ->
CoreProcessExit.code(exit)
CoreProcessExit.status(exit) == :signal ->
signal = CoreProcessExit.signal(exit)
128 + signal_to_int(signal)
true ->
raw_status
end
end
defp wrapped_exit_reason?(reason) do
CoreProcessExit.match?(reason) or wrapped_exit_reason_shape?(reason)
end
defp wrapped_exit_reason_shape?(:normal), do: true
defp wrapped_exit_reason_shape?(reason) when is_integer(reason), do: true
defp wrapped_exit_reason_shape?({:exit_code, status}) when is_integer(status), do: true
defp wrapped_exit_reason_shape?({:exit_status, status}) when is_integer(status), do: true
defp wrapped_exit_reason_shape?({:signal, _signal, _core?}), do: true
defp wrapped_exit_reason_shape?({:shutdown, reason}), do: wrapped_exit_reason?(reason)
defp wrapped_exit_reason_shape?({:transport, reason}), do: wrapped_exit_reason?(reason)
defp wrapped_exit_reason_shape?({:send_failed, reason}), do: wrapped_exit_reason?(reason)
defp wrapped_exit_reason_shape?({:call_exit, reason}), do: wrapped_exit_reason?(reason)
defp wrapped_exit_reason_shape?({:error, reason}), do: wrapped_exit_reason?(reason)
defp wrapped_exit_reason_shape?({:exit, reason}), do: wrapped_exit_reason?(reason)
defp wrapped_exit_reason_shape?({:EXIT, _pid, reason}), do: wrapped_exit_reason?(reason)
defp wrapped_exit_reason_shape?({reason, {GenServer, :call, _}}),
do: wrapped_exit_reason?(reason)
defp wrapped_exit_reason_shape?(_reason), do: false
defp signal_to_int(signal) when is_integer(signal), do: signal
defp signal_to_int(signal) when is_atom(signal),
do: Map.get(signal_numbers(), signal, 1)
defp signal_numbers do
%{
sigabrt: 6,
sigalrm: 14,
sigbus: 7,
sigchld: 17,
sigcld: 17,
sigcont: 18,
sigemt: 7,
sigfpe: 8,
sighup: 1,
sigill: 4,
siginfo: 29,
sigint: 2,
sigio: 29,
sigiote: 6,
sigkill: 9,
siglost: 29,
sigpipe: 13,
sigpoll: 29,
sigprof: 27,
sigpwr: 30,
sigquit: 3,
sigsegv: 11,
sigstop: 19,
sigsys: 31,
sigterm: 15,
sigtrap: 5,
sigtstp: 20,
sigttin: 21,
sigttou: 22,
sigurg: 23,
sigusr1: 10,
sigusr2: 12,
sigvtalrm: 26,
sigwinch: 28,
sigxcpu: 24,
sigxfsz: 25
}
end
end