Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent blocking all virtual serial ports on full PTS #16

Merged
merged 3 commits into from
Aug 15, 2024

Conversation

macman31
Copy link
Contributor

I am running the following command to multiplex a serial port into multiple virtual serial ports:

vsp-router \
  --attach gps0:/dev/ttyUSB0,9600 \
  --create /dev/gps0_gpsd \
  --create /dev/gps0_data \
  --create /dev/gps0_debug \
  --route gps0:gps0_gpsd \
  --route gps0:gps0_data \
  --route gps0:gps0_debug \
  --route gps0_debug:gps0

The intention is for /dev/gps0_gpsd and /dev/gps0_data to be actively read from during normal operations, and /dev/gps0_debug should just be available in case I want to monitor the GPS data or send commands to it.

This works well for a few seconds, but after some time vsp-router blocks on trying to write to gps0_debug which is not actively being read from. When this happens new data stop being sent to all virtual serial ports, including the ones that are actively being read from.
This is due to the fact that data written to a PTS are being buffered until around ~20kB of data (enforced by the kernel), then new writes are blocked by the kernel until some data is read.
When reading again from gps0_debug data streaming resumes on all virtual serial ports, and vsp-router also proceeds to send all data that was accumulated during the block to all virtual serial ports.

This is causing me some issues:

  • If one virtual serial port is not being read from, intentionally or because the program reading from it crashes, I still want data to be sent to other serial ports
  • When reading resumes I do not care about receiving the data that was not being sent during the block as it is stale data

I address those issues in this PR: when a virtual serial port is not being read from, up to ~20kB of data will be accumulated and they will be returned at the next read. New data past those ~20kB will be discarded with a warning message in the logs, but without blocking the other virtual serial ports.

When reading from a virtual serial port, up to ~20kB of stale data will be returned, followed by new data. This behavior is different from a physical serial port which does not buffer data, but it is easy to control from services opening the virtual serial ports by running tcflush with the queue selector TCIFLUSH on the file descriptor corresponding to the virtual serial port before attempting to read data from it. This way only new data will be returned, the buffered data will be discarded.
For example gpsd correctly does a tcflush when opening serial ports.

Applying this PR to vsp-router and doing the tcflush from client services results in reads from virtual serial ports behaving as close as possible as reads from physical serial ports. I suggest adding this information about tcflush somewhere as it is really useful when combined with vsp-router.

Note that I am very new at Rust, feel free to rewrite the code as you see fit if you want to accept this PR.

@rfdonnelly
Copy link
Owner

Hi @macman31. Thank you for your contribution and detailed explanation. This is a welcome enhancement. If you could please run cargo fmt and if you'd like to take a cut at this:

I suggest adding this information about tcflush somewhere as it is really useful when combined with vsp-router.

@macman31
Copy link
Contributor Author

Hello @rfdonnelly I implemented the requested changes.
FYI my use case for your project is multiplexing a GPS UART to get both time sync using gpsd+chrony and telemetry data using custom scripts, running on a Raspberry Pi inside a nonprofit stratospheric balloon :)

@rfdonnelly rfdonnelly merged commit 09b10e1 into rfdonnelly:main Aug 15, 2024
5 of 6 checks passed
@rfdonnelly
Copy link
Owner

Merged. Thank you. Cool use case!

@macman31
Copy link
Contributor Author

Awesome thanks!
Could you do a new release with the changes when you get the chance please?

@rfdonnelly
Copy link
Owner

I've released v1.0.3 with this change. Also technically v1.0.2 but there were some troubles with the release process on that one.

@macman31
Copy link
Contributor Author

Awesome thanks :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants