Handling preemptive threads in callbacks (via declare)

I’m addressing those of you who understand the issues around running Xojo code in native OS threads, i.e. that it can lead to crashes.

I just had a thought come up on that and wanted to ask for input from those of you who are familiar with this topic:

We know that Xojo’s own threads are using native OS threads, and the Xojo runtime makes sure they do not run into issues by locking all but one of those threads at all times, so that the native OS thread scheduler can always only let one thread run. The runtime eventually unlocks another single thread (whenever a loop is being iterated, for instance), thereby keeping control over when it’s safe to switch to its other threads.

Now, the problem for us Xojo users is that when we use declares that use callbacks, it can happen that those callbacks occur in a pre-emptive thread not controlled by Xojo. If we then access any Xojo object from that thread, we’ll run the certain risk of crashing or other grave program misbehaviours.

So, I wonder:

Couldn’t we talk to the Xojo runtime’s thread scheduler, i.e. that code that decides when to lock/unlock its threads, and have this new thread calling our callback function be controlled by Xojo as well? All we need to do is invoke a runtime function that says:

Hey Xojo, this is a new thread you don’t know of - please lock it now and unlock it as soon as any of your other Xojo threads is ready to yield.

And before we leave this callback function, we’d again make a call into the runtime, saying:

Hey Xojo, we’re now leaving this thread. You can release and dispose of the lock on it again.

Any reason why this couldn’t work? If none are found, then I’d propose a feature request that adds such functions, e.g. to the System module, so that we can invoke them from our callbacks.

(Note: This is part of my research for my Multithreading session at the upcoming MBS Xojo conference in Munich next week.)

Here’s one case where this procedure could fail:

If the thread that invokes the callback is blocking the main thread, then locking the callback thread would result in a deadlock. But that’s a “normal” issue you have with any use of threads, and if your use case has this condition, then this proposed solution won’t work there.

But I believe there are still plenty of cases that would not run into such deadlocks, and that’s what I’m aiming for.

When a Xojo method is called, some work is done behind the scenes. That may crash already if called on another thread.

A good feature request would be to not raise Stackoverflow exceptions on non Xojo threads.

Could you please show me some proof of that? (Sure, if it’s an object method you’d be right, but we’re talking about shared/global methods here)

See my explanations in this old thread: https://forum.xojo.com/20313
I disassembled the code and saw nothing that would agree with you, nor does the demo I made ever crash.

So, from that point I cannot see why my proposal can’t work.

Oh, the lock/unlock is for object methods.
So as soon as an object (or string) is referenced, it may crash.

Christian, you’re stating the obvious :slight_smile: That’s exactly what I was speaking of: If, before accessing an object or string, we can let the Xojo runtime know of this new thread, then this would be dealt with, and we should have no such crashes.

but it may be better a #pragma threadsafe which puts some code on begin of method to make a loop

if IsMainThread then // continue else LockGlobalMutex // we get lock if other thread yields end if

And on end of method, it would unlock the mutex as last thing before returning.

or something like this.

Good point, a pragma would certainly be a safer way than having to invoke the methods ourselves.

and it may make it work for delegates from objects.

@Thomas Tempelmann - Could you try something?

  1. Create a class
  2. Add a method that you will use for the callback.
  3. Add a private timer property of type Timer.
  4. Add a private Boolean property named Finished.
  5. Add a method called TimerAction for the timer callback.
  6. Add properties of each of the parameters of the callback
  7. Add an event definition to notify your app.
  8. In the constructor, create the timer instance with a short period (like 100ms) and a mode of 2 and point the Action event of the timer at the TimerAction method.
  9. In the callback method, set the properties that correspond to the callback parameters and set the Finished property to True.
  10. In the TimerAction method, if Finished = True, call RemoveHandler to disconnect the timer, set the timer property to Nil and fire the event.

When you are about to call the declare, create an instance of this object and use the AddressOf the class instance callback method.

