close() is asynchronous?
We have observed failure in our unit tests when the serial cannot be opened, as if it has not been closed properly during the termination of a previous test process.
At first I thought I would have to explicitly terminate it by trapping exit in another process but the GenServer documentation states:
Therefore it is not guaranteed that terminate/2 is called when a GenServer exits. For such reasons, we usually recommend important clean-up rules to happen in separated processes either by use of monitoring or by links themselves. For example if the GenServer controls a port (e.g. :gen_tcp.socket) or File.io_device/0, they will be closed on receiving a GenServer’s exit signal and do not need to be closed in terminate/2.
So I am assuming this is the case for Nerves also, so there is no need to explicitly close it.
Looking at the implementation of close/1, it is synchronous (GenServer.call is used) but internally it uses call_port which use message passing with the port.
Is it possible that this internal message passing is asynchronous and one of the test in the suite open the serial while the message to close it from the previous invocation has not been processed?
Adding a small delay ( :timer.sleep(100)) in the ExUnit setup function solves the problem. However I am not big fan of the solution, as solving problems with timers have a tendency to not be reliable and cause later problem when it is not expected.
If my hypothesis is true (asynchronous call is used internally), what approach would you suggest to solve the problem?
You probably need to call Nerves.UART.stop(pid) to shutdown the GenServer
I ran into this issue yesterday, and that worked for me. It appears close doesn't fully release the file handler. I was on Ubuntu 16.04
I did but it did not solve the problem. Also, looking at the code, Nerves.UART close the port upon termination.