[ejabberd] The strange useless loop in ejabberd_app.erl

Badlop badlop at gmail.com
Wed Apr 7 14:42:44 MSD 2010


2010/4/6 Xi Liu <jason.liuxi at gmail.com>:
>   I find a really strange thing in the code.
> And now I think the loop was intended, But why?

Those lines were written by Alexey Shchepin 7 years ago,
at the beginning of ejabberd project. They were never changed.

You got me curious about that strange loop, let's see if we both find
its meaning
without asking the mastermind Alexey :)


>   In ejabberd_app.erl there is a loop function doing nothing just loop on
> the expat_erl port it opend before,
>
> After I comment the call to the loop function, Clients could no longer
> connect to the server. I debuged and found that this due to xml_stream
> cannot open a new expat_erl port, and the console says  "expat_erl: not
> found".
>
> So in conclusion, the useless loop helps  the successive  expat_erl
> open_port function find the expat_erl lib?

The port is opened, and obviously it must be kept open during all the
ejabberd living.

init() ->
    register(ejabberd, self()),
    ...
    Port = open_port({spawn, expat_erl}, [binary]),
    loop(Port).

Let's say an erlang process calls init().
That process registers itself with name 'ejabberd'.
Then it calls open_port, and the port gets linked to the process.

Since when will the port be opened? Until it closes, or the process
'ejabberd' is stopped.
See http://www.erlang.org/doc/tutorial/c_portdriver.html#id2260932
> All communication goes through one Erlang process that is the connected
> process of the port driver. Terminating this process closes the port driver.

If you call open_port and nothing more, 'ejabberd' will soon stop, and
the port gets closed.
You must keep 'ejabberd' alive, for example putting it in an endless loop.
In erlang, a simple endless loop is to 'receive' any message and call
recursively.

loop(Port) ->
    receive
	_ ->
	    loop(Port)
    end.

In fact, nobody sends any message to that 'ejabberd' process.
Change to this and start ejabberd with "ejabberdctl live":

loop(Port) ->
    receive
	stop ->
	    io:format("ejabberd_app loop got a stop message~n", []),
	    ok;
	M ->
	    io:format("ejabberd_app loop got a message: ~p~n", [M]),
	    loop(Port)
    end.

If you send a normal message, the loop continues:
(ejabberd at localhost)1> ejabberd ! hi.
ejabberd_app loop got a message: hi
hi

If you end the loop, the process is stopped, the port is closed
and the XMPP server won't work correctly:
(ejabberd at localhost)2> ejabberd ! stop.
ejabberd_app loop got a stop message
stop
=SUPERVISOR REPORT==== 7-Apr-2010::12:28:07 ===
     Supervisor: {local,ejabberd_receiver_sup}
     Context:    child_terminated
     Reason:     driver_unloaded
...



---
Badlop
ProcessOne


More information about the ejabberd mailing list