Files
2026-08-24 10:03:24 +08:00

233 lines
4.7 KiB
C++

/*
* Copyright (C) 2007 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 "AmlMpThread"
#include "AmlMpThread.h"
#include "AmlMpLog.h"
#include <unistd.h>
#include <sys/syscall.h>
#include <pthread.h>
#include <string.h>
static const char* mName = LOG_TAG;
namespace aml_mp {
AmlMpThread::AmlMpThread()
: mStatus(0)
, mExitPending(false)
, mRunning(false)
, mThread(-1)
, mTid(-1)
{
}
AmlMpThread::~AmlMpThread()
{
}
int AmlMpThread::readyToRun()
{
return 0;
}
typedef int (*thread_func_t)(void*);
struct ThreadData {
thread_func_t entryFunction;
void* userData;
char* threadName;
static void* trampoline(void* t) {
ThreadData* userData = (ThreadData*)t;
thread_func_t f = userData->entryFunction;
void* u = userData->userData;
char* name = userData->threadName;
delete userData;
if (name) {
pthread_setname_np(pthread_self(), name);
free(name);
}
f(u);
return nullptr;
}
};
int AmlMpThread::run(const char* name)
{
std::lock_guard<std::mutex> _l(mLock);
if (mRunning) {
return -EINVAL;
}
mStatus = 0;
mExitPending = false;
mRunning = true;
mThread = -1;
mTid = -1;
mHoldSelf = this;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
ThreadData* t = new ThreadData;
t->threadName = strdup(name);
t->entryFunction = _threadLoop;
t->userData = this;
pthread_t thread;
int result = pthread_create(&thread, &attr, &ThreadData::trampoline, t);
pthread_attr_destroy(&attr);
if (result != 0) {
MLOGE("pthread create failed %d", result);
if (t->threadName) {
free(t->threadName);
}
delete t;
mStatus = -EINVAL;
mRunning = false;
mThread = -1;
mHoldSelf.clear();
return mStatus;
}
mThread = thread;
return 0;
}
int AmlMpThread::_threadLoop(void* user)
{
AmlMpThread* const self = static_cast<AmlMpThread*>(user);
sptr<AmlMpThread> strong(self->mHoldSelf);
wptr<AmlMpThread> weak(strong);
self->mHoldSelf.clear();
self->mTid = syscall(__NR_gettid);
bool first = true;
do {
bool result;
if (first) {
first =false;
self->mStatus = self->readyToRun();
result = self->mStatus == 0;
if (result && !self->exitPending()) {
result = self->threadLoop();
}
} else {
result = self->threadLoop();
}
{
std::unique_lock<std::mutex> _l(self->mLock);
if (result == false || self->mExitPending) {
self->mExitPending = true;
self->mRunning = false;
self->mThread = -1;
self->mThreadExitedCondition.notify_all();
break;
}
}
strong.clear();
strong = weak.promote();
} while (strong != nullptr);
MLOGI("thread exited!!!");
return 0;
}
void AmlMpThread::requestExit()
{
std::lock_guard<std::mutex> _l(mLock);
mExitPending = true;
}
int AmlMpThread::requestExitAndWait()
{
std::unique_lock<std::mutex> _l(mLock);
if (mThread == pthread_self()) {
MLOGE("don't call waitForExit from this thread!");
return -EWOULDBLOCK;
}
mExitPending = true;
while (mRunning) {
mThreadExitedCondition.wait(_l);
}
mExitPending = false;
return mStatus;
}
int AmlMpThread::join()
{
std::unique_lock<std::mutex> _l(mLock);
if (mThread == pthread_self()) {
MLOGE("don't call waitForExit from this thread!");
return -EWOULDBLOCK;
}
while (mRunning) {
mThreadExitedCondition.wait(_l);
}
return mStatus;
}
bool AmlMpThread::isRunning()
{
std::lock_guard<std::mutex> _l(mLock);
return mRunning;
}
int AmlMpThread::getTid() const
{
std::lock_guard<std::mutex> _l(mLock);
int tid;
if (mRunning) {
tid = mTid;
} else {
tid = -1;
}
return tid;
}
bool AmlMpThread::exitPending() const
{
std::lock_guard<std::mutex> _l(mLock);
return mExitPending;
}
}