Do not re-open the SPI handle on every module_init() - #429
Open
qnology wants to merge 1 commit into
Open
Conversation
RaspberryPi.module_init() calls self.SPI.open(0, 0) unconditionally. spidev's open() does not close an existing handle, so every call after the first leaks one /dev/spidev0.0 file descriptor. This is reachable from the documented API. Switching a panel between 4Gray and 1Gray requires calling init(mode) again, and the bundled example does exactly that: epd_3in7_test.py calls init(0), init(1), then init(0), with a single module_exit() at the end, leaking two descriptors per run. A long-running program that redraws periodically hits the process NOFILE limit. Measured on a Pi 3B refreshing an epd3in7 once a minute: 1024 descriptors held, 1012 of them spidev, after 16.7 hours. Past that the process cannot open a socket either, so unrelated network calls start failing with EINVAL. Fixed with the same Flag guard SunriseX3.module_init() already uses in this file, and reset in module_exit() so a genuine teardown still re-opens. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #428.
RaspberryPi.module_init()callsself.SPI.open(0, 0)unconditionally.spidev'sopen()does not close an existing handle, so every call after the first leaks one/dev/spidev0.0file descriptor.This is reachable from the documented API — switching a panel between 4Gray and 1Gray requires calling
init(mode)again, andexamples/epd_3in7_test.pydoes exactly that (init(0),init(1),init(0), with a singlemodule_exit()), leaking two descriptors per run.Measured on a Pi 3B refreshing an
epd3in7once a minute: 1024 descriptors held, 1012 of them spidev, after 16.7 hours. Past theNOFILEceiling the process could no longer open a socket either, so unrelated HTTPS calls began failing with[Errno 22] Invalid argument— which is what makes this awkward to diagnose. Full write-up in #428.The change
Uses the guard
SunriseX3.module_init()already uses a few classes down in this same file, so the two implementations now behave consistently:Flag = 0class attribute onRaspberryPi, matchingSunriseX3module_init()opens SPI only whenFlag == 0module_exit()resetsFlagso a genuine teardown still re-opensOnly the
cleanup=Falsebranch is guarded; thecleanup=Truepath usesDEV_SPIand is untouched.Behaviour
module_init()module_exit()thenmodule_init()No API change, and no change for callers that already do a single
init()/module_exit().Verified on the affected hardware: a Pi 3B driving an
epd3in7at one refresh per minute now holds a steady 13 file descriptors, 1 of them spidev, across sustained operation — previously it gained one per minute until it died.🤖 Generated with Claude Code