Skip to content

UDP link card; no more exit segfaults in test children - #11

Merged
txp666 merged 3 commits into
mainfrom
udp
Nov 4, 2026
Merged

txp666 merged 3 commits into
mainfrom
udp

Conversation

@txp666

@txp666 txp666 commented Nov 4, 2026

Copy link
Copy Markdown
Owner
  • New UdpConfigCard (UDP 配置):
    • It binds a local port (defaultLocalPort, 0 lets the system choose) and sends to defaultHost:defaultPort.
    • With no remote host it answers the last sender, and it refuses to start when both the host and the local port are empty.
    • A broadcast address broadcasts.
    • Every datagram is one frame, as MQTT messages are, so all parsers work on it.
    • The Modbus master, poller and slave run over it (modbus_tcp framing, or RTU/ASCII), and the slave always answers the asker.
    • It owns its link like the other cards and exports with the app.
  • Docs: the UDP card in uidp-format.md, uidp-widgets.md, protocol.md and the READMEs. Bluetooth is dropped from the roadmap, together with a stale "English interface planned" line.
  • Fixes the intermittent segfault at interpreter exit in test child processes, seen in CI on macOS-Intel / Python 3.12 and Windows / Python 3.14:
    • PyQt's exit hook (cleanup_on_exit) deletes Python-owned QObjects while it walks sip's wrapper table. When one of those deletions runs Python that wraps new objects, sip can free the table being walked.
    • tests/orderly_exit.py deletes those objects first, from an atexit hook that runs before PyQt's, and every test child starts with its one-line prelude.
    • The designer and exported apps already tear down in order before exiting.

Checked:

  • The full suite (232 tests) passes.
  • A pymodbus UDP master passed all 16 Modbus checks against an exported app with a UDP slave card: reads, 05/06/0F/10 writes read back, live widget updates, exception codes 01/02/03, and an unknown unit getting no reply.
  • The exit crash reproduced 6 times in 1000 runs on x86_64 Python 3.12 before the fix, and 0 times in 1000 after it.

🤖 Generated with Claude Code

txp666 and others added 3 commits November 4, 2026 20:08
UdpConfigCard binds a local port and sends to a remote host and port;
with no remote it answers the last sender, and a broadcast address
broadcasts. Every datagram is one frame, as MQTT messages are, so all
parsers work on it, and the Modbus master, poller and slave run over it
(modbus_tcp framing, or RTU/ASCII), the slave always answering the
asker. It owns its link like the other cards and exports with the app.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PyQt's atexit hook deletes every QObject Python still owns while it walks
sip's table of wrappers. When a deletion runs Python (a destroyed slot, an
event filter) that wraps new objects, sip can grow the table and free the
copy being walked. Test child processes then segfaulted now and then after
their script had finished (macOS-Intel / Python 3.12, Windows / Python 3.14).
The designer and exported apps already tear down before exiting and were not
affected.

tests/orderly_exit.py does the same deletions first from an atexit hook
that runs before PyQt's, leaving PyQt nothing to delete. Every test child
script starts with its one-line prelude, and importing the module covers the
test process itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@txp666
txp666 merged commit 3d60de6 into main Nov 4, 2026
6 checks passed
@txp666
txp666 deleted the udp branch November 4, 2026 12:22
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.

1 participant