Packages
livebook
0.6.1
0.19.8
0.19.7
0.19.6
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.19.0
0.18.6
0.18.5
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.3
0.17.2
0.17.1
0.17.0
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.14.0-rc.1
0.14.0-rc.0
0.13.3
0.13.2
0.13.1
0.13.0
0.12.1
0.12.0
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.3
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.1
0.4.0
0.3.2
0.3.1
0.3.0
0.2.3
0.2.2
0.2.1
0.2.0
0.1.2
0.1.1
0.1.0
Automate code & data workflows with interactive notebooks
Current section
Files
Jump to
Current section
Files
lib/livebook/runtime/erl_dist/io_forward_gl.ex
defmodule Livebook.Runtime.ErlDist.IOForwardGL do
@moduledoc false
# An IO device process forwarding all requests to sender's group
# leader.
#
# We register this device as the `:standard_error` in the runtime
# node, so that all evaluation warnings are treated as stdout.
#
# The process implements [The Erlang I/O Protocol](https://erlang.org/doc/apps/stdlib/io_protocol.html)
# and can be thought of as a virtual IO device.
use GenServer
@doc """
Starts the IO device.
## Options
* `:name` - the name to register the process under. Optional.
If the name is already used, it will be unregistered before
starting the process and registered back when the server
terminates.
"""
@spec start_link(keyword()) :: GenServer.on_start()
def start_link(opts \\ []) do
name = opts[:name]
if previous = name && Process.whereis(name) do
Process.unregister(name)
end
GenServer.start_link(__MODULE__, {name, previous}, opts)
end
@impl true
def init({name, previous}) do
Process.flag(:trap_exit, true)
{:ok, %{name: name, previous: previous}}
end
@impl true
def handle_info({:io_request, from, reply_as, req}, state) do
case Process.info(from, :group_leader) do
{:group_leader, group_leader} ->
# Forward the request to sender's group leader
# and instruct it to get back to us.
send(group_leader, {:io_request, from, reply_as, req})
_ ->
send(from, {:io_reply, reply_as, {:error, :terminated}})
end
{:noreply, state}
end
@impl true
def terminate(_, %{name: name, previous: previous}) do
if name && previous do
Process.unregister(name)
Process.register(previous, name)
end
:ok
end
end