Question

I'm having one of those mental-block moments in trying to implement what should be a fairly simple routine, for serial IO.

The situation is that we have an embedded linux board (think Pi / Beagle) which communicates with another device on the UART using the standard Linux termios code.

The problem is we have two clashing requirements:

In the transmit direction, we want to block on the Linux messaging queue msgrcv() function until a message arrives for us to send.

In the receive direction, we need to wait/block for an incoming message (which can have a termination character for canonical mode operation).

Tx and Rx are asynchronous and not related to each other - either could want to happen at any time.

Polling would be a pain as it introduces an overhead in CPU cycles and delay in response.

One approach would be to split this into two threads, one handling the Tx and blocking on msgrcv(), and the other on the Rx and blocking on UART read() in canonical mode - but that would introduce the pain of setting up semaphores between the Tx & Rx processes and both having to repeatedly open & close the serial port, and the Rx thread would presumably end up having to poll the semaphore in case the Tx wanted control, putting us back to polling.

I would stress that I'm relatively new to all this Linux stuff, so am entirely ready to be shown the bleeding obvious solution/method/call/operation that I'm missing here.

Is there some way to be blocking on the UART Rx but still able to transmit on demand?

Was it helpful?

Solution

In the end I followed Martin James' suggestion, doing something like this:

fd = open(serial_port);
pthread_create(TxThread, fd);
pthread_create(RxThread, fd);

Linux seems entirely happy with this, both threads do their jobs with no problem.

OTHER TIPS

It might be simpler to have a thread for the msgqueue, in combination with a pipe, so you can wait on the pipe and the serial port using select()/poll()/... in your serial tx/rx thread.

Fortunately you don't even have to do that. It turns out that on Linux (but not on all other unixes!) message queue IDs are also file descriptors, so you can just wait on the message queue and the serial port in one poll() call. You only have to check which one is active to figure out what you have to do.

See also Why is there no poll/select-like mechanism for message queues.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top