blob: 7d668e3183a7feb26c2ad460adf5ba1e500146dd [file] [log] [blame]
/**
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "NativeCallbackThread"
//#define LOG_NDEBUG 0
#include "NativeCallbackThread.h"
#include <utils/Log.h>
namespace android {
NativeCallbackThread::NativeCallbackThread(JavaVM *vm) : mExitting(false), mvm(vm) {
auto res = pthread_create(&mThread, nullptr, main, this);
if (res != 0) {
ALOGE("Couldn't start NativeCallbackThread");
mThread = 0;
return;
}
ALOGD("Started native callback thread %p", this);
}
NativeCallbackThread::~NativeCallbackThread() {
ALOGV("~NativeCallbackThread %p", this);
stop();
}
void* NativeCallbackThread::main(void *args) {
auto self = reinterpret_cast<NativeCallbackThread*>(args);
self->main();
return nullptr;
}
void NativeCallbackThread::main() {
ALOGV("NativeCallbackThread::main()");
JNIEnv *env = nullptr;
JavaVMAttachArgs aargs = {JNI_VERSION_1_4, "NativeCallbackThread", nullptr};
if (mvm->AttachCurrentThread(&env, &aargs) != JNI_OK || env == nullptr) {
ALOGE("Couldn't attach thread");
return;
}
while (!mExitting) {
ALOGV("Waiting for task...");
Task task;
{
AutoMutex _l(mQueueMutex);
auto res = mQueueCond.wait(mQueueMutex);
ALOGE_IF(res != 0, "Wait failed: %d", res);
if (mExitting || res != 0) break;
if (mQueue.empty()) continue;
task = mQueue.front();
mQueue.pop();
}
ALOGV("Executing task...");
task(env);
if (env->ExceptionCheck()) {
ALOGE("Unexpected exception:");
env->ExceptionDescribe();
env->ExceptionClear();
}
}
auto res = mvm->DetachCurrentThread();
ALOGE_IF(res != JNI_OK, "Couldn't detach thread");
ALOGV("Native callback thread %p finished", this);
}
void NativeCallbackThread::enqueue(const Task &task) {
AutoMutex _l(mQueueMutex);
if (mThread == 0 || mExitting) {
ALOGW("Callback thread %p is not serving calls", this);
return;
}
mQueue.push(task);
mQueueCond.signal();
}
void NativeCallbackThread::stop() {
ALOGV("stop() %p", this);
{
AutoMutex _l(mQueueMutex);
if (mThread == 0 || mExitting) return;
mExitting = true;
mQueueCond.signal();
}
auto ret = pthread_join(mThread, nullptr);
ALOGE_IF(ret != 0, "Couldn't join thread: %d", ret);
ALOGD("Stopped native callback thread %p", this);
}
} // namespace android