hubertlepicki
Erlang/Elixir Interactive Shell jobs get stuck when printing to output
So I have this little problem with both Erlang and Elixir interactive shells. Which probably means I do not understand something basic and it is intended behavior. In short:
- I start outputting something to the console from default job
- I start another job (
Ctrl + G, thens 'Elixir.IEx'andc 2 - I go back to initial job
Ctrl + Gthenc 1
The job numer 1 is stuck. Does not output anything. I can interrupt it, however, and then it works again, until I switch context to another job.
I have tried this on Elixir 1.5 @ Erlang 19.3 and 20.0, and on both these Erlang versions with Erlang code (io:format instead of IO.puts). The result is always the same: when I switch back to a job that attempted to output something to the shell while it was in the background, this job is stuck.
Most Liked
peerreynders
I wonder if it’s related to [erlang-questions] “New” vs. “old” console behavior: bug or feature?
The user.erl process forwards that data to the shell. The shell
attempts to evaluate it, and if there’s not enough data, it asks for
more. user.erl then blocks until it can get more data to respond to the
io request.
It sounds like the user process can get stuck in a selective receive - so if it’s responsible for anything else that would be blocked too.
REPL? A bit more (and less) than that
PS: Though it sounds like the behaviour of the old shell - not the current one with user_drv (though according to observer user is running).
Seems the first shell’s group leader is getting stuck here as soon as you try to connect back to it.
iex(1)> spid = self()
#PID<0.84.0>
iex(2)> {:group_leader, leader_1} = Process.info spid, :group_leader
{:group_leader, #PID<0.53.0>}
iex(3)> {:group_leader, leader} = Process.info leader_1, :group_leader
{:group_leader, #PID<0.35.0>}
iex(4)> {:group_leader, ^leader} = Process.info leader, :group_leader
{:group_leader, #PID<0.35.0>}
iex(5)> defmodule Foo do
...(5)> def loop do
...(5)> IO.puts "Looping..."
...(5)> :timer.sleep(1000)
...(5)> loop()
...(5)> end
...(5)> end
{:module, Foo,
<<70, 79, 82, 49, 0, 0, 4, 8, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 108, 0,
0, 0, 12, 10, 69, 108, 105, 120, 105, 114, 46, 70, 111, 111, 8, 95, 95, 105,
110, 102, 111, 95, 95, 9, 102, 117, ...>>, {:loop, 0}}
iex(6)> Foo.loop()
Looping...
Looping...
Looping...
Looping...
Looping...
User switch command
--> s 'Elixir.IEx'
--> c 2
Interactive Elixir (1.5.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> leader_1 = pid("0.53.0")
#PID<0.53.0>
iex(2)> Process.info leader_1, :message_queue_len
{:message_queue_len, 0}
iex(3)> Process.info leader_1, :messages
{:messages, []}
iex(4)> Process.info leader_1, :current_location
{:current_location, {:group, :server_loop, 3, [file: 'group.erl', line: 113]}}
iex(5)>
User switch command
--> c 1
User switch command
--> c 2
nil
iex(6)> Process.info leader_1, :message_queue_len
{:message_queue_len, 2}
iex(7)> Process.info leader_1, :messages
{:messages, [{#PID<0.51.0>, {:data, '\r'}}, {#PID<0.51.0>, {:data, '\r'}}]}
iex(8)> Process.info leader_1, :current_location
{:current_location, {:group, :server_loop, 3, [file: 'group.erl', line: 113]}}
iex(9)> Process.whereis :user_drv
#PID<0.51.0>
iex(10)>
Variation on the theme:
iex(1)> leader_1 = Process.group_leader()
#PID<0.53.0>
iex(2)> {:group_leader, leader} = Process.info leader_1, :group_leader
{:group_leader, #PID<0.35.0>}
iex(3)> {:group_leader, ^leader} = Process.info leader_1, :group_leader
{:group_leader, #PID<0.35.0>}
iex(4)> defmodule Foo do
...(4)>
...(4)> def start(),
...(4)> do: (Kernel.spawn_link &loop/0)
...(4)>
...(4)> def loop do
...(4)> IO.puts "Looping..."
...(4)> :timer.sleep(1000)
...(4)> loop()
...(4)> end
...(4)> end
{:module, Foo,
<<70, 79, 82, 49, 0, 0, 4, 228, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 141,
0, 0, 0, 15, 10, 69, 108, 105, 120, 105, 114, 46, 70, 111, 111, 8, 95, 95,
105, 110, 102, 111, 95, 95, 9, 102, 117, ...>>, {:loop, 0}}
iex(5)>
nil
iex(6)> Foo.start()
Looping...
#PID<0.127.0>
Looping...
Looping...
Looping...
Looping...
Looping...
Looping...
iex(7)>
User switch command
--> s 'Elixir.IEx'
--> c 2
Interactive Elixir (1.5.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> leader_1 = pid("0.53.0")
#PID<0.53.0>
iex(2)> Process.info leader_1, :message_queue_len
{:message_queue_len, 0}
iex(3)> Process.info leader_1, :messages
{:messages, []}
iex(4)> Process.info leader_1, :current_location
{:current_location, {:group, :more_data, 5, [file: 'group.erl', line: 638]}}
iex(5)>
User switch command
--> c 1
nil
iex(8)> Process.info leader_1, :message_queue_len
{:message_queue_len, 0}
iex(9)> Process.info leader_1, :messages
{:messages, []}
iex(10)> Process.info leader_1, :current_location
{:current_location, {:group, :server_loop, 3, [file: 'group.erl', line: 113]}}
iex(11)> foo_pid = pid("0.127.0")
#PID<0.127.0>
iex(12)> Process.info foo_pid, :group_leader
{:group_leader, #PID<0.53.0>}
iex(13)> Process.info foo_pid, :current_location
{:current_location, {:io, :execute_request, 2, [file: 'io.erl', line: 572]}}
iex(14)>
Basically the spawned process is stuck here presumably waiting for a response from the group_leader which never comes. Looks like the response to the IO request got lost because the group_leader is waiting for more data.
hubertlepicki
Just to follow-up, I indeed found a bug in Erlang/OTP. This has been already resolved by the awesome OTP team, and is working correctly on master.
The next release that will include the fix will be 20.1.
hubertlepicki
And I’ve run this test on Ubuntu, Erlang 18 - 20, the issue is present there too.
Wanted to report a bug at Erlang bugtracker but it seems down
https://bugs.erlang.org/
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