This should get the callback onto the main thread without directly accessing any non-intrinsic types (unless I forgot something… it’s 4am here). We used this technique in the XDC 2018 iOS app to get the TouchID callbacks without crashing.

Darn. Now I’m awake. I’ll go find the code to make sure my explanation is 100% correct.

Here’s a link to an example project.

@Greg O’Lone That’s just a tried and well-known pattern for executing some code on the main thread when one runs on another (Xojo-controlled) thread. I cannot use your described technique for my described cases because the technique requires access to Xojo objects (such as a Timer object) while being in the callback - and that’s what can lead to a crash because we’re missing the protection “lock” calls I and Christian are proposing for that.

I guess I should come up with a concrete example where this is needed

Only, I cannot come up with a good one right now. It would have to be something where one invokes a macOS function that in turn creates its own pthread or NSTask and makes a callback on that thread. I suspect that Cocoa UI animation callback handlers (as Blocks) might do this, but am not sure.

Okay, here’s one, based on the example I’m going to show on the MBS / Xojo conference next week:

I have made a dylib (in C) that can compress data very fast, using multiple, preemptive, threads.

Xojo calls into the dylib, passing the data to compress, and then a new thread is created as needed to compress the data. Once this thread is finished, it needs to let the Xojo app know.

The dylib’s thread can’t just call back into Xojo code to let it know it’s finished, because that Xojo callback function would then run into a thread unknown to the Xojo runtime, and eventually lead to a crash when the timing is bad. Instead, the Xojo code needs to run a timer and keep polling - which is inefficient.

This is where my proposal comes in: With the lock calls (or pragma, as Christian suggests), Xojo could prevent this kind of crash when the dylib calls back into Xojo code, by suspending the calling thread until the latest Xojo thread gets back running, and once that yields, resumes the callback thread, thereby making sure the Xojo runtime is in a defined (safe!) state where we can’t run into the dreaded crashes.

Thomas, that’s not what I’m doing there. The callback is from a preemptive thread within the iOS framework and calls one method which sets three non-object properties: a Boolean, an integer and a pointer. That won’t crash. Then ~250ms later, the timer (running in the Xojo main thread) notices that the Boolean has changed, picks up the change and raises the event.

I know you’re doubting my answer, but did you even try it? As I said, we are using this code to do exactly what you are describing for TouchID.

The same approach Greg mentions is used several times throughout iOSKit with AVFoundation classes.

That said, there have been two times where I wasn’t able to do that so I feel your pain @Thomas Tempelmann - I’ll see if I can find those examples, I know I posted a feedback case about this a year or two back.

@Greg O’Lone Thanks for clarifying. So, what you’re doing is quite similar to what I was advertising in the linked thread in 2016 (https://forum.xojo.com/20313 - it appears you didn’t look at mine then, either :wink: ), to which Norman told us all, despite my “proving” that it works: That can’t work, ever :smiley:

So, while that approach obviously works, it involves polling, and I would like to propse a better method that not only avoid latency induced by polling but that makes such callbacks safer, too.

Well yeah, with a title like Using Grand Central Dispatch (GCD) for preemptive threading that wouldn’t have been of interest to me 3½ years ago.

Anyway, I was only offering something that works right now.

I could need something to help for callbacks on preemptive threads for my EventKit on iOS.

I made feedback cases:

<https://xojo.com/issue/53200>: ThreadSafeCallback pragma for callbacks
<https://xojo.com/issue/53201>: StackOverflowChecking should work for non Xojo threads by doing nothing

Trust me, it still isn’t the answer for non-Apple SDK functionality (i.e.: BSD layer POSIX calls). GCD doesn’t recognize that something is occurring and allows the task manager to Zombie your process if it runs for too long.

The case I mentioned is:
<https://xojo.com/issue/40205> Please add a #pragma to dispatch a method to the main thread

Thomas, it like you already commented on it that you think it should be different than I suggested a few years back, but I’ll still bring it up to connect what I said earlier…