Is calling different SBApplication objects from different threads bad?

Not quite but maybe sorta related to the errOSAInternalTableOverflow problem I asked about in a different thread, this one deals with crashes our app gets (and much more frequently lately after recent OS updates (15.7.3) are OK'd by our IT department).

Our app can run multiple jobs concurrently, each in their own NSOperation. Each op creates its own SBApplication instance that controls unique instances of InDesignServer. What I'm seeing recently is lots of crashes happening while multiple ops are calling into ScriptingBridge. Shown at the bottom is one of the stack crawls from one of the threads. I've trimmed all but the last of our code. Other threads have a similar stack crawl.

In searching for answers, Google's AI overview mentions "If you must use multiple threads, ensure that each thread creates its own SBApplication instance…" Which is what we do. No thread can reach another thread's SBApplication instance. Is that statement a lie? Do I need to lock around every ScriptingBridge call (which is going to severely slow things down)?

0   AE                            	       0x1a7dba8d4 0x1a7d80000 + 239828
1   AE                            	       0x1a7d826d8 AEProcessMessage + 3496
2   AE                            	       0x1a7d8f210 0x1a7d80000 + 61968
3   AE                            	       0x1a7d91978 0x1a7d80000 + 72056
4   AE                            	       0x1a7d91764 0x1a7d80000 + 71524
5   CoreFoundation                	       0x1a0396a64 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28
6   CoreFoundation                	       0x1a03969f8 __CFRunLoopDoSource0 + 172
7   CoreFoundation                	       0x1a0396764 __CFRunLoopDoSources0 + 232
8   CoreFoundation                	       0x1a03953b8 __CFRunLoopRun + 840
9   CoreFoundation                	       0x1a03949e8 CFRunLoopRunSpecific + 572
10  AE                            	       0x1a7dbc108 0x1a7d80000 + 246024
11  AE                            	       0x1a7d988fc AESendMessage + 4724
12  ScriptingBridge               	       0x1ecb652ac -[SBAppContext sendEvent:error:] + 80
13  ScriptingBridge               	       0x1ecb5eb4c -[SBObject sendEvent:id:keys:values:count:] + 216
14  ScriptingBridge               	       0x1ecb6890c -[SBCommandThunk invoke:] + 376
15  CoreFoundation                	       0x1a037594c ___forwarding___ + 956
16  CoreFoundation                	       0x1a03754d0 _CF_forwarding_prep_0 + 96
17  RRD                           	       0x1027fca18 -[AppleScriptHelper runAppleScript:withSubstitutionValues:usingSBApp:] + 1036




Answered by DTS Engineer in 876135022

Our app can run multiple jobs concurrently, each in its own NSOperation. Each op creates its own SBApplication instance that controls unique instances of InDesignServer. What I'm seeing recently is lots of crashes happening while multiple ops are calling into ScriptingBridge. Shown at the bottom is one of the stack crawls from one of the threads.

Can you attach a full crash log? If it's too long or you don't want to share it publicly, you can also file a bug, upload the logs there, then post the bug number back here. I want to see the full app context and crash state, just in case there is something else going on.

Also, as a specific detail, how are you actually creating these threads and, in particular, these are standard threads (NSThread/pthread) NOT something fancy like GCD or Swift Async.

In searching for answers, Google's AI overview mentions "If you must use multiple threads, ensure that each thread creates its own SBApplication instance…" Which is what we do. No thread can reach another thread's SBApplication instance. Is that statement a lie?

Theoretically, yes, SBApplication should generally be thread safe, assuming it's used "reasonably". The complication here, and I confess I hadn't actually thought about how it was implemented until today, is that the people who implemented the ScriptingBridge were being very, very clever. Basically, the ScriptingBridge implements a dynamic proxy object system on top of the AppleEvent in much the same way that Cocoa Distributed Objects (DO) implement a proxy object system on top of the Objective-C message runtime. Much like DO, that's both incredibly powerful but also very "tricky" with a lot of moving components that are tricky to validate. Basically, this should work but I also wouldn't be surprised if you found some edge case bug or implementation detail.

That leads to here:

Do I need to lock around every ScriptingBridge call (which is going to severely slow things down)?

What's the larger context of your app? How many simultaneous apps are you trying to control, how long do you expect your app to run, etc.? In particular, if this is a long-running app that's going to be controlling "lots" of app runs, then you might think in terms of a "broader" architectural solution, mostly likely shifting your controllers into helper processes.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Our app can run multiple jobs concurrently, each in its own NSOperation. Each op creates its own SBApplication instance that controls unique instances of InDesignServer. What I'm seeing recently is lots of crashes happening while multiple ops are calling into ScriptingBridge. Shown at the bottom is one of the stack crawls from one of the threads.

Can you attach a full crash log? If it's too long or you don't want to share it publicly, you can also file a bug, upload the logs there, then post the bug number back here. I want to see the full app context and crash state, just in case there is something else going on.

Also, as a specific detail, how are you actually creating these threads and, in particular, these are standard threads (NSThread/pthread) NOT something fancy like GCD or Swift Async.

In searching for answers, Google's AI overview mentions "If you must use multiple threads, ensure that each thread creates its own SBApplication instance…" Which is what we do. No thread can reach another thread's SBApplication instance. Is that statement a lie?

Theoretically, yes, SBApplication should generally be thread safe, assuming it's used "reasonably". The complication here, and I confess I hadn't actually thought about how it was implemented until today, is that the people who implemented the ScriptingBridge were being very, very clever. Basically, the ScriptingBridge implements a dynamic proxy object system on top of the AppleEvent in much the same way that Cocoa Distributed Objects (DO) implement a proxy object system on top of the Objective-C message runtime. Much like DO, that's both incredibly powerful but also very "tricky" with a lot of moving components that are tricky to validate. Basically, this should work but I also wouldn't be surprised if you found some edge case bug or implementation detail.

That leads to here:

Do I need to lock around every ScriptingBridge call (which is going to severely slow things down)?

What's the larger context of your app? How many simultaneous apps are you trying to control, how long do you expect your app to run, etc.? In particular, if this is a long-running app that's going to be controlling "lots" of app runs, then you might think in terms of a "broader" architectural solution, mostly likely shifting your controllers into helper processes.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Thanks, Kevin.

I've entered FB21953216 with 2 crash logs attached. Both show multiple threads calling SB (job thread names begin with "ProofProcessor"). One has 3 jobs and the other has 4.

Our app can run up to 40 jobs concurrently, but rarely get more than half a dozen, usually just a few. Each job can run a unique instance of InDesignServer. Our app runs "forever".

Before moving to ScriptingBridge, we did run into the problem of only being able to run one script at a time from the main thread, so we added an external app and each job launched one of those to run the scripts. I don't recall the exact security changes nor in which OS we found that a change to ScriptingBridge was needed. A different engineer handled that change.

Is calling different SBApplication objects from different threads bad?
 
 
Q