Preventing socket events from injecting themselves into the stack

So many years using Xojo, and still finding new weird behaviors. I have console app that manages a bunch of sockets. Socket events fire on the main thread, unless you’re polling them. I’m not. Being a console app, I have a single DoEvents loop in the Run event handler. While I fully understand that I cannot count on event order, I’m having a situation where the error event of a socket sometimes gets added to the existing stack instead of waiting for the next iteration of the event loop.

Take this log output for example:

ExchangeSocket.mRconSocket_Disconnected: RCON has disconnected
ExchangeSocket.Error: Unexpected disconnect, calling Cleanup
ExchangeSocket.Cleanup: Cleanup started
ExchangeSocket.Cleanup: Cleanup finished
ExchangeSocket.mRconSocket_Disconnected: RCON cleanup complete

These are independent methods that I’ve confirmed are definitely both firing on the main thread. But while executing the code for ExchangeSocket.mRconSocket_Disconnected, ExchangeSocket.Error has fired. You can see that in this stack trace here:

The code is in Sentinel.Service.SaveTo, but ExchangeSocket.Event.Error has just decided it’s going to be run. I’d expect at a loop boundary, but in this case the calling line is a SelectSQL. And no, the line doesn’t actually call the event. That’s just where the event has been injected into the stack.

This is code from ExchangeSocket.mRconSocket_Disconnected. You can see the DebugPrint at the top, though the Terminal is obscuring a successful usage of Self.mService just above that if. When that line was called, Self.mService was not nil. But then “Unexpected disconnect” is called, which I know sets Self.mService to nil as part of cleanup, and then back in mRconSocket_Disconnected, Self.mService is now nil.

This is macOS ARM 2025r1.1. I can’t even think of a way to counter this. It just shouldn’t be happening.

Ok, I know what’s happening. The key clue is this line:

It’s the Multithreaded property of the database. When true (the default) your SQL statements can act as event loops.

Anybody have any idea how Multithreaded = False behaves inside a preemptive thread?

1 Like

Well, if the SQL code doesn’t yield, that should not cause trouble since preemptive threads don’t need to call yield. When other threads do yield, they may do the socket events.