Crash on PS4 due to semaphore count with Unity 2020.3.12f1

We have recently upgraded from Unity 2019.3 to 2020.3.12f1, this caused our game to crash on PS4.

The crash is caused by frequent calls to the EventInstance’s EVENT_CALLBACK.

Unity dev quote:

The problem is as follows: When a function call is made from native to managed, and if the call is made by a thread that is unknown to the managed VM, the following happens:

  1. The managed VM thinks “This thread is not one of mine” and must quickly instantiate a new System.Threading.Thread object to represent the calling thread. This is the ScopedThreadAttacher that you can see in the callstack.
  2. The native representation of a System.Threading.Thread holds a native semaphore as a member variable. This is the baselibReentrantLock that you can see in the callstack, ending up as a BaseLib_SystemSemaphore_Create call.
  3. After the managed call completes, the newly-created Thread instance immediately becomes eligible for garbage collection, but it has not been finalized yet.
  4. The native representation of the Thread stays alive until the finalizer of the managed Thread is run, after garbage collection.
  5. If the same native thread subsequently makes another managed call, then another System.Threading.Thread instance is created, including another native representation, including another semaphore.

So if the native plugin makes calls back into managed code at a very very high rate, then there’s a possibility of hitting any platform limits on the number of concurrent semaphores. On PlayStation 4 the limit on the number of synchronization objects (combined mutexes, semaphores, etc.) is relatively low at [4096]
End quote

I have confirmed that this is indeed the issue. In the previous version of unity, the kernel semaphore count remained at around 81 and did not scale with the event instance callback. In Unity 2020.3.12f1 the semaphore count scales exactly with the amount of calls to that callback and the crash happens at around the 3600th call (including mutexes that takes us above the limit).

Even if the callback is completely empty the crash still occurs but if we do not subscribe to the callback the semaphore count remains low and the crash does not occur.

Even though this is probably a Unity-issue, is there a way for FMOD to support the callback in a way that bypasses the logic described earlier?

(it is not an option to run FMOD synchronously on PS4 since this adds too much CPU overhead, even though this fixes the crash).

Kind Regards,

Robert

Unfortunately this does look like more of an issue with Unity and there isn’t a lot we can do to work around this as we don’t have access to.

You could try limiting the the callbacks by being more specific with the masks when setting the callback. If it’s beat or marker callbacks you could use the deferred flag which will push them to the main thread.

Thanks for your response!
We are already using the FMOD.Studio.INITFLAGS.DEFERRED_CALLBACKS flags, or is that not the one you mean?

Also, I understand you can’t fix this, I have submitted a Unity bug report.

That is the flag I was referring to, although we only support deferred marker and beat callbacks so all the others will still fire from native threads.