juce_android_JNIHelpers.h. Claim you need locks around get functions too.
class ThreadLocalJNIEnvHolder
{
public:
ThreadLocalJNIEnvHolder()
: jvm (nullptr)
{
zeromem (threads, sizeof (threads));
zeromem (envs, sizeof (envs));
}
void initialise (JNIEnv* env)
{
// NB: the DLL can be left loaded by the JVM, so the same static
// objects can end up being reused by subsequent runs of the app
zeromem (threads, sizeof (threads));
zeromem (envs, sizeof (envs));
env->GetJavaVM (&jvm);
_add(env);
}
JNIEnv* attach()
{
JNIEnv* env = _attach();
if (env != nullptr)
{
SpinLock::ScopedLockType sl (addRemoveLock);
if (!_get())
_add(env);
}
return env;
}
void detach()
{
jvm->DetachCurrentThread();
const pthread_t thisThread = pthread_self();
SpinLock::ScopedLockType sl (addRemoveLock);
for (int i = 0; i < maxThreads; ++i)
{
if (threads[i] == thisThread)
{
threads[i] = 0;
break;
}
}
}
JNIEnv* getOrAttach() noexcept
{
SpinLock::ScopedLockType sl (addRemoveLock);
JNIEnv* env = _get();
if (env == nullptr)
{
env = _attach();
if (env) _add(env);
}
jassert (env != nullptr);
return env;
}
enum { maxThreads = 32 };
private:
JavaVM* jvm;
pthread_t threads [maxThreads];
JNIEnv* envs [maxThreads];
SpinLock addRemoveLock;
JNIEnv* _attach()
{
JNIEnv* env = nullptr;
jvm->AttachCurrentThread (&env, nullptr);
return env;
}
JNIEnv* _get() const noexcept
{
const pthread_t thisThread = pthread_self();
for (int i = 0; i < maxThreads; ++i)
if (threads[i] == thisThread)
return envs[i];
return nullptr;
}
void _add(JNIEnv* env)
{
const pthread_t thisThread = pthread_self();
for (int i = 0; i < maxThreads; ++i)
{
if (threads[i] == 0)
{
envs[i] = env;
threads[i] = thisThread;
return;
}
}
jassertfalse; // too many threads!
}
};
