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 ExternalRuntimeTransport.ProcessExit, as: CoreProcessExit
@spec exit_status(term()) :: {:ok, integer()} | :unknown
def exit_status(reason)
def exit_status(:normal), do: {:ok, 0}
def exit_status(%CoreProcessExit{status: :success}), do: {:ok, 0}
def exit_status(%CoreProcessExit{status: :exit, code: status}) when is_integer(status),
do: {:ok, status}
def exit_status(%CoreProcessExit{status: :signal, signal: signal}) do
{:ok, 128 + signal_to_int(signal)}
end
def exit_status(%CoreProcessExit{reason: reason}), do: exit_status(reason)
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({:shutdown, reason}), do: exit_status(reason)
def exit_status({:transport, reason}), do: exit_status(reason)
def exit_status({:send_failed, reason}), do: exit_status(reason)
def exit_status({:call_exit, reason}), do: exit_status(reason)
def exit_status({:error, reason}), do: exit_status(reason)
def exit_status({:exit, reason}), do: exit_status(reason)
def exit_status({:EXIT, _pid, reason}), do: exit_status(reason)
def exit_status({reason, {GenServer, :call, _}}), do: exit_status(reason)
def exit_status({reason, _meta}) do
if wrapped_exit_reason?(reason) do
exit_status(reason)
else
:unknown
end
end
def exit_status(_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
case CoreProcessExit.from_reason(raw_status) do
%CoreProcessExit{status: :success} ->
0
%CoreProcessExit{status: :exit, code: code} when is_integer(code) ->
code
%CoreProcessExit{status: :signal, signal: signal} ->
128 + signal_to_int(signal)
_other ->
raw_status
end
end
defp wrapped_exit_reason?(:normal), do: true
defp wrapped_exit_reason?(%CoreProcessExit{}), do: true
defp wrapped_exit_reason?({:exit_code, status}) when is_integer(status), do: true
defp wrapped_exit_reason?({:exit_status, status}) when is_integer(status), do: true
defp wrapped_exit_reason?({:signal, _signal, _core?}), do: true
defp wrapped_exit_reason?(status) when is_integer(status), do: true
defp wrapped_exit_reason?({:shutdown, reason}), do: wrapped_exit_reason?(reason)
defp wrapped_exit_reason?({:transport, reason}), do: wrapped_exit_reason?(reason)
defp wrapped_exit_reason?({:send_failed, reason}), do: wrapped_exit_reason?(reason)
defp wrapped_exit_reason?({:call_exit, reason}), do: wrapped_exit_reason?(reason)
defp wrapped_exit_reason?({:error, reason}), do: wrapped_exit_reason?(reason)
defp wrapped_exit_reason?({:exit, reason}), do: wrapped_exit_reason?(reason)
defp wrapped_exit_reason?({:EXIT, _pid, reason}), do: wrapped_exit_reason?(reason)
defp wrapped_exit_reason?({reason, {GenServer, :call, _}}), do: wrapped_exit_reason?(reason)
defp wrapped_exit_reason?(_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